Revert directory structure changes
diff --git a/ChangeLog b/ChangeLog
index 7173b00..0f74718 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,28 +1,3 @@
-Thu Feb 23 02:03:56 CET 2001 Tomasz K³oczko <kloczek@pld.org.pl>
-
-	* *.c *.h libxml files: moved to libxml directory - this allow
-	  simplify automake/autoconf. Now isn't neccessary hack on
-	  am/ac level for make and remove libxml symlink (modified for this
-	  also configure.in and main Makefile.am). Now automake abilities
-	  are used in best way (like in many other projects with libraries).
-	* include/win32config.h: moved to libxml directory (now include
-	  directory isn't neccessary).
-	* Makefile.am, examples/Makefile.am, libxml/Makefile.am:
-	  added empty DEFS and in INCLUDES rest only -I$(top_builddir) -
-	  this allow minimize parameters count passed to libtool script
-	  (now compilation is also slyghtly more quiet).
-	* configure.in: simplifies libzdetestion - prepare separated
-	  variables for keep libz name and path to libz header files isn't
-	  realy neccessary (if someone have libz installed in non standard
-	  prefix path to header files ald library can be passed as:
-	  $ CFALGS="-I</libz.h/path>" LDFLAGS="-L</libz/path>" ./configure
-	* autogen.sh: check now for libxml/entities.h.
-
-	After above building libxml pass correctly and also pass
-	"make install DESTDIR=</install/prefix>" from tar ball generated by
-	"make dist". Seems ac/am reorganization is finished. This changes
-	not touches any other things on *.{c,h} files level.
-
 Thu Feb 22 07:52:27 CET 2001 Daniel Veillard <Daniel.Veillard@imag.fr>
 
 	* xpath.c: finally implemented xmlXPathCompareNodeSets
diff --git a/HTMLparser.c b/HTMLparser.c
new file mode 100644
index 0000000..4fb40df
--- /dev/null
+++ b/HTMLparser.c
@@ -0,0 +1,4966 @@
+/*
+ * HTMLparser.c : an HTML 4.0 non-verifying parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_HTML_ENABLED
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/HTMLparser.h>
+#include <libxml/entities.h>
+#include <libxml/encoding.h>
+#include <libxml/valid.h>
+#include <libxml/xmlIO.h>
+
+#define HTML_MAX_NAMELEN 1000
+#define HTML_PARSER_BIG_BUFFER_SIZE 1000
+#define HTML_PARSER_BUFFER_SIZE 100
+
+/* #define DEBUG */
+/* #define DEBUG_PUSH */
+
+int htmlOmittedDefaultValue = 1;
+
+/************************************************************************
+ *									*
+ * 		Parser stacks related functions and macros		*
+ *									*
+ ************************************************************************/
+
+/*
+ * Generic function for accessing stacks in the Parser Context
+ */
+
+#define PUSH_AND_POP(scope, type, name)					\
+scope int html##name##Push(htmlParserCtxtPtr ctxt, type value) {	\
+    if (ctxt->name##Nr >= ctxt->name##Max) {				\
+	ctxt->name##Max *= 2;						\
+        ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,		\
+	             ctxt->name##Max * sizeof(ctxt->name##Tab[0]));	\
+        if (ctxt->name##Tab == NULL) {					\
+	    xmlGenericError(xmlGenericErrorContext,			\
+		    		"realloc failed !\n");			\
+	    return(0);							\
+	}								\
+    }									\
+    ctxt->name##Tab[ctxt->name##Nr] = value;				\
+    ctxt->name = value;							\
+    return(ctxt->name##Nr++);						\
+}									\
+scope type html##name##Pop(htmlParserCtxtPtr ctxt) {			\
+    type ret;								\
+    if (ctxt->name##Nr < 0) return(0);					\
+    ctxt->name##Nr--;							\
+    if (ctxt->name##Nr < 0) return(0);					\
+    if (ctxt->name##Nr > 0)						\
+	ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];		\
+    else								\
+        ctxt->name = NULL;						\
+    ret = ctxt->name##Tab[ctxt->name##Nr];				\
+    ctxt->name##Tab[ctxt->name##Nr] = 0;				\
+    return(ret);							\
+}									\
+
+PUSH_AND_POP(extern, xmlNodePtr, node)
+PUSH_AND_POP(extern, xmlChar*, name)
+
+/*
+ * Macros for accessing the content. Those should be used only by the parser,
+ * and not exported.
+ *
+ * Dirty macros, i.e. one need to make assumption on the context to use them
+ *
+ *   CUR_PTR return the current pointer to the xmlChar to be parsed.
+ *   CUR     returns the current xmlChar value, i.e. a 8 bit value if compiled
+ *           in ISO-Latin or UTF-8, and the current 16 bit value if compiled
+ *           in UNICODE mode. This should be used internally by the parser
+ *           only to compare to ASCII values otherwise it would break when
+ *           running with UTF-8 encoding.
+ *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
+ *           to compare on ASCII based substring.
+ *   UPP(n)  returns the n'th next xmlChar converted to uppercase. Same as CUR
+ *           it should be used only to compare on ASCII based substring.
+ *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
+ *           strings within the parser.
+ *
+ * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
+ *
+ *   CURRENT Returns the current char value, with the full decoding of
+ *           UTF-8 if we are using this mode. It returns an int.
+ *   NEXT    Skip to the next character, this does the proper decoding
+ *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
+ *   COPY(to) copy one char to *to, increment CUR_PTR and to accordingly
+ */
+
+#define UPPER (toupper(*ctxt->input->cur))
+
+#define SKIP(val) ctxt->nbChars += (val),ctxt->input->cur += (val)
+
+#define NXT(val) ctxt->input->cur[(val)]
+
+#define UPP(val) (toupper(ctxt->input->cur[(val)]))
+
+#define CUR_PTR ctxt->input->cur
+
+#define SHRINK  xmlParserInputShrink(ctxt->input)
+
+#define GROW  xmlParserInputGrow(ctxt->input, INPUT_CHUNK)
+
+#define CURRENT ((int) (*ctxt->input->cur))
+
+#define SKIP_BLANKS htmlSkipBlankChars(ctxt)
+
+/* Inported from XML */
+
+/* #define CUR (ctxt->token ? ctxt->token : (int) (*ctxt->input->cur)) */
+#define CUR ((int) (*ctxt->input->cur))
+#define NEXT xmlNextChar(ctxt),ctxt->nbChars++
+
+#define RAW (ctxt->token ? -1 : (*ctxt->input->cur))
+#define NXT(val) ctxt->input->cur[(val)]
+#define CUR_PTR ctxt->input->cur
+
+
+#define NEXTL(l) do {							\
+    if (*(ctxt->input->cur) == '\n') {					\
+	ctxt->input->line++; ctxt->input->col = 1;			\
+    } else ctxt->input->col++;						\
+    ctxt->token = 0; ctxt->input->cur += l; ctxt->nbChars++;		\
+  } while (0)
+    
+/************
+    \
+    if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);	\
+    if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt);
+ ************/
+
+#define CUR_CHAR(l) htmlCurrentChar(ctxt, &l)
+#define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l)
+
+#define COPY_BUF(l,b,i,v)						\
+    if (l == 1) b[i++] = (xmlChar) v;					\
+    else i += xmlCopyChar(l,&b[i],v)
+
+/**
+ * htmlCurrentChar:
+ * @ctxt:  the HTML parser context
+ * @len:  pointer to the length of the char read
+ *
+ * The current char value, if using UTF-8 this may actaully span multiple
+ * bytes in the input buffer. Implement the end of line normalization:
+ * 2.11 End-of-Line Handling
+ * If the encoding is unspecified, in the case we find an ISO-Latin-1
+ * char, then the encoding converter is plugged in automatically.
+ *
+ * Returns the current char value and its lenght
+ */
+
+int
+htmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
+    if (ctxt->instate == XML_PARSER_EOF)
+	return(0);
+
+    if (ctxt->token != 0) {
+	*len = 0;
+	return(ctxt->token);
+    }	
+    if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
+	/*
+	 * We are supposed to handle UTF8, check it's valid
+	 * From rfc2044: encoding of the Unicode values on UTF-8:
+	 *
+	 * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+	 * 0000 0000-0000 007F   0xxxxxxx
+	 * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+	 * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
+	 *
+	 * Check for the 0x110000 limit too
+	 */
+	const unsigned char *cur = ctxt->input->cur;
+	unsigned char c;
+	unsigned int val;
+
+	c = *cur;
+	if (c & 0x80) {
+	    if (cur[1] == 0)
+		xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+	    if ((cur[1] & 0xc0) != 0x80)
+		goto encoding_error;
+	    if ((c & 0xe0) == 0xe0) {
+
+		if (cur[2] == 0)
+		    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+		if ((cur[2] & 0xc0) != 0x80)
+		    goto encoding_error;
+		if ((c & 0xf0) == 0xf0) {
+		    if (cur[3] == 0)
+			xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+		    if (((c & 0xf8) != 0xf0) ||
+			((cur[3] & 0xc0) != 0x80))
+			goto encoding_error;
+		    /* 4-byte code */
+		    *len = 4;
+		    val = (cur[0] & 0x7) << 18;
+		    val |= (cur[1] & 0x3f) << 12;
+		    val |= (cur[2] & 0x3f) << 6;
+		    val |= cur[3] & 0x3f;
+		} else {
+		  /* 3-byte code */
+		    *len = 3;
+		    val = (cur[0] & 0xf) << 12;
+		    val |= (cur[1] & 0x3f) << 6;
+		    val |= cur[2] & 0x3f;
+		}
+	    } else {
+	      /* 2-byte code */
+		*len = 2;
+		val = (cur[0] & 0x1f) << 6;
+		val |= cur[1] & 0x3f;
+	    }
+	    if (!IS_CHAR(val)) {
+		ctxt->errNo = XML_ERR_INVALID_ENCODING;
+		if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+				     "Char 0x%X out of allowed range\n", val);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }    
+	    return(val);
+	} else {
+	    /* 1-byte code */
+	    *len = 1;
+	    return((int) *ctxt->input->cur);
+	}
+    }
+    /*
+     * Assume it's a fixed lenght encoding (1) with
+     * a compatibke encoding for the ASCII set, since
+     * XML constructs only use < 128 chars
+     */
+    *len = 1;
+    if ((int) *ctxt->input->cur < 0x80)
+	return((int) *ctxt->input->cur);
+
+    /*
+     * Humm this is bad, do an automatic flow conversion
+     */
+    xmlSwitchEncoding(ctxt, XML_CHAR_ENCODING_8859_1);
+    ctxt->charset = XML_CHAR_ENCODING_UTF8;
+    return(xmlCurrentChar(ctxt, len));
+
+encoding_error:
+    /*
+     * If we detect an UTF8 error that probably mean that the
+     * input encoding didn't get properly advertized in the
+     * declaration header. Report the error and switch the encoding
+     * to ISO-Latin-1 (if you don't like this policy, just declare the
+     * encoding !)
+     */
+    ctxt->errNo = XML_ERR_INVALID_ENCODING;
+    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
+	ctxt->sax->error(ctxt->userData, 
+			 "Input is not proper UTF-8, indicate encoding !\n");
+	ctxt->sax->error(ctxt->userData, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+			ctxt->input->cur[0], ctxt->input->cur[1],
+			ctxt->input->cur[2], ctxt->input->cur[3]);
+    }
+
+    ctxt->charset = XML_CHAR_ENCODING_8859_1; 
+    *len = 1;
+    return((int) *ctxt->input->cur);
+}
+
+/**
+ * htmlNextChar:
+ * @ctxt:  the HTML parser context
+ *
+ * Skip to the next char input char.
+ */
+
+void
+htmlNextChar(htmlParserCtxtPtr ctxt) {
+    if (ctxt->instate == XML_PARSER_EOF)
+	return;
+    if ((*ctxt->input->cur == 0) &&
+        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) {
+	    xmlPopInput(ctxt);
+    } else {
+        if (*(ctxt->input->cur) == '\n') {
+	    ctxt->input->line++; ctxt->input->col = 1;
+	} else ctxt->input->col++;
+	ctxt->input->cur++;
+	ctxt->nbChars++;
+        if (*ctxt->input->cur == 0)
+	    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+    }
+}
+
+/**
+ * htmlSkipBlankChars:
+ * @ctxt:  the HTML parser context
+ *
+ * skip all blanks character found at that point in the input streams.
+ *
+ * Returns the number of space chars skipped
+ */
+
+int
+htmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
+    int res = 0;
+
+    while (IS_BLANK(*(ctxt->input->cur))) {
+	if ((*ctxt->input->cur == 0) &&
+	    (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0)) {
+		xmlPopInput(ctxt);
+	} else {
+	    if (*(ctxt->input->cur) == '\n') {
+		ctxt->input->line++; ctxt->input->col = 1;
+	    } else ctxt->input->col++;
+	    ctxt->input->cur++;
+	    ctxt->nbChars++;
+	    if (*ctxt->input->cur == 0)
+		xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+	}
+	res++;
+    }
+    return(res);
+}
+
+
+
+/************************************************************************
+ *									*
+ * 		The list of HTML elements and their properties		*
+ *									*
+ ************************************************************************/
+
+/*
+ *  Start Tag: 1 means the start tag can be ommited
+ *  End Tag:   1 means the end tag can be ommited
+ *             2 means it's forbidden (empty elements)
+ *  Depr:      this element is deprecated
+ *  DTD:       1 means that this element is valid only in the Loose DTD
+ *             2 means that this element is valid only in the Frameset DTD
+ *
+ * Name,Start Tag,End Tag,Save End,  Empty,  Depr.,    DTD, Description
+ */
+htmlElemDesc  html40ElementTable[] = {
+{ "a",		0,	0,	0,	0,	0,	0, "anchor " },
+{ "abbr",	0,	0,	0,	0,	0,	0, "abbreviated form" },
+{ "acronym",	0,	0,	0,	0,	0,	0, "" },
+{ "address",	0,	0,	0,	0,	0,	0, "information on author " },
+{ "applet",	0,	0,	0,	0,	1,	1, "java applet " },
+{ "area",	0,	2,	2,	1,	0,	0, "client-side image map area " },
+{ "b",		0,	0,	0,	0,	0,	0, "bold text style" },
+{ "base",	0,	2,	2,	1,	0,	0, "document base uri " },
+{ "basefont",	0,	2,	2,	1,	1,	1, "base font size " },
+{ "bdo",	0,	0,	0,	0,	0,	0, "i18n bidi over-ride " },
+{ "big",	0,	0,	0,	0,	0,	0, "large text style" },
+{ "blockquote",	0,	0,	0,	0,	0,	0, "long quotation " },
+{ "body",	1,	1,	0,	0,	0,	0, "document body " },
+{ "br",		0,	2,	2,	1,	0,	0, "forced line break " },
+{ "button",	0,	0,	0,	0,	0,	0, "push button " },
+{ "caption",	0,	0,	0,	0,	0,	0, "table caption " },
+{ "center",	0,	0,	0,	0,	1,	1, "shorthand for div align=center " },
+{ "cite",	0,	0,	0,	0,	0,	0, "citation" },
+{ "code",	0,	0,	0,	0,	0,	0, "computer code fragment" },
+{ "col",	0,	2,	2,	1,	0,	0, "table column " },
+{ "colgroup",	0,	1,	0,	0,	0,	0, "table column group " },
+{ "dd",		0,	1,	0,	0,	0,	0, "definition description " },
+{ "del",	0,	0,	0,	0,	0,	0, "deleted text " },
+{ "dfn",	0,	0,	0,	0,	0,	0, "instance definition" },
+{ "dir",	0,	0,	0,	0,	1,	1, "directory list" },
+{ "div",	0,	0,	0,	0,	0,	0, "generic language/style container"},
+{ "dl",		0,	0,	0,	0,	0,	0, "definition list " },
+{ "dt",		0,	1,	0,	0,	0,	0, "definition term " },
+{ "em",		0,	0,	0,	0,	0,	0, "emphasis" },
+{ "fieldset",	0,	0,	0,	0,	0,	0, "form control group " },
+{ "font",	0,	0,	0,	0,	1,	1, "local change to font " },
+{ "form",	0,	0,	0,	0,	0,	0, "interactive form " },
+{ "frame",	0,	2,	2,	1,	0,	2, "subwindow " },
+{ "frameset",	0,	0,	0,	0,	0,	2, "window subdivision" },
+{ "h1",		0,	0,	0,	0,	0,	0, "heading " },
+{ "h2",		0,	0,	0,	0,	0,	0, "heading " },
+{ "h3",		0,	0,	0,	0,	0,	0, "heading " },
+{ "h4",		0,	0,	0,	0,	0,	0, "heading " },
+{ "h5",		0,	0,	0,	0,	0,	0, "heading " },
+{ "h6",		0,	0,	0,	0,	0,	0, "heading " },
+{ "head",	1,	1,	0,	0,	0,	0, "document head " },
+{ "hr",		0,	2,	2,	1,	0,	0, "horizontal rule " },
+{ "html",	1,	1,	0,	0,	0,	0, "document root element " },
+{ "i",		0,	0,	0,	0,	0,	0, "italic text style" },
+{ "iframe",	0,	0,	0,	0,	0,	1, "inline subwindow " },
+{ "img",	0,	2,	2,	1,	0,	0, "embedded image " },
+{ "input",	0,	2,	2,	1,	0,	0, "form control " },
+{ "ins",	0,	0,	0,	0,	0,	0, "inserted text" },
+{ "isindex",	0,	2,	2,	1,	1,	1, "single line prompt " },
+{ "kbd",	0,	0,	0,	0,	0,	0, "text to be entered by the user" },
+{ "label",	0,	0,	0,	0,	0,	0, "form field label text " },
+{ "legend",	0,	0,	0,	0,	0,	0, "fieldset legend " },
+{ "li",		0,	1,	1,	0,	0,	0, "list item " },
+{ "link",	0,	2,	2,	1,	0,	0, "a media-independent link " },
+{ "map",	0,	0,	0,	0,	0,	0, "client-side image map " },
+{ "menu",	0,	0,	0,	0,	1,	1, "menu list " },
+{ "meta",	0,	2,	2,	1,	0,	0, "generic metainformation " },
+{ "noframes",	0,	0,	0,	0,	0,	2, "alternate content container for non frame-based rendering " },
+{ "noscript",	0,	0,	0,	0,	0,	0, "alternate content container for non script-based rendering " },
+{ "object",	0,	0,	0,	0,	0,	0, "generic embedded object " },
+{ "ol",		0,	0,	0,	0,	0,	0, "ordered list " },
+{ "optgroup",	0,	0,	0,	0,	0,	0, "option group " },
+{ "option",	0,	1,	0,	0,	0,	0, "selectable choice " },
+{ "p",		0,	1,	1,	0,	0,	0, "paragraph " },
+{ "param",	0,	2,	2,	1,	0,	0, "named property value " },
+{ "pre",	0,	0,	0,	0,	0,	0, "preformatted text " },
+{ "q",		0,	0,	0,	0,	0,	0, "short inline quotation " },
+{ "s",		0,	0,	0,	0,	1,	1, "strike-through text style" },
+{ "samp",	0,	0,	0,	0,	0,	0, "sample program output, scripts, etc." },
+{ "script",	0,	0,	0,	0,	0,	0, "script statements " },
+{ "select",	0,	0,	0,	0,	0,	0, "option selector " },
+{ "small",	0,	0,	0,	0,	0,	0, "small text style" },
+{ "span",	0,	0,	0,	0,	0,	0, "generic language/style container " },
+{ "strike",	0,	0,	0,	0,	1,	1, "strike-through text" },
+{ "strong",	0,	0,	0,	0,	0,	0, "strong emphasis" },
+{ "style",	0,	0,	0,	0,	0,	0, "style info " },
+{ "sub",	0,	0,	0,	0,	0,	0, "subscript" },
+{ "sup",	0,	0,	0,	0,	0,	0, "superscript " },
+{ "table",	0,	0,	0,	0,	0,	0, "&#160;" },
+{ "tbody",	1,	0,	0,	0,	0,	0, "table body " },
+{ "td",		0,	0,	0,	0,	0,	0, "table data cell" },
+{ "textarea",	0,	0,	0,	0,	0,	0, "multi-line text field " },
+{ "tfoot",	0,	1,	0,	0,	0,	0, "table footer " },
+{ "th",		0,	1,	0,	0,	0,	0, "table header cell" },
+{ "thead",	0,	1,	0,	0,	0,	0, "table header " },
+{ "title",	0,	0,	0,	0,	0,	0, "document title " },
+{ "tr",		0,	1,	0,	0,	0,	0, "table row " },
+{ "tt",		0,	0,	0,	0,	0,	0, "teletype or monospaced text style" },
+{ "u",		0,	0,	0,	0,	1,	1, "underlined text style" },
+{ "ul",		0,	0,	0,	0,	0,	0, "unordered list " },
+{ "var",	0,	0,	0,	0,	0,	0, "instance of a variable or program argument" },
+};
+
+/*
+ * start tags that imply the end of a current element
+ * any tag of each line implies the end of the current element if the type of
+ * that element is in the same line
+ */
+char *htmlEquEnd[] = {
+"dt", "dd", "li", "option", NULL,
+"h1", "h2", "h3", "h4", "h5", "h6", NULL,
+"ol", "menu", "dir", "address", "pre", "listing", "xmp", NULL,
+NULL
+};
+/*
+ * acording the HTML DTD, HR should be added to the 2nd line above, as it
+ * is not allowed within a H1, H2, H3, etc. But we should tolerate that case
+ * because many documents contain rules in headings...
+ */
+
+/*
+ * start tags that imply the end of current element
+ */
+char *htmlStartClose[] = {
+"form",		"form", "p", "hr", "h1", "h2", "h3", "h4", "h5", "h6",
+		"dl", "ul", "ol", "menu", "dir", "address", "pre",
+		"listing", "xmp", "head", NULL,
+"head",		"p", NULL,
+"title",	"p", NULL,
+"body",		"head", "style", "link", "title", "p", NULL,
+"li",		"p", "h1", "h2", "h3", "h4", "h5", "h6", "dl", "address",
+		"pre", "listing", "xmp", "head", "li", NULL,
+"hr",		"p", "head", NULL,
+"h1",		"p", "head", NULL,
+"h2",		"p", "head", NULL,
+"h3",		"p", "head", NULL,
+"h4",		"p", "head", NULL,
+"h5",		"p", "head", NULL,
+"h6",		"p", "head", NULL,
+"dir",		"p", "head", NULL,
+"address",	"p", "head", "ul", NULL,
+"pre",		"p", "head", "ul", NULL,
+"listing",	"p", "head", NULL,
+"xmp",		"p", "head", NULL,
+"blockquote",	"p", "head", NULL,
+"dl",		"p", "dt", "menu", "dir", "address", "pre", "listing",
+		"xmp", "head", NULL,
+"dt",		"p", "menu", "dir", "address", "pre", "listing", "xmp",
+                "head", "dd", NULL,
+"dd",		"p", "menu", "dir", "address", "pre", "listing", "xmp",
+                "head", "dt", NULL,
+"ul",		"p", "head", "ol", "menu", "dir", "address", "pre",
+		"listing", "xmp", NULL,
+"ol",		"p", "head", "ul", NULL,
+"menu",		"p", "head", "ul", NULL,
+"p",		"p", "head", "h1", "h2", "h3", "h4", "h5", "h6", NULL,
+"div",		"p", "head", NULL,
+"noscript",	"p", "head", NULL,
+"center",	"font", "b", "i", "p", "head", NULL,
+"a",		"a", NULL,
+"caption",	"p", NULL,
+"colgroup",	"caption", "colgroup", "col", "p", NULL,
+"col",		"caption", "col", "p", NULL,
+"table",	"p", "head", "h1", "h2", "h3", "h4", "h5", "h6", "pre",
+		"listing", "xmp", "a", NULL,
+"th",		"th", "td", NULL,
+"td",		"th", "td", "p", NULL,
+"tr",		"th", "td", "tr", "caption", "col", "colgroup", "p", NULL,
+"thead",	"caption", "col", "colgroup", NULL,
+"tfoot",	"th", "td", "tr", "caption", "col", "colgroup", "thead",
+		"tbody", "p", NULL,
+"tbody",	"th", "td", "tr", "caption", "col", "colgroup", "thead",
+		"tfoot", "tbody", "p", NULL,
+"optgroup",	"option", NULL,
+"option",	"option", NULL,
+"fieldset",	"legend", "p", "head", "h1", "h2", "h3", "h4", "h5", "h6",
+		"pre", "listing", "xmp", "a", NULL,
+NULL
+};
+
+/*
+ * The list of HTML elements which are supposed not to have
+ * CDATA content and where a p element will be implied
+ *
+ * TODO: extend that list by reading the HTML SGML DtD on
+ *       implied paragraph
+ */
+static char *htmlNoContentElements[] = {
+    "html",
+    "head",
+    "body",
+    NULL
+};
+
+/*
+ * The list of HTML attributes which are of content %Script;
+ * NOTE: when adding ones, check htmlIsScriptAttribute() since
+ *       it assumes the name starts with 'on'
+ */
+static char *htmlScriptAttributes[] = {
+    "onclick",
+    "ondblclick",
+    "onmousedown",
+    "onmouseup",
+    "onmouseover",
+    "onmousemove",
+    "onmouseout",
+    "onkeypress",
+    "onkeydown",
+    "onkeyup",
+    "onload",
+    "onunload",
+    "onfocus",
+    "onblur",
+    "onsubmit",
+    "onrest",
+    "onchange",
+    "onselect"
+};
+
+
+static char** htmlStartCloseIndex[100];
+static int htmlStartCloseIndexinitialized = 0;
+
+/************************************************************************
+ *									*
+ * 		functions to handle HTML specific data			*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlInitAutoClose:
+ *
+ * Initialize the htmlStartCloseIndex for fast lookup of closing tags names.
+ * This is not reentrant. Call xmlInitParser() once before processing in
+ * case of use in multithreaded programs.
+ */
+void
+htmlInitAutoClose(void) {
+    int index, i = 0;
+
+    if (htmlStartCloseIndexinitialized) return;
+
+    for (index = 0;index < 100;index ++) htmlStartCloseIndex[index] = NULL;
+    index = 0;
+    while ((htmlStartClose[i] != NULL) && (index < 100 - 1)) {
+        htmlStartCloseIndex[index++] = &htmlStartClose[i];
+	while (htmlStartClose[i] != NULL) i++;
+	i++;
+    }
+    htmlStartCloseIndexinitialized = 1;
+}
+
+/**
+ * htmlTagLookup:
+ * @tag:  The tag name in lowercase
+ *
+ * Lookup the HTML tag in the ElementTable
+ *
+ * Returns the related htmlElemDescPtr or NULL if not found.
+ */
+htmlElemDescPtr
+htmlTagLookup(const xmlChar *tag) {
+    int i;
+
+    for (i = 0; i < (sizeof(html40ElementTable) /
+                     sizeof(html40ElementTable[0]));i++) {
+        if (xmlStrEqual(tag, BAD_CAST html40ElementTable[i].name))
+	    return(&html40ElementTable[i]);
+    }
+    return(NULL);
+}
+
+/**
+ * htmlCheckAutoClose:
+ * @newtag:  The new tag name
+ * @oldtag:  The old tag name
+ *
+ * Checks wether the new tag is one of the registered valid tags for closing old.
+ * Initialize the htmlStartCloseIndex for fast lookup of closing tags names.
+ *
+ * Returns 0 if no, 1 if yes.
+ */
+int
+htmlCheckAutoClose(const xmlChar *newtag, const xmlChar *oldtag) {
+    int i, index;
+    char **close = NULL;
+
+    if (htmlStartCloseIndexinitialized == 0) htmlInitAutoClose();
+
+    /* inefficient, but not a big deal */
+    for (index = 0; index < 100;index++) {
+        close = htmlStartCloseIndex[index];
+	if (close == NULL) return(0);
+	if (xmlStrEqual(BAD_CAST *close, newtag)) break;
+    }
+
+    i = close - htmlStartClose;
+    i++;
+    while (htmlStartClose[i] != NULL) {
+        if (xmlStrEqual(BAD_CAST htmlStartClose[i], oldtag)) {
+	    return(1);
+	}
+	i++;
+    }
+    return(0);
+}
+
+/**
+ * htmlAutoCloseOnClose:
+ * @ctxt:  an HTML parser context
+ * @newtag:  The new tag name
+ *
+ * The HTmL DtD allows an ending tag to implicitely close other tags.
+ */
+void
+htmlAutoCloseOnClose(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
+    htmlElemDescPtr info;
+    xmlChar *oldname;
+    int i;
+
+#ifdef DEBUG
+    xmlGenericError(xmlGenericErrorContext,"Close of %s stack: %d elements\n", newtag, ctxt->nameNr);
+    for (i = 0;i < ctxt->nameNr;i++) 
+        xmlGenericError(xmlGenericErrorContext,"%d : %s\n", i, ctxt->nameTab[i]);
+#endif
+
+    for (i = (ctxt->nameNr - 1);i >= 0;i--) {
+        if (xmlStrEqual(newtag, ctxt->nameTab[i])) break;
+    }
+    if (i < 0) return;
+
+    while (!xmlStrEqual(newtag, ctxt->name)) {
+	info = htmlTagLookup(ctxt->name);
+	if ((info == NULL) || (info->endTag == 1)) {
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"htmlAutoCloseOnClose: %s closes %s\n", newtag, ctxt->name);
+#endif
+        } else {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		 "Opening and ending tag mismatch: %s and %s\n",
+		                 newtag, ctxt->name);
+	    ctxt->wellFormed = 0;
+	}
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+	    ctxt->sax->endElement(ctxt->userData, ctxt->name);
+	oldname = htmlnamePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"htmlAutoCloseOnClose: popped %s\n", oldname);
+#endif
+	    xmlFree(oldname);
+	}	
+    }
+}
+
+/**
+ * htmlAutoClose:
+ * @ctxt:  an HTML parser context
+ * @newtag:  The new tag name or NULL
+ *
+ * The HTmL DtD allows a tag to implicitely close other tags.
+ * The list is kept in htmlStartClose array. This function is
+ * called when a new tag has been detected and generates the
+ * appropriates closes if possible/needed.
+ * If newtag is NULL this mean we are at the end of the resource
+ * and we should check 
+ */
+void
+htmlAutoClose(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
+    xmlChar *oldname;
+    while ((newtag != NULL) && (ctxt->name != NULL) && 
+           (htmlCheckAutoClose(newtag, ctxt->name))) {
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"htmlAutoClose: %s closes %s\n", newtag, ctxt->name);
+#endif
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+	    ctxt->sax->endElement(ctxt->userData, ctxt->name);
+	oldname = htmlnamePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"htmlAutoClose: popped %s\n", oldname);
+#endif
+	    xmlFree(oldname);
+        }
+    }
+    if (newtag == NULL) {
+	htmlAutoCloseOnClose(ctxt, BAD_CAST"head");
+	htmlAutoCloseOnClose(ctxt, BAD_CAST"body");
+	htmlAutoCloseOnClose(ctxt, BAD_CAST"html");
+    }
+    while ((newtag == NULL) && (ctxt->name != NULL) &&
+	   ((xmlStrEqual(ctxt->name, BAD_CAST"head")) ||
+	    (xmlStrEqual(ctxt->name, BAD_CAST"body")) ||
+	    (xmlStrEqual(ctxt->name, BAD_CAST"html")))) {
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"htmlAutoClose: EOF closes %s\n", ctxt->name);
+#endif
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+	    ctxt->sax->endElement(ctxt->userData, ctxt->name);
+	oldname = htmlnamePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"htmlAutoClose: popped %s\n", oldname);
+#endif
+	    xmlFree(oldname);
+        }
+   }
+
+}
+
+/**
+ * htmlAutoCloseTag:
+ * @doc:  the HTML document
+ * @name:  The tag name
+ * @elem:  the HTML element
+ *
+ * The HTmL DtD allows a tag to implicitely close other tags.
+ * The list is kept in htmlStartClose array. This function checks
+ * if the element or one of it's children would autoclose the
+ * given tag.
+ *
+ * Returns 1 if autoclose, 0 otherwise
+ */
+int
+htmlAutoCloseTag(htmlDocPtr doc, const xmlChar *name, htmlNodePtr elem) {
+    htmlNodePtr child;
+
+    if (elem == NULL) return(1);
+    if (xmlStrEqual(name, elem->name)) return(0);
+    if (htmlCheckAutoClose(elem->name, name)) return(1);
+    child = elem->children;
+    while (child != NULL) {
+        if (htmlAutoCloseTag(doc, name, child)) return(1);
+	child = child->next;
+    }
+    return(0);
+}
+
+/**
+ * htmlIsAutoClosed:
+ * @doc:  the HTML document
+ * @elem:  the HTML element
+ *
+ * The HTmL DtD allows a tag to implicitely close other tags.
+ * The list is kept in htmlStartClose array. This function checks
+ * if a tag is autoclosed by one of it's child
+ *
+ * Returns 1 if autoclosed, 0 otherwise
+ */
+int
+htmlIsAutoClosed(htmlDocPtr doc, htmlNodePtr elem) {
+    htmlNodePtr child;
+
+    if (elem == NULL) return(1);
+    child = elem->children;
+    while (child != NULL) {
+	if (htmlAutoCloseTag(doc, elem->name, child)) return(1);
+	child = child->next;
+    }
+    return(0);
+}
+
+/**
+ * htmlCheckImplied:
+ * @ctxt:  an HTML parser context
+ * @newtag:  The new tag name
+ *
+ * The HTML DtD allows a tag to exists only implicitely
+ * called when a new tag has been detected and generates the
+ * appropriates implicit tags if missing
+ */
+void
+htmlCheckImplied(htmlParserCtxtPtr ctxt, const xmlChar *newtag) {
+    if (!htmlOmittedDefaultValue)
+	return;
+    if (xmlStrEqual(newtag, BAD_CAST"html"))
+	return;
+    if (ctxt->nameNr <= 0) {
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"Implied element html: pushed html\n");
+#endif    
+	htmlnamePush(ctxt, xmlStrdup(BAD_CAST"html"));
+	if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+	    ctxt->sax->startElement(ctxt->userData, BAD_CAST"html", NULL);
+    }
+    if ((xmlStrEqual(newtag, BAD_CAST"body")) || (xmlStrEqual(newtag, BAD_CAST"head")))
+        return;
+    if ((ctxt->nameNr <= 1) && 
+        ((xmlStrEqual(newtag, BAD_CAST"script")) ||
+	 (xmlStrEqual(newtag, BAD_CAST"style")) ||
+	 (xmlStrEqual(newtag, BAD_CAST"meta")) ||
+	 (xmlStrEqual(newtag, BAD_CAST"link")) ||
+	 (xmlStrEqual(newtag, BAD_CAST"title")) ||
+	 (xmlStrEqual(newtag, BAD_CAST"base")))) {
+	    /* 
+	     * dropped OBJECT ... i you put it first BODY will be
+	     * assumed !
+	     */
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"Implied element head: pushed head\n");
+#endif    
+	    htmlnamePush(ctxt, xmlStrdup(BAD_CAST"head"));
+	    if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+		ctxt->sax->startElement(ctxt->userData, BAD_CAST"head", NULL);
+    } else if ((!xmlStrEqual(newtag, BAD_CAST"noframes")) &&
+	       (!xmlStrEqual(newtag, BAD_CAST"frame")) &&
+	       (!xmlStrEqual(newtag, BAD_CAST"frameset"))) {
+	int i;
+	for (i = 0;i < ctxt->nameNr;i++) {
+	    if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) {
+		return;
+	    }
+	    if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"head")) {
+		return;
+	    }
+	}
+	    
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"Implied element body: pushed body\n");
+#endif    
+	htmlnamePush(ctxt, xmlStrdup(BAD_CAST"body"));
+	if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+	    ctxt->sax->startElement(ctxt->userData, BAD_CAST"body", NULL);
+    }
+}
+
+/**
+ * htmlCheckParagraph
+ * @ctxt:  an HTML parser context
+ *
+ * Check whether a p element need to be implied before inserting
+ * characters in the current element.
+ *
+ * Returns 1 if a paragraph has been inserted, 0 if not and -1
+ *         in case of error.
+ */
+
+int
+htmlCheckParagraph(htmlParserCtxtPtr ctxt) {
+    const xmlChar *tag;
+    int i;
+
+    if (ctxt == NULL)
+	return(-1);
+    tag = ctxt->name;
+    if (tag == NULL) {
+	htmlAutoClose(ctxt, BAD_CAST"p");
+	htmlCheckImplied(ctxt, BAD_CAST"p");
+	htmlnamePush(ctxt, xmlStrdup(BAD_CAST"p"));
+	if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+	    ctxt->sax->startElement(ctxt->userData, BAD_CAST"p", NULL);
+	return(1);
+    }
+    if (!htmlOmittedDefaultValue)
+	return(0);
+    for (i = 0; htmlNoContentElements[i] != NULL; i++) {
+	if (xmlStrEqual(tag, BAD_CAST htmlNoContentElements[i])) {
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"Implied element paragraph\n");
+#endif    
+	    htmlAutoClose(ctxt, BAD_CAST"p");
+	    htmlCheckImplied(ctxt, BAD_CAST"p");
+	    htmlnamePush(ctxt, xmlStrdup(BAD_CAST"p"));
+	    if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+		ctxt->sax->startElement(ctxt->userData, BAD_CAST"p", NULL);
+	    return(1);
+	}
+    }
+    return(0);
+}
+
+/**
+ * htmlIsScriptAttribute:
+ * @name:  an attribute name
+ *
+ * Check if an attribute is of content type Script
+ *
+ * Returns 1 is the attribute is a script 0 otherwise
+ */
+int
+htmlIsScriptAttribute(const xmlChar *name) {
+    int i;
+
+    if (name == NULL)
+       	return(0);
+    /*
+     * all script attributes start with 'on'
+     */
+    if ((name[0] != 'o') || (name[1] != 'n'))
+       	return(0);
+    for (i = 0;
+	 i < sizeof(htmlScriptAttributes)/sizeof(htmlScriptAttributes[0]);
+	 i++) {
+	if (xmlStrEqual(name, (const xmlChar *) htmlScriptAttributes[i]))
+	    return(1);
+    }
+    return(0);
+}
+
+/************************************************************************
+ *									*
+ * 		The list of HTML predefined entities			*
+ *									*
+ ************************************************************************/
+
+
+htmlEntityDesc  html40EntitiesTable[] = {
+/*
+ * the 4 absolute ones, plus apostrophe.
+ */
+{ 34,	"quot",	"quotation mark = APL quote, U+0022 ISOnum" },
+{ 38,	"amp",	"ampersand, U+0026 ISOnum" },
+{ 39,	"apos",	"single quote" },
+{ 60,	"lt",	"less-than sign, U+003C ISOnum" },
+{ 62,	"gt",	"greater-than sign, U+003E ISOnum" },
+
+/*
+ * A bunch still in the 128-255 range
+ * Replacing them depend really on the charset used.
+ */
+{ 160,	"nbsp",	"no-break space = non-breaking space, U+00A0 ISOnum" },
+{ 161,	"iexcl","inverted exclamation mark, U+00A1 ISOnum" },
+{ 162,	"cent",	"cent sign, U+00A2 ISOnum" },
+{ 163,	"pound","pound sign, U+00A3 ISOnum" },
+{ 164,	"curren","currency sign, U+00A4 ISOnum" },
+{ 165,	"yen",	"yen sign = yuan sign, U+00A5 ISOnum" },
+{ 166,	"brvbar","broken bar = broken vertical bar, U+00A6 ISOnum" },
+{ 167,	"sect",	"section sign, U+00A7 ISOnum" },
+{ 168,	"uml",	"diaeresis = spacing diaeresis, U+00A8 ISOdia" },
+{ 169,	"copy",	"copyright sign, U+00A9 ISOnum" },
+{ 170,	"ordf",	"feminine ordinal indicator, U+00AA ISOnum" },
+{ 171,	"laquo","left-pointing double angle quotation mark = left pointing guillemet, U+00AB ISOnum" },
+{ 172,	"not",	"not sign, U+00AC ISOnum" },
+{ 173,	"shy",	"soft hyphen = discretionary hyphen, U+00AD ISOnum" },
+{ 174,	"reg",	"registered sign = registered trade mark sign, U+00AE ISOnum" },
+{ 175,	"macr",	"macron = spacing macron = overline = APL overbar, U+00AF ISOdia" },
+{ 176,	"deg",	"degree sign, U+00B0 ISOnum" },
+{ 177,	"plusmn","plus-minus sign = plus-or-minus sign, U+00B1 ISOnum" },
+{ 178,	"sup2",	"superscript two = superscript digit two = squared, U+00B2 ISOnum" },
+{ 179,	"sup3",	"superscript three = superscript digit three = cubed, U+00B3 ISOnum" },
+{ 180,	"acute","acute accent = spacing acute, U+00B4 ISOdia" },
+{ 181,	"micro","micro sign, U+00B5 ISOnum" },
+{ 182,	"para",	"pilcrow sign = paragraph sign, U+00B6 ISOnum" },
+{ 183,	"middot","middle dot = Georgian comma Greek middle dot, U+00B7 ISOnum" },
+{ 184,	"cedil","cedilla = spacing cedilla, U+00B8 ISOdia" },
+{ 185,	"sup1",	"superscript one = superscript digit one, U+00B9 ISOnum" },
+{ 186,	"ordm",	"masculine ordinal indicator, U+00BA ISOnum" },
+{ 187,	"raquo","right-pointing double angle quotation mark right pointing guillemet, U+00BB ISOnum" },
+{ 188,	"frac14","vulgar fraction one quarter = fraction one quarter, U+00BC ISOnum" },
+{ 189,	"frac12","vulgar fraction one half = fraction one half, U+00BD ISOnum" },
+{ 190,	"frac34","vulgar fraction three quarters = fraction three quarters, U+00BE ISOnum" },
+{ 191,	"iquest","inverted question mark = turned question mark, U+00BF ISOnum" },
+{ 192,	"Agrave","latin capital letter A with grave = latin capital letter A grave, U+00C0 ISOlat1" },
+{ 193,	"Aacute","latin capital letter A with acute, U+00C1 ISOlat1" },
+{ 194,	"Acirc","latin capital letter A with circumflex, U+00C2 ISOlat1" },
+{ 195,	"Atilde","latin capital letter A with tilde, U+00C3 ISOlat1" },
+{ 196,	"Auml",	"latin capital letter A with diaeresis, U+00C4 ISOlat1" },
+{ 197,	"Aring","latin capital letter A with ring above = latin capital letter A ring, U+00C5 ISOlat1" },
+{ 198,	"AElig","latin capital letter AE = latin capital ligature AE, U+00C6 ISOlat1" },
+{ 199,	"Ccedil","latin capital letter C with cedilla, U+00C7 ISOlat1" },
+{ 200,	"Egrave","latin capital letter E with grave, U+00C8 ISOlat1" },
+{ 201,	"Eacute","latin capital letter E with acute, U+00C9 ISOlat1" },
+{ 202,	"Ecirc","latin capital letter E with circumflex, U+00CA ISOlat1" },
+{ 203,	"Euml",	"latin capital letter E with diaeresis, U+00CB ISOlat1" },
+{ 204,	"Igrave","latin capital letter I with grave, U+00CC ISOlat1" },
+{ 205,	"Iacute","latin capital letter I with acute, U+00CD ISOlat1" },
+{ 206,	"Icirc","latin capital letter I with circumflex, U+00CE ISOlat1" },
+{ 207,	"Iuml",	"latin capital letter I with diaeresis, U+00CF ISOlat1" },
+{ 208,	"ETH",	"latin capital letter ETH, U+00D0 ISOlat1" },
+{ 209,	"Ntilde","latin capital letter N with tilde, U+00D1 ISOlat1" },
+{ 210,	"Ograve","latin capital letter O with grave, U+00D2 ISOlat1" },
+{ 211,	"Oacute","latin capital letter O with acute, U+00D3 ISOlat1" },
+{ 212,	"Ocirc","latin capital letter O with circumflex, U+00D4 ISOlat1" },
+{ 213,	"Otilde","latin capital letter O with tilde, U+00D5 ISOlat1" },
+{ 214,	"Ouml",	"latin capital letter O with diaeresis, U+00D6 ISOlat1" },
+{ 215,	"times","multiplication sign, U+00D7 ISOnum" },
+{ 216,	"Oslash","latin capital letter O with stroke latin capital letter O slash, U+00D8 ISOlat1" },
+{ 217,	"Ugrave","latin capital letter U with grave, U+00D9 ISOlat1" },
+{ 218,	"Uacute","latin capital letter U with acute, U+00DA ISOlat1" },
+{ 219,	"Ucirc","latin capital letter U with circumflex, U+00DB ISOlat1" },
+{ 220,	"Uuml",	"latin capital letter U with diaeresis, U+00DC ISOlat1" },
+{ 221,	"Yacute","latin capital letter Y with acute, U+00DD ISOlat1" },
+{ 222,	"THORN","latin capital letter THORN, U+00DE ISOlat1" },
+{ 223,	"szlig","latin small letter sharp s = ess-zed, U+00DF ISOlat1" },
+{ 224,	"agrave","latin small letter a with grave = latin small letter a grave, U+00E0 ISOlat1" },
+{ 225,	"aacute","latin small letter a with acute, U+00E1 ISOlat1" },
+{ 226,	"acirc","latin small letter a with circumflex, U+00E2 ISOlat1" },
+{ 227,	"atilde","latin small letter a with tilde, U+00E3 ISOlat1" },
+{ 228,	"auml",	"latin small letter a with diaeresis, U+00E4 ISOlat1" },
+{ 229,	"aring","latin small letter a with ring above = latin small letter a ring, U+00E5 ISOlat1" },
+{ 230,	"aelig","latin small letter ae = latin small ligature ae, U+00E6 ISOlat1" },
+{ 231,	"ccedil","latin small letter c with cedilla, U+00E7 ISOlat1" },
+{ 232,	"egrave","latin small letter e with grave, U+00E8 ISOlat1" },
+{ 233,	"eacute","latin small letter e with acute, U+00E9 ISOlat1" },
+{ 234,	"ecirc","latin small letter e with circumflex, U+00EA ISOlat1" },
+{ 235,	"euml",	"latin small letter e with diaeresis, U+00EB ISOlat1" },
+{ 236,	"igrave","latin small letter i with grave, U+00EC ISOlat1" },
+{ 237,	"iacute","latin small letter i with acute, U+00ED ISOlat1" },
+{ 238,	"icirc","latin small letter i with circumflex, U+00EE ISOlat1" },
+{ 239,	"iuml",	"latin small letter i with diaeresis, U+00EF ISOlat1" },
+{ 240,	"eth",	"latin small letter eth, U+00F0 ISOlat1" },
+{ 241,	"ntilde","latin small letter n with tilde, U+00F1 ISOlat1" },
+{ 242,	"ograve","latin small letter o with grave, U+00F2 ISOlat1" },
+{ 243,	"oacute","latin small letter o with acute, U+00F3 ISOlat1" },
+{ 244,	"ocirc","latin small letter o with circumflex, U+00F4 ISOlat1" },
+{ 245,	"otilde","latin small letter o with tilde, U+00F5 ISOlat1" },
+{ 246,	"ouml",	"latin small letter o with diaeresis, U+00F6 ISOlat1" },
+{ 247,	"divide","division sign, U+00F7 ISOnum" },
+{ 248,	"oslash","latin small letter o with stroke, = latin small letter o slash, U+00F8 ISOlat1" },
+{ 249,	"ugrave","latin small letter u with grave, U+00F9 ISOlat1" },
+{ 250,	"uacute","latin small letter u with acute, U+00FA ISOlat1" },
+{ 251,	"ucirc","latin small letter u with circumflex, U+00FB ISOlat1" },
+{ 252,	"uuml",	"latin small letter u with diaeresis, U+00FC ISOlat1" },
+{ 253,	"yacute","latin small letter y with acute, U+00FD ISOlat1" },
+{ 254,	"thorn","latin small letter thorn with, U+00FE ISOlat1" },
+{ 255,	"yuml",	"latin small letter y with diaeresis, U+00FF ISOlat1" },
+
+{ 338,	"OElig","latin capital ligature OE, U+0152 ISOlat2" },
+{ 339,	"oelig","latin small ligature oe, U+0153 ISOlat2" },
+{ 352,	"Scaron","latin capital letter S with caron, U+0160 ISOlat2" },
+{ 353,	"scaron","latin small letter s with caron, U+0161 ISOlat2" },
+{ 376,	"Yuml",	"latin capital letter Y with diaeresis, U+0178 ISOlat2" },
+
+/*
+ * Anything below should really be kept as entities references
+ */
+{ 402,	"fnof",	"latin small f with hook = function = florin, U+0192 ISOtech" },
+
+{ 710,	"circ",	"modifier letter circumflex accent, U+02C6 ISOpub" },
+{ 732,	"tilde","small tilde, U+02DC ISOdia" },
+
+{ 913,	"Alpha","greek capital letter alpha, U+0391" },
+{ 914,	"Beta",	"greek capital letter beta, U+0392" },
+{ 915,	"Gamma","greek capital letter gamma, U+0393 ISOgrk3" },
+{ 916,	"Delta","greek capital letter delta, U+0394 ISOgrk3" },
+{ 917,	"Epsilon","greek capital letter epsilon, U+0395" },
+{ 918,	"Zeta",	"greek capital letter zeta, U+0396" },
+{ 919,	"Eta",	"greek capital letter eta, U+0397" },
+{ 920,	"Theta","greek capital letter theta, U+0398 ISOgrk3" },
+{ 921,	"Iota",	"greek capital letter iota, U+0399" },
+{ 922,	"Kappa","greek capital letter kappa, U+039A" },
+{ 923,	"Lambda""greek capital letter lambda, U+039B ISOgrk3" },
+{ 924,	"Mu",	"greek capital letter mu, U+039C" },
+{ 925,	"Nu",	"greek capital letter nu, U+039D" },
+{ 926,	"Xi",	"greek capital letter xi, U+039E ISOgrk3" },
+{ 927,	"Omicron","greek capital letter omicron, U+039F" },
+{ 928,	"Pi",	"greek capital letter pi, U+03A0 ISOgrk3" },
+{ 929,	"Rho",	"greek capital letter rho, U+03A1" },
+{ 931,	"Sigma","greek capital letter sigma, U+03A3 ISOgrk3" },
+{ 932,	"Tau",	"greek capital letter tau, U+03A4" },
+{ 933,	"Upsilon","greek capital letter upsilon, U+03A5 ISOgrk3" },
+{ 934,	"Phi",	"greek capital letter phi, U+03A6 ISOgrk3" },
+{ 935,	"Chi",	"greek capital letter chi, U+03A7" },
+{ 936,	"Psi",	"greek capital letter psi, U+03A8 ISOgrk3" },
+{ 937,	"Omega","greek capital letter omega, U+03A9 ISOgrk3" },
+
+{ 945,	"alpha","greek small letter alpha, U+03B1 ISOgrk3" },
+{ 946,	"beta",	"greek small letter beta, U+03B2 ISOgrk3" },
+{ 947,	"gamma","greek small letter gamma, U+03B3 ISOgrk3" },
+{ 948,	"delta","greek small letter delta, U+03B4 ISOgrk3" },
+{ 949,	"epsilon","greek small letter epsilon, U+03B5 ISOgrk3" },
+{ 950,	"zeta",	"greek small letter zeta, U+03B6 ISOgrk3" },
+{ 951,	"eta",	"greek small letter eta, U+03B7 ISOgrk3" },
+{ 952,	"theta","greek small letter theta, U+03B8 ISOgrk3" },
+{ 953,	"iota",	"greek small letter iota, U+03B9 ISOgrk3" },
+{ 954,	"kappa","greek small letter kappa, U+03BA ISOgrk3" },
+{ 955,	"lambda","greek small letter lambda, U+03BB ISOgrk3" },
+{ 956,	"mu",	"greek small letter mu, U+03BC ISOgrk3" },
+{ 957,	"nu",	"greek small letter nu, U+03BD ISOgrk3" },
+{ 958,	"xi",	"greek small letter xi, U+03BE ISOgrk3" },
+{ 959,	"omicron","greek small letter omicron, U+03BF NEW" },
+{ 960,	"pi",	"greek small letter pi, U+03C0 ISOgrk3" },
+{ 961,	"rho",	"greek small letter rho, U+03C1 ISOgrk3" },
+{ 962,	"sigmaf","greek small letter final sigma, U+03C2 ISOgrk3" },
+{ 963,	"sigma","greek small letter sigma, U+03C3 ISOgrk3" },
+{ 964,	"tau",	"greek small letter tau, U+03C4 ISOgrk3" },
+{ 965,	"upsilon","greek small letter upsilon, U+03C5 ISOgrk3" },
+{ 966,	"phi",	"greek small letter phi, U+03C6 ISOgrk3" },
+{ 967,	"chi",	"greek small letter chi, U+03C7 ISOgrk3" },
+{ 968,	"psi",	"greek small letter psi, U+03C8 ISOgrk3" },
+{ 969,	"omega","greek small letter omega, U+03C9 ISOgrk3" },
+{ 977,	"thetasym","greek small letter theta symbol, U+03D1 NEW" },
+{ 978,	"upsih","greek upsilon with hook symbol, U+03D2 NEW" },
+{ 982,	"piv",	"greek pi symbol, U+03D6 ISOgrk3" },
+
+{ 8194,	"ensp",	"en space, U+2002 ISOpub" },
+{ 8195,	"emsp",	"em space, U+2003 ISOpub" },
+{ 8201,	"thinsp","thin space, U+2009 ISOpub" },
+{ 8204,	"zwnj",	"zero width non-joiner, U+200C NEW RFC 2070" },
+{ 8205,	"zwj",	"zero width joiner, U+200D NEW RFC 2070" },
+{ 8206,	"lrm",	"left-to-right mark, U+200E NEW RFC 2070" },
+{ 8207,	"rlm",	"right-to-left mark, U+200F NEW RFC 2070" },
+{ 8211,	"ndash","en dash, U+2013 ISOpub" },
+{ 8212,	"mdash","em dash, U+2014 ISOpub" },
+{ 8216,	"lsquo","left single quotation mark, U+2018 ISOnum" },
+{ 8217,	"rsquo","right single quotation mark, U+2019 ISOnum" },
+{ 8218,	"sbquo","single low-9 quotation mark, U+201A NEW" },
+{ 8220,	"ldquo","left double quotation mark, U+201C ISOnum" },
+{ 8221,	"rdquo","right double quotation mark, U+201D ISOnum" },
+{ 8222,	"bdquo","double low-9 quotation mark, U+201E NEW" },
+{ 8224,	"dagger","dagger, U+2020 ISOpub" },
+{ 8225,	"Dagger","double dagger, U+2021 ISOpub" },
+
+{ 8226,	"bull",	"bullet = black small circle, U+2022 ISOpub" },
+{ 8230,	"hellip","horizontal ellipsis = three dot leader, U+2026 ISOpub" },
+
+{ 8240,	"permil","per mille sign, U+2030 ISOtech" },
+
+{ 8242,	"prime","prime = minutes = feet, U+2032 ISOtech" },
+{ 8243,	"Prime","double prime = seconds = inches, U+2033 ISOtech" },
+
+{ 8249,	"lsaquo","single left-pointing angle quotation mark, U+2039 ISO proposed" },
+{ 8250,	"rsaquo","single right-pointing angle quotation mark, U+203A ISO proposed" },
+
+{ 8254,	"oline","overline = spacing overscore, U+203E NEW" },
+{ 8260,	"frasl","fraction slash, U+2044 NEW" },
+
+{ 8364,	"euro",	"euro sign, U+20AC NEW" },
+
+{ 8465,	"image","blackletter capital I = imaginary part, U+2111 ISOamso" },
+{ 8472,	"weierp","script capital P = power set = Weierstrass p, U+2118 ISOamso" },
+{ 8476,	"real",	"blackletter capital R = real part symbol, U+211C ISOamso" },
+{ 8482,	"trade","trade mark sign, U+2122 ISOnum" },
+{ 8501,	"alefsym","alef symbol = first transfinite cardinal, U+2135 NEW" },
+{ 8592,	"larr",	"leftwards arrow, U+2190 ISOnum" },
+{ 8593,	"uarr",	"upwards arrow, U+2191 ISOnum" },
+{ 8594,	"rarr",	"rightwards arrow, U+2192 ISOnum" },
+{ 8595,	"darr",	"downwards arrow, U+2193 ISOnum" },
+{ 8596,	"harr",	"left right arrow, U+2194 ISOamsa" },
+{ 8629,	"crarr","downwards arrow with corner leftwards = carriage return, U+21B5 NEW" },
+{ 8656,	"lArr",	"leftwards double arrow, U+21D0 ISOtech" },
+{ 8657,	"uArr",	"upwards double arrow, U+21D1 ISOamsa" },
+{ 8658,	"rArr",	"rightwards double arrow, U+21D2 ISOtech" },
+{ 8659,	"dArr",	"downwards double arrow, U+21D3 ISOamsa" },
+{ 8660,	"hArr",	"left right double arrow, U+21D4 ISOamsa" },
+
+{ 8704,	"forall","for all, U+2200 ISOtech" },
+{ 8706,	"part",	"partial differential, U+2202 ISOtech" },
+{ 8707,	"exist","there exists, U+2203 ISOtech" },
+{ 8709,	"empty","empty set = null set = diameter, U+2205 ISOamso" },
+{ 8711,	"nabla","nabla = backward difference, U+2207 ISOtech" },
+{ 8712,	"isin",	"element of, U+2208 ISOtech" },
+{ 8713,	"notin","not an element of, U+2209 ISOtech" },
+{ 8715,	"ni",	"contains as member, U+220B ISOtech" },
+{ 8719,	"prod",	"n-ary product = product sign, U+220F ISOamsb" },
+{ 8721,	"sum",	"n-ary sumation, U+2211 ISOamsb" },
+{ 8722,	"minus","minus sign, U+2212 ISOtech" },
+{ 8727,	"lowast","asterisk operator, U+2217 ISOtech" },
+{ 8730,	"radic","square root = radical sign, U+221A ISOtech" },
+{ 8733,	"prop",	"proportional to, U+221D ISOtech" },
+{ 8734,	"infin","infinity, U+221E ISOtech" },
+{ 8736,	"ang",	"angle, U+2220 ISOamso" },
+{ 8743,	"and",	"logical and = wedge, U+2227 ISOtech" },
+{ 8744,	"or",	"logical or = vee, U+2228 ISOtech" },
+{ 8745,	"cap",	"intersection = cap, U+2229 ISOtech" },
+{ 8746,	"cup",	"union = cup, U+222A ISOtech" },
+{ 8747,	"int",	"integral, U+222B ISOtech" },
+{ 8756,	"there4","therefore, U+2234 ISOtech" },
+{ 8764,	"sim",	"tilde operator = varies with = similar to, U+223C ISOtech" },
+{ 8773,	"cong",	"approximately equal to, U+2245 ISOtech" },
+{ 8776,	"asymp","almost equal to = asymptotic to, U+2248 ISOamsr" },
+{ 8800,	"ne",	"not equal to, U+2260 ISOtech" },
+{ 8801,	"equiv","identical to, U+2261 ISOtech" },
+{ 8804,	"le",	"less-than or equal to, U+2264 ISOtech" },
+{ 8805,	"ge",	"greater-than or equal to, U+2265 ISOtech" },
+{ 8834,	"sub",	"subset of, U+2282 ISOtech" },
+{ 8835,	"sup",	"superset of, U+2283 ISOtech" },
+{ 8836,	"nsub",	"not a subset of, U+2284 ISOamsn" },
+{ 8838,	"sube",	"subset of or equal to, U+2286 ISOtech" },
+{ 8839,	"supe",	"superset of or equal to, U+2287 ISOtech" },
+{ 8853,	"oplus","circled plus = direct sum, U+2295 ISOamsb" },
+{ 8855,	"otimes","circled times = vector product, U+2297 ISOamsb" },
+{ 8869,	"perp",	"up tack = orthogonal to = perpendicular, U+22A5 ISOtech" },
+{ 8901,	"sdot",	"dot operator, U+22C5 ISOamsb" },
+{ 8968,	"lceil","left ceiling = apl upstile, U+2308 ISOamsc" },
+{ 8969,	"rceil","right ceiling, U+2309 ISOamsc" },
+{ 8970,	"lfloor","left floor = apl downstile, U+230A ISOamsc" },
+{ 8971,	"rfloor","right floor, U+230B ISOamsc" },
+{ 9001,	"lang",	"left-pointing angle bracket = bra, U+2329 ISOtech" },
+{ 9002,	"rang",	"right-pointing angle bracket = ket, U+232A ISOtech" },
+{ 9674,	"loz",	"lozenge, U+25CA ISOpub" },
+
+{ 9824,	"spades","black spade suit, U+2660 ISOpub" },
+{ 9827,	"clubs","black club suit = shamrock, U+2663 ISOpub" },
+{ 9829,	"hearts","black heart suit = valentine, U+2665 ISOpub" },
+{ 9830,	"diams","black diamond suit, U+2666 ISOpub" },
+
+};
+
+/************************************************************************
+ *									*
+ *		Commodity functions to handle entities			*
+ *									*
+ ************************************************************************/
+
+/*
+ * Macro used to grow the current buffer.
+ */
+#define growBuffer(buffer) {						\
+    buffer##_size *= 2;							\
+    buffer = (xmlChar *) xmlRealloc(buffer, buffer##_size * sizeof(xmlChar));	\
+    if (buffer == NULL) {						\
+	perror("realloc failed");					\
+	return(NULL);							\
+    }									\
+}
+
+/**
+ * htmlEntityLookup:
+ * @name: the entity name
+ *
+ * Lookup the given entity in EntitiesTable
+ *
+ * TODO: the linear scan is really ugly, an hash table is really needed.
+ *
+ * Returns the associated htmlEntityDescPtr if found, NULL otherwise.
+ */
+htmlEntityDescPtr
+htmlEntityLookup(const xmlChar *name) {
+    int i;
+
+    for (i = 0;i < (sizeof(html40EntitiesTable)/
+                    sizeof(html40EntitiesTable[0]));i++) {
+        if (xmlStrEqual(name, BAD_CAST html40EntitiesTable[i].name)) {
+#ifdef DEBUG
+            xmlGenericError(xmlGenericErrorContext,"Found entity %s\n", name);
+#endif
+            return(&html40EntitiesTable[i]);
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * htmlEntityValueLookup:
+ * @value: the entity's unicode value
+ *
+ * Lookup the given entity in EntitiesTable
+ *
+ * TODO: the linear scan is really ugly, an hash table is really needed.
+ *
+ * Returns the associated htmlEntityDescPtr if found, NULL otherwise.
+ */
+htmlEntityDescPtr
+htmlEntityValueLookup(int value) {
+    int i;
+#ifdef DEBUG
+    int lv = 0;
+#endif
+
+    for (i = 0;i < (sizeof(html40EntitiesTable)/
+                    sizeof(html40EntitiesTable[0]));i++) {
+        if ((unsigned int) html40EntitiesTable[i].value >= value) {
+	    if ((unsigned int) html40EntitiesTable[i].value > value)
+		break;
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"Found entity %s\n", html40EntitiesTable[i].name);
+#endif
+            return(&html40EntitiesTable[i]);
+	}
+#ifdef DEBUG
+	if (lv > html40EntitiesTable[i].value) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "html40EntitiesTable[] is not sorted (%d > %d)!\n",
+		    lv, html40EntitiesTable[i].value);
+	}
+	lv = html40EntitiesTable[i].value;
+#endif
+    }
+    return(NULL);
+}
+
+/**
+ * UTF8ToHtml:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of UTF-8 chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an ASCII
+ * plus HTML entities block of chars out.
+ *
+ * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of octets consumed.
+ */
+int
+UTF8ToHtml(unsigned char* out, int *outlen,
+              const unsigned char* in, int *inlen) {
+    const unsigned char* processed = in;
+    const unsigned char* outend;
+    const unsigned char* outstart = out;
+    const unsigned char* instart = in;
+    const unsigned char* inend;
+    unsigned int c, d;
+    int trailing;
+
+    if (in == NULL) {
+        /*
+	 * initialization nothing to do
+	 */
+	*outlen = 0;
+	*inlen = 0;
+	return(0);
+    }
+    inend = in + (*inlen);
+    outend = out + (*outlen);
+    while (in < inend) {
+	d = *in++;
+	if      (d < 0x80)  { c= d; trailing= 0; }
+	else if (d < 0xC0) {
+	    /* trailing byte in leading position */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+        } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
+        else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
+        else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
+	else {
+	    /* no chance for this in Ascii */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+	}
+
+	if (inend - in < trailing) {
+	    break;
+	} 
+
+	for ( ; trailing; trailing--) {
+	    if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
+		break;
+	    c <<= 6;
+	    c |= d & 0x3F;
+	}
+
+	/* assertion: c is a single UTF-4 value */
+	if (c < 0x80) {
+	    if (out + 1 >= outend)
+		break;
+	    *out++ = c;
+	} else {
+	    int len;
+	    htmlEntityDescPtr ent;
+
+	    /*
+	     * Try to lookup a predefined HTML entity for it
+	     */
+
+	    ent = htmlEntityValueLookup(c);
+	    if (ent == NULL) {
+		/* no chance for this in Ascii */
+		*outlen = out - outstart;
+		*inlen = processed - instart;
+		return(-2);
+	    }
+	    len = strlen(ent->name);
+	    if (out + 2 + len >= outend)
+		break;
+	    *out++ = '&';
+	    memcpy(out, ent->name, len);
+	    out += len;
+	    *out++ = ';';
+	}
+	processed = in;
+    }
+    *outlen = out - outstart;
+    *inlen = processed - instart;
+    return(0);
+}
+
+/**
+ * htmlEncodeEntities:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of UTF-8 chars
+ * @inlen:  the length of @in
+ * @quoteChar: the quote character to escape (' or ") or zero.
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an ASCII
+ * plus HTML entities block of chars out.
+ *
+ * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of octets consumed.
+ */
+int
+htmlEncodeEntities(unsigned char* out, int *outlen,
+		   const unsigned char* in, int *inlen, int quoteChar) {
+    const unsigned char* processed = in;
+    const unsigned char* outend = out + (*outlen);
+    const unsigned char* outstart = out;
+    const unsigned char* instart = in;
+    const unsigned char* inend = in + (*inlen);
+    unsigned int c, d;
+    int trailing;
+
+    while (in < inend) {
+	d = *in++;
+	if      (d < 0x80)  { c= d; trailing= 0; }
+	else if (d < 0xC0) {
+	    /* trailing byte in leading position */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+        } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
+        else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
+        else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
+	else {
+	    /* no chance for this in Ascii */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+	}
+
+	if (inend - in < trailing)
+	    break;
+
+	while (trailing--) {
+	    if (((d= *in++) & 0xC0) != 0x80) {
+		*outlen = out - outstart;
+		*inlen = processed - instart;
+		return(-2);
+	    }
+	    c <<= 6;
+	    c |= d & 0x3F;
+	}
+
+	/* assertion: c is a single UTF-4 value */
+	if (c < 0x80 && c != quoteChar && c != '&' && c != '<' && c != '>') {
+	    if (out >= outend)
+		break;
+	    *out++ = c;
+	} else {
+	    htmlEntityDescPtr ent;
+	    const char *cp;
+	    char nbuf[16];
+	    int len;
+
+	    /*
+	     * Try to lookup a predefined HTML entity for it
+	     */
+	    ent = htmlEntityValueLookup(c);
+	    if (ent == NULL) {
+		sprintf(nbuf, "#%u", c);
+		cp = nbuf;
+	    }
+	    else
+		cp = ent->name;
+	    len = strlen(cp);
+	    if (out + 2 + len > outend)
+		break;
+	    *out++ = '&';
+	    memcpy(out, cp, len);
+	    out += len;
+	    *out++ = ';';
+	}
+	processed = in;
+    }
+    *outlen = out - outstart;
+    *inlen = processed - instart;
+    return(0);
+}
+
+/**
+ * htmlDecodeEntities:
+ * @ctxt:  the parser context
+ * @len:  the len to decode (in bytes !), -1 for no size limit
+ * @end:  an end marker xmlChar, 0 if none
+ * @end2:  an end marker xmlChar, 0 if none
+ * @end3:  an end marker xmlChar, 0 if none
+ *
+ * Subtitute the HTML entities by their value
+ *
+ * DEPRECATED !!!!
+ *
+ * Returns A newly allocated string with the substitution done. The caller
+ *      must deallocate it !
+ */
+xmlChar *
+htmlDecodeEntities(htmlParserCtxtPtr ctxt, int len,
+                  xmlChar end, xmlChar  end2, xmlChar end3) {
+    xmlChar *name = NULL;
+    xmlChar *buffer = NULL;
+    unsigned int buffer_size = 0;
+    unsigned int nbchars = 0;
+    htmlEntityDescPtr ent;
+    unsigned int max = (unsigned int) len;
+    int c,l;
+
+    if (ctxt->depth > 40) {
+	ctxt->errNo = XML_ERR_ENTITY_LOOP;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"Detected entity reference loop\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+
+    /*
+     * allocate a translation buffer.
+     */
+    buffer_size = HTML_PARSER_BIG_BUFFER_SIZE;
+    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+	perror("xmlDecodeEntities: malloc failed");
+	return(NULL);
+    }
+
+    /*
+     * Ok loop until we reach one of the ending char or a size limit.
+     */
+    c = CUR_CHAR(l);
+    while ((nbchars < max) && (c != end) &&
+           (c != end2) && (c != end3)) {
+
+	if (c == 0) break;
+        if (((c == '&') && (ctxt->token != '&')) && (NXT(1) == '#')) {
+	    int val = htmlParseCharRef(ctxt);
+	    COPY_BUF(0,buffer,nbchars,val);
+	    NEXTL(l);
+	} else if ((c == '&') && (ctxt->token != '&')) {
+	    ent = htmlParseEntityRef(ctxt, &name);
+	    if (name != NULL) {
+		if (ent != NULL) {
+		    int val = ent->value;
+		    COPY_BUF(0,buffer,nbchars,val);
+		    NEXTL(l);
+		} else {
+		    const xmlChar *cur = name;
+
+		    buffer[nbchars++] = '&';
+		    if (nbchars > buffer_size - HTML_PARSER_BUFFER_SIZE) {
+			growBuffer(buffer);
+		    }
+		    while (*cur != 0) {
+			buffer[nbchars++] = *cur++;
+		    }
+		    buffer[nbchars++] = ';';
+		}
+	    }
+	} else {
+	    COPY_BUF(l,buffer,nbchars,c);
+	    NEXTL(l);
+	    if (nbchars > buffer_size - HTML_PARSER_BUFFER_SIZE) {
+	      growBuffer(buffer);
+	    }
+	}
+	c = CUR_CHAR(l);
+    }
+    buffer[nbchars++] = 0;
+    return(buffer);
+}
+
+/************************************************************************
+ *									*
+ *		Commodity functions to handle streams			*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlFreeInputStream:
+ * @input:  an htmlParserInputPtr
+ *
+ * Free up an input stream.
+ */
+void
+htmlFreeInputStream(htmlParserInputPtr input) {
+    if (input == NULL) return;
+
+    if (input->filename != NULL) xmlFree((char *) input->filename);
+    if (input->directory != NULL) xmlFree((char *) input->directory);
+    if ((input->free != NULL) && (input->base != NULL))
+        input->free((xmlChar *) input->base);
+    if (input->buf != NULL) 
+        xmlFreeParserInputBuffer(input->buf);
+    memset(input, -1, sizeof(htmlParserInput));
+    xmlFree(input);
+}
+
+/**
+ * htmlNewInputStream:
+ * @ctxt:  an HTML parser context
+ *
+ * Create a new input stream structure
+ * Returns the new input stream or NULL
+ */
+htmlParserInputPtr
+htmlNewInputStream(htmlParserCtxtPtr ctxt) {
+    htmlParserInputPtr input;
+
+    input = (xmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput));
+    if (input == NULL) {
+        ctxt->errNo = XML_ERR_NO_MEMORY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	                     "malloc: couldn't allocate a new input stream\n");
+	return(NULL);
+    }
+    memset(input, 0, sizeof(htmlParserInput));
+    input->filename = NULL;
+    input->directory = NULL;
+    input->base = NULL;
+    input->cur = NULL;
+    input->buf = NULL;
+    input->line = 1;
+    input->col = 1;
+    input->buf = NULL;
+    input->free = NULL;
+    input->version = NULL;
+    input->consumed = 0;
+    input->length = 0;
+    return(input);
+}
+
+
+/************************************************************************
+ *									*
+ *		Commodity functions, cleanup needed ?			*
+ *									*
+ ************************************************************************/
+
+/**
+ * areBlanks:
+ * @ctxt:  an HTML parser context
+ * @str:  a xmlChar *
+ * @len:  the size of @str
+ *
+ * Is this a sequence of blank chars that one can ignore ?
+ *
+ * Returns 1 if ignorable 0 otherwise.
+ */
+
+static int areBlanks(htmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
+    int i;
+    xmlNodePtr lastChild;
+
+    for (i = 0;i < len;i++)
+        if (!(IS_BLANK(str[i]))) return(0);
+
+    if (CUR == 0) return(1);
+    if (CUR != '<') return(0);
+    if (ctxt->name == NULL)
+	return(1);
+    if (xmlStrEqual(ctxt->name, BAD_CAST"html"))
+	return(1);
+    if (xmlStrEqual(ctxt->name, BAD_CAST"head"))
+	return(1);
+    if (xmlStrEqual(ctxt->name, BAD_CAST"body"))
+	return(1);
+    if (ctxt->node == NULL) return(0);
+    lastChild = xmlGetLastChild(ctxt->node);
+    if (lastChild == NULL) {
+        if (ctxt->node->content != NULL) return(0);
+    } else if (xmlNodeIsText(lastChild)) {
+        return(0);
+    } else if (xmlStrEqual(lastChild->name, BAD_CAST"b")) {
+        return(0);
+    } else if (xmlStrEqual(lastChild->name, BAD_CAST"bold")) {
+        return(0);
+    } else if (xmlStrEqual(lastChild->name, BAD_CAST"em")) {
+        return(0);
+    }
+    return(1);
+}
+
+/**
+ * htmlHandleEntity:
+ * @ctxt:  an HTML parser context
+ * @entity:  an XML entity pointer.
+ *
+ * Default handling of an HTML entity, call the parser with the
+ * substitution string
+ */
+
+void
+htmlHandleEntity(htmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
+    int len;
+
+    if (entity->content == NULL) {
+        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "htmlHandleEntity %s: content == NULL\n",
+	               entity->name);
+	ctxt->wellFormed = 0;
+        return;
+    }
+    len = xmlStrlen(entity->content);
+
+    /*
+     * Just handle the content as a set of chars.
+     */
+    htmlCheckParagraph(ctxt);
+    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
+	ctxt->sax->characters(ctxt->userData, entity->content, len);
+
+}
+
+/**
+ * htmlNewDocNoDtD:
+ * @URI:  URI for the dtd, or NULL
+ * @ExternalID:  the external ID of the DTD, or NULL
+ *
+ * Returns a new document, do not intialize the DTD if not provided
+ */
+htmlDocPtr
+htmlNewDocNoDtD(const xmlChar *URI, const xmlChar *ExternalID) {
+    xmlDocPtr cur;
+
+    /*
+     * Allocate a new document and fill the fields.
+     */
+    cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewDoc : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlDoc));
+
+    cur->type = XML_HTML_DOCUMENT_NODE;
+    cur->version = NULL;
+    cur->intSubset = NULL;
+    if ((ExternalID != NULL) ||
+	(URI != NULL))
+	xmlCreateIntSubset(cur, BAD_CAST "HTML", ExternalID, URI);
+    cur->doc = cur;
+    cur->name = NULL;
+    cur->children = NULL; 
+    cur->extSubset = NULL;
+    cur->oldNs = NULL;
+    cur->encoding = NULL;
+    cur->standalone = 1;
+    cur->compression = 0;
+    cur->ids = NULL;
+    cur->refs = NULL;
+#ifndef XML_WITHOUT_CORBA
+    cur->_private = NULL;
+#endif
+    return(cur);
+}
+
+/**
+ * htmlNewDoc:
+ * @URI:  URI for the dtd, or NULL
+ * @ExternalID:  the external ID of the DTD, or NULL
+ *
+ * Returns a new document
+ */
+htmlDocPtr
+htmlNewDoc(const xmlChar *URI, const xmlChar *ExternalID) {
+    if ((URI == NULL) && (ExternalID == NULL))
+	return(htmlNewDocNoDtD(
+		    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
+		    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd"));
+
+    return(htmlNewDocNoDtD(URI, ExternalID));
+}
+
+
+/************************************************************************
+ *									*
+ *			The parser itself				*
+ *	Relates to http://www.w3.org/TR/html40				*
+ *									*
+ ************************************************************************/
+
+/************************************************************************
+ *									*
+ *			The parser itself				*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlParseHTMLName:
+ * @ctxt:  an HTML parser context
+ *
+ * parse an HTML tag or attribute name, note that we convert it to lowercase
+ * since HTML names are not case-sensitive.
+ *
+ * Returns the Tag Name parsed or NULL
+ */
+
+xmlChar *
+htmlParseHTMLName(htmlParserCtxtPtr ctxt) {
+    xmlChar *ret = NULL;
+    int i = 0;
+    xmlChar loc[HTML_PARSER_BUFFER_SIZE];
+
+    if (!IS_LETTER(CUR) && (CUR != '_') &&
+        (CUR != ':')) return(NULL);
+
+    while ((i < HTML_PARSER_BUFFER_SIZE) &&
+           ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+	   (CUR == ':') || (CUR == '-') || (CUR == '_'))) {
+	if ((CUR >= 'A') && (CUR <= 'Z')) loc[i] = CUR + 0x20;
+        else loc[i] = CUR;
+	i++;
+	
+	NEXT;
+    }
+    
+    ret = xmlStrndup(loc, i);
+
+    return(ret);
+}
+
+/**
+ * htmlParseName:
+ * @ctxt:  an HTML parser context
+ *
+ * parse an HTML name, this routine is case sensistive.
+ *
+ * Returns the Name parsed or NULL
+ */
+
+xmlChar *
+htmlParseName(htmlParserCtxtPtr ctxt) {
+    xmlChar buf[HTML_MAX_NAMELEN];
+    int len = 0;
+
+    GROW;
+    if (!IS_LETTER(CUR) && (CUR != '_')) {
+	return(NULL);
+    }
+
+    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+           (CUR == '.') || (CUR == '-') ||
+	   (CUR == '_') || (CUR == ':') || 
+	   (IS_COMBINING(CUR)) ||
+	   (IS_EXTENDER(CUR))) {
+	buf[len++] = CUR;
+	NEXT;
+	if (len >= HTML_MAX_NAMELEN) {
+	    xmlGenericError(xmlGenericErrorContext, 
+	       "htmlParseName: reached HTML_MAX_NAMELEN limit\n");
+	    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+		   (CUR == '.') || (CUR == '-') ||
+		   (CUR == '_') || (CUR == ':') || 
+		   (IS_COMBINING(CUR)) ||
+		   (IS_EXTENDER(CUR)))
+		 NEXT;
+	    break;
+	}
+    }
+    return(xmlStrndup(buf, len));
+}
+
+/**
+ * htmlParseHTMLAttribute:
+ * @ctxt:  an HTML parser context
+ * @stop:  a char stop value
+ * 
+ * parse an HTML attribute value till the stop (quote), if
+ * stop is 0 then it stops at the first space
+ *
+ * Returns the attribute parsed or NULL
+ */
+
+xmlChar *
+htmlParseHTMLAttribute(htmlParserCtxtPtr ctxt, const xmlChar stop) {
+    xmlChar *buffer = NULL;
+    int buffer_size = 0;
+    xmlChar *out = NULL;
+    xmlChar *name = NULL;
+
+    xmlChar *cur = NULL;
+    htmlEntityDescPtr ent;
+
+    /*
+     * allocate a translation buffer.
+     */
+    buffer_size = HTML_PARSER_BUFFER_SIZE;
+    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+	perror("htmlParseHTMLAttribute: malloc failed");
+	return(NULL);
+    }
+    out = buffer;
+
+    /*
+     * Ok loop until we reach one of the ending chars
+     */
+    while ((CUR != 0) && (CUR != stop) && (CUR != '>')) {
+	if ((stop == 0) && (IS_BLANK(CUR))) break;
+        if (CUR == '&') {
+	    if (NXT(1) == '#') {
+		unsigned int c;
+		int bits;
+
+		c = htmlParseCharRef(ctxt);
+		if      (c <    0x80)
+		        { *out++  = c;                bits= -6; }
+		else if (c <   0x800)
+		        { *out++  =((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+		else if (c < 0x10000)
+		        { *out++  =((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+		else                 
+		        { *out++  =((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+	 
+		for ( ; bits >= 0; bits-= 6) {
+		    *out++  = ((c >> bits) & 0x3F) | 0x80;
+		}
+	    } else {
+		ent = htmlParseEntityRef(ctxt, &name);
+		if (name == NULL) {
+		    *out++ = '&';
+		    if (out - buffer > buffer_size - 100) {
+			int index = out - buffer;
+
+			growBuffer(buffer);
+			out = &buffer[index];
+		    }
+		} else if (ent == NULL) {
+		    *out++ = '&';
+		    cur = name;
+		    while (*cur != 0) {
+			if (out - buffer > buffer_size - 100) {
+			    int index = out - buffer;
+
+			    growBuffer(buffer);
+			    out = &buffer[index];
+			}
+			*out++ = *cur++;
+		    }
+		    xmlFree(name);
+		} else {
+		    unsigned int c;
+		    int bits;
+
+		    if (out - buffer > buffer_size - 100) {
+			int index = out - buffer;
+
+			growBuffer(buffer);
+			out = &buffer[index];
+		    }
+		    c = (xmlChar)ent->value;
+		    if      (c <    0x80)
+			{ *out++  = c;                bits= -6; }
+		    else if (c <   0x800)
+			{ *out++  =((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+		    else if (c < 0x10000)
+			{ *out++  =((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+		    else                 
+			{ *out++  =((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+	     
+		    for ( ; bits >= 0; bits-= 6) {
+			*out++  = ((c >> bits) & 0x3F) | 0x80;
+		    }
+		    xmlFree(name);
+		}
+	    }
+	} else {
+	    unsigned int c;
+	    int bits, l;
+
+	    if (out - buffer > buffer_size - 100) {
+		int index = out - buffer;
+
+		growBuffer(buffer);
+		out = &buffer[index];
+	    }
+	    c = CUR_CHAR(l);
+	    if      (c <    0x80)
+		    { *out++  = c;                bits= -6; }
+	    else if (c <   0x800)
+		    { *out++  =((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+	    else if (c < 0x10000)
+		    { *out++  =((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+	    else                 
+		    { *out++  =((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+     
+	    for ( ; bits >= 0; bits-= 6) {
+		*out++  = ((c >> bits) & 0x3F) | 0x80;
+	    }
+	    NEXT;
+	}
+    }
+    *out++ = 0;
+    return(buffer);
+}
+
+/**
+ * htmlParseNmtoken:
+ * @ctxt:  an HTML parser context
+ * 
+ * parse an HTML Nmtoken.
+ *
+ * Returns the Nmtoken parsed or NULL
+ */
+
+xmlChar *
+htmlParseNmtoken(htmlParserCtxtPtr ctxt) {
+    xmlChar buf[HTML_MAX_NAMELEN];
+    int len = 0;
+
+    GROW;
+    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+           (CUR == '.') || (CUR == '-') ||
+	   (CUR == '_') || (CUR == ':') || 
+	   (IS_COMBINING(CUR)) ||
+	   (IS_EXTENDER(CUR))) {
+	buf[len++] = CUR;
+	NEXT;
+	if (len >= HTML_MAX_NAMELEN) {
+	    xmlGenericError(xmlGenericErrorContext, 
+	       "htmlParseNmtoken: reached HTML_MAX_NAMELEN limit\n");
+	    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+		   (CUR == '.') || (CUR == '-') ||
+		   (CUR == '_') || (CUR == ':') || 
+		   (IS_COMBINING(CUR)) ||
+		   (IS_EXTENDER(CUR)))
+		 NEXT;
+	    break;
+	}
+    }
+    return(xmlStrndup(buf, len));
+}
+
+/**
+ * htmlParseEntityRef:
+ * @ctxt:  an HTML parser context
+ * @str:  location to store the entity name
+ *
+ * parse an HTML ENTITY references
+ *
+ * [68] EntityRef ::= '&' Name ';'
+ *
+ * Returns the associated htmlEntityDescPtr if found, or NULL otherwise,
+ *         if non-NULL *str will have to be freed by the caller.
+ */
+htmlEntityDescPtr
+htmlParseEntityRef(htmlParserCtxtPtr ctxt, xmlChar **str) {
+    xmlChar *name;
+    htmlEntityDescPtr ent = NULL;
+    *str = NULL;
+
+    if (CUR == '&') {
+        NEXT;
+        name = htmlParseName(ctxt);
+	if (name == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "htmlParseEntityRef: no name\n");
+	    ctxt->wellFormed = 0;
+	} else {
+	    GROW;
+	    if (CUR == ';') {
+		*str = name;
+
+		/*
+		 * Lookup the entity in the table.
+		 */
+		ent = htmlEntityLookup(name);
+		if (ent != NULL) /* OK that's ugly !!! */
+		    NEXT;
+	    } else {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "htmlParseEntityRef: expecting ';'\n");
+		*str = name;
+	    }
+	}
+    }
+    return(ent);
+}
+
+/**
+ * htmlParseAttValue:
+ * @ctxt:  an HTML parser context
+ *
+ * parse a value for an attribute
+ * Note: the parser won't do substitution of entities here, this
+ * will be handled later in xmlStringGetNodeList, unless it was
+ * asked for ctxt->replaceEntities != 0 
+ *
+ * Returns the AttValue parsed or NULL.
+ */
+
+xmlChar *
+htmlParseAttValue(htmlParserCtxtPtr ctxt) {
+    xmlChar *ret = NULL;
+
+    if (CUR == '"') {
+        NEXT;
+	ret = htmlParseHTMLAttribute(ctxt, '"');
+        if (CUR != '"') {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
+	    ctxt->wellFormed = 0;
+	} else
+	    NEXT;
+    } else if (CUR == '\'') {
+        NEXT;
+	ret = htmlParseHTMLAttribute(ctxt, '\'');
+        if (CUR != '\'') {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
+	    ctxt->wellFormed = 0;
+	} else
+	    NEXT;
+    } else {
+        /*
+	 * That's an HTMLism, the attribute value may not be quoted
+	 */
+	ret = htmlParseHTMLAttribute(ctxt, 0);
+	if (ret == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, "AttValue: no value found\n");
+	    ctxt->wellFormed = 0;
+	}
+    }
+    return(ret);
+}
+
+/**
+ * htmlParseSystemLiteral:
+ * @ctxt:  an HTML parser context
+ * 
+ * parse an HTML Literal
+ *
+ * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
+ *
+ * Returns the SystemLiteral parsed or NULL
+ */
+
+xmlChar *
+htmlParseSystemLiteral(htmlParserCtxtPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+
+    if (CUR == '"') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_CHAR(CUR)) && (CUR != '"'))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
+	    ctxt->wellFormed = 0;
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+        }
+    } else if (CUR == '\'') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_CHAR(CUR)) && (CUR != '\''))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
+	    ctxt->wellFormed = 0;
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+        }
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "SystemLiteral \" or ' expected\n");
+	ctxt->wellFormed = 0;
+    }
+    
+    return(ret);
+}
+
+/**
+ * htmlParsePubidLiteral:
+ * @ctxt:  an HTML parser context
+ *
+ * parse an HTML public literal
+ *
+ * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
+ *
+ * Returns the PubidLiteral parsed or NULL.
+ */
+
+xmlChar *
+htmlParsePubidLiteral(htmlParserCtxtPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+    /*
+     * Name ::= (Letter | '_') (NameChar)*
+     */
+    if (CUR == '"') {
+        NEXT;
+	q = CUR_PTR;
+	while (IS_PUBIDCHAR(CUR)) NEXT;
+	if (CUR != '"') {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
+	    ctxt->wellFormed = 0;
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+	}
+    } else if (CUR == '\'') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_LETTER(CUR)) && (CUR != '\''))
+	    NEXT;
+	if (!IS_LETTER(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
+	    ctxt->wellFormed = 0;
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+	}
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "SystemLiteral \" or ' expected\n");
+	ctxt->wellFormed = 0;
+    }
+    
+    return(ret);
+}
+
+/**
+ * htmlParseScript:
+ * @ctxt:  an HTML parser context
+ *
+ * parse the content of an HTML SCRIPT or STYLE element
+ * http://www.w3.org/TR/html4/sgml/dtd.html#Script
+ * http://www.w3.org/TR/html4/sgml/dtd.html#StyleSheet
+ * http://www.w3.org/TR/html4/types.html#type-script
+ * http://www.w3.org/TR/html4/types.html#h-6.15
+ * http://www.w3.org/TR/html4/appendix/notes.html#h-B.3.2.1
+ *
+ * Script data ( %Script; in the DTD) can be the content of the SCRIPT
+ * element and the value of intrinsic event attributes. User agents must
+ * not evaluate script data as HTML markup but instead must pass it on as
+ * data to a script engine.
+ * NOTES:
+ * - The content is passed like CDATA
+ * - the attributes for style and scripting "onXXX" are also described
+ *   as CDATA but SGML allows entities references in attributes so their
+ *   processing is identical as other attributes
+ */
+void
+htmlParseScript(htmlParserCtxtPtr ctxt) {
+    xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 1];
+    int nbchar = 0;
+    xmlChar cur;
+
+    SHRINK;
+    cur = CUR;
+    while (IS_CHAR(cur)) {
+	if ((cur == '<') && (NXT(1) == '/')) {
+	    /*
+	     * One should break here, the specification is clear:
+	     * Authors should therefore escape "</" within the content.
+	     * Escape mechanisms are specific to each scripting or
+	     * style sheet language.
+	     */
+	    if (((NXT(2) >= 'A') && (NXT(2) <= 'Z')) ||
+	        ((NXT(2) >= 'a') && (NXT(2) <= 'z')))
+		break; /* while */
+	}
+	buf[nbchar++] = cur;
+	if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
+	    if (ctxt->sax->cdataBlock!= NULL) {
+		/*
+		 * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
+		 */
+		ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
+	    }
+	    nbchar = 0;
+	}
+	NEXT;
+	cur = CUR;
+    }
+    if (!(IS_CHAR(cur))) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"Invalid char in CDATA 0x%X\n", cur);
+	ctxt->wellFormed = 0;
+	NEXT;
+    }
+
+    if ((nbchar != 0) && (ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+	if (ctxt->sax->cdataBlock!= NULL) {
+	    /*
+	     * Insert as CDATA, which is the same as HTML_PRESERVE_NODE
+	     */
+	    ctxt->sax->cdataBlock(ctxt->userData, buf, nbchar);
+	}
+    }
+}
+
+
+/**
+ * htmlParseCharData:
+ * @ctxt:  an HTML parser context
+ * @cdata:  int indicating whether we are within a CDATA section
+ *
+ * parse a CharData section.
+ * if we are within a CDATA section ']]>' marks an end of section.
+ *
+ * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
+ */
+
+void
+htmlParseCharData(htmlParserCtxtPtr ctxt, int cdata) {
+    xmlChar buf[HTML_PARSER_BIG_BUFFER_SIZE + 5];
+    int nbchar = 0;
+    int cur, l;
+
+    SHRINK;
+    cur = CUR_CHAR(l);
+    while (((cur != '<') || (ctxt->token == '<')) &&
+           ((cur != '&') || (ctxt->token == '&')) && 
+	   (IS_CHAR(cur))) {
+	COPY_BUF(l,buf,nbchar,cur);
+	if (nbchar >= HTML_PARSER_BIG_BUFFER_SIZE) {
+	    /*
+	     * Ok the segment is to be consumed as chars.
+	     */
+	    if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+		if (areBlanks(ctxt, buf, nbchar)) {
+		    if (ctxt->sax->ignorableWhitespace != NULL)
+			ctxt->sax->ignorableWhitespace(ctxt->userData,
+			                               buf, nbchar);
+		} else {
+		    htmlCheckParagraph(ctxt);
+		    if (ctxt->sax->characters != NULL)
+			ctxt->sax->characters(ctxt->userData, buf, nbchar);
+		}
+	    }
+	    nbchar = 0;
+	}
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+    }
+    if (nbchar != 0) {
+	/*
+	 * Ok the segment is to be consumed as chars.
+	 */
+	if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+	    if (areBlanks(ctxt, buf, nbchar)) {
+		if (ctxt->sax->ignorableWhitespace != NULL)
+		    ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
+	    } else {
+		htmlCheckParagraph(ctxt);
+		if (ctxt->sax->characters != NULL)
+		    ctxt->sax->characters(ctxt->userData, buf, nbchar);
+	    }
+	}
+    }
+}
+
+/**
+ * htmlParseExternalID:
+ * @ctxt:  an HTML parser context
+ * @publicID:  a xmlChar** receiving PubidLiteral
+ * @strict: indicate whether we should restrict parsing to only
+ *          production [75], see NOTE below
+ *
+ * Parse an External ID or a Public ID
+ *
+ * NOTE: Productions [75] and [83] interract badly since [75] can generate
+ *       'PUBLIC' S PubidLiteral S SystemLiteral
+ *
+ * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
+ *                   | 'PUBLIC' S PubidLiteral S SystemLiteral
+ *
+ * [83] PublicID ::= 'PUBLIC' S PubidLiteral
+ *
+ * Returns the function returns SystemLiteral and in the second
+ *                case publicID receives PubidLiteral, is strict is off
+ *                it is possible to return NULL and have publicID set.
+ */
+
+xmlChar *
+htmlParseExternalID(htmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
+    xmlChar *URI = NULL;
+
+    if ((UPPER == 'S') && (UPP(1) == 'Y') &&
+         (UPP(2) == 'S') && (UPP(3) == 'T') &&
+	 (UPP(4) == 'E') && (UPP(5) == 'M')) {
+        SKIP(6);
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Space required after 'SYSTEM'\n");
+	    ctxt->wellFormed = 0;
+	}
+        SKIP_BLANKS;
+	URI = htmlParseSystemLiteral(ctxt);
+	if (URI == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+	          "htmlParseExternalID: SYSTEM, no URI\n");
+	    ctxt->wellFormed = 0;
+        }
+    } else if ((UPPER == 'P') && (UPP(1) == 'U') &&
+	       (UPP(2) == 'B') && (UPP(3) == 'L') &&
+	       (UPP(4) == 'I') && (UPP(5) == 'C')) {
+        SKIP(6);
+	if (!IS_BLANK(CUR)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Space required after 'PUBLIC'\n");
+	    ctxt->wellFormed = 0;
+	}
+        SKIP_BLANKS;
+	*publicID = htmlParsePubidLiteral(ctxt);
+	if (*publicID == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	          "htmlParseExternalID: PUBLIC, no Public Identifier\n");
+	    ctxt->wellFormed = 0;
+	}
+        SKIP_BLANKS;
+        if ((CUR == '"') || (CUR == '\'')) {
+	    URI = htmlParseSystemLiteral(ctxt);
+	}
+    }
+    return(URI);
+}
+
+/**
+ * htmlParseComment:
+ * @ctxt:  an HTML parser context
+ *
+ * Parse an XML (SGML) comment <!-- .... -->
+ *
+ * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+ */
+void
+htmlParseComment(htmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len;
+    int size = HTML_PARSER_BUFFER_SIZE;
+    int q, ql;
+    int r, rl;
+    int cur, l;
+    xmlParserInputState state;
+
+    /*
+     * Check that there is a comment right here.
+     */
+    if ((RAW != '<') || (NXT(1) != '!') ||
+        (NXT(2) != '-') || (NXT(3) != '-')) return;
+
+    state = ctxt->instate;
+    ctxt->instate = XML_PARSER_COMMENT;
+    SHRINK;
+    SKIP(4);
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	ctxt->instate = state;
+	return;
+    }
+    q = CUR_CHAR(ql);
+    NEXTL(ql);
+    r = CUR_CHAR(rl);
+    NEXTL(rl);
+    cur = CUR_CHAR(l);
+    len = 0;
+    while (IS_CHAR(cur) &&
+           ((cur != '>') ||
+	    (r != '-') || (q != '-'))) {
+	if (len + 5 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		ctxt->instate = state;
+		return;
+	    }
+	}
+	COPY_BUF(ql,buf,len,q);
+	q = r;
+	ql = rl;
+	r = cur;
+	rl = l;
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+	if (cur == 0) {
+	    SHRINK;
+	    GROW;
+	    cur = CUR_CHAR(l);
+	}
+    }
+    buf[len] = 0;
+    if (!IS_CHAR(cur)) {
+	ctxt->errNo = XML_ERR_COMMENT_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "Comment not terminated \n<!--%.50s\n", buf);
+	ctxt->wellFormed = 0;
+	xmlFree(buf);
+    } else {
+        NEXT;
+	if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
+	    (!ctxt->disableSAX))
+	    ctxt->sax->comment(ctxt->userData, buf);
+	xmlFree(buf);
+    }
+    ctxt->instate = state;
+}
+
+/**
+ * htmlParseCharRef:
+ * @ctxt:  an HTML parser context
+ *
+ * parse Reference declarations
+ *
+ * [66] CharRef ::= '&#' [0-9]+ ';' |
+ *                  '&#x' [0-9a-fA-F]+ ';'
+ *
+ * Returns the value parsed (as an int)
+ */
+int
+htmlParseCharRef(htmlParserCtxtPtr ctxt) {
+    int val = 0;
+
+    if ((CUR == '&') && (NXT(1) == '#') &&
+        (NXT(2) == 'x')) {
+	SKIP(3);
+	while (CUR != ';') {
+	    if ((CUR >= '0') && (CUR <= '9')) 
+	        val = val * 16 + (CUR - '0');
+	    else if ((CUR >= 'a') && (CUR <= 'f'))
+	        val = val * 16 + (CUR - 'a') + 10;
+	    else if ((CUR >= 'A') && (CUR <= 'F'))
+	        val = val * 16 + (CUR - 'A') + 10;
+	    else {
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		         "htmlParseCharRef: invalid hexadecimal value\n");
+		ctxt->wellFormed = 0;
+		return(0);
+	    }
+	    NEXT;
+	}
+	if (CUR == ';')
+	    NEXT;
+    } else if  ((CUR == '&') && (NXT(1) == '#')) {
+	SKIP(2);
+	while (CUR != ';') {
+	    if ((CUR >= '0') && (CUR <= '9')) 
+	        val = val * 10 + (CUR - '0');
+	    else {
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		         "htmlParseCharRef: invalid decimal value\n");
+		ctxt->wellFormed = 0;
+		return(0);
+	    }
+	    NEXT;
+	}
+	if (CUR == ';')
+	    NEXT;
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "htmlParseCharRef: invalid value\n");
+	ctxt->wellFormed = 0;
+    }
+    /*
+     * Check the value IS_CHAR ...
+     */
+    if (IS_CHAR(val)) {
+        return(val);
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "htmlParseCharRef: invalid xmlChar value %d\n",
+	                     val);
+	ctxt->wellFormed = 0;
+    }
+    return(0);
+}
+
+
+/**
+ * htmlParseDocTypeDecl :
+ * @ctxt:  an HTML parser context
+ *
+ * parse a DOCTYPE declaration
+ *
+ * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? 
+ *                      ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
+ */
+
+void
+htmlParseDocTypeDecl(htmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *ExternalID = NULL;
+    xmlChar *URI = NULL;
+
+    /*
+     * We know that '<!DOCTYPE' has been detected.
+     */
+    SKIP(9);
+
+    SKIP_BLANKS;
+
+    /*
+     * Parse the DOCTYPE name.
+     */
+    name = htmlParseName(ctxt);
+    if (name == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "htmlParseDocTypeDecl : no DOCTYPE name !\n");
+	ctxt->wellFormed = 0;
+    }
+    /*
+     * Check that upper(name) == "HTML" !!!!!!!!!!!!!
+     */
+
+    SKIP_BLANKS;
+
+    /*
+     * Check for SystemID and ExternalID
+     */
+    URI = htmlParseExternalID(ctxt, &ExternalID, 0);
+    SKIP_BLANKS;
+
+    /*
+     * We should be at the end of the DOCTYPE declaration.
+     */
+    if (CUR != '>') {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
+	ctxt->wellFormed = 0;
+        /* We shouldn't try to resynchronize ... */
+    }
+    NEXT;
+
+    /*
+     * Create or update the document accordingly to the DOCTYPE
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) &&
+	(!ctxt->disableSAX))
+	ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
+
+    /*
+     * Cleanup, since we don't use all those identifiers
+     */
+    if (URI != NULL) xmlFree(URI);
+    if (ExternalID != NULL) xmlFree(ExternalID);
+    if (name != NULL) xmlFree(name);
+}
+
+/**
+ * htmlParseAttribute:
+ * @ctxt:  an HTML parser context
+ * @value:  a xmlChar ** used to store the value of the attribute
+ *
+ * parse an attribute
+ *
+ * [41] Attribute ::= Name Eq AttValue
+ *
+ * [25] Eq ::= S? '=' S?
+ *
+ * With namespace:
+ *
+ * [NS 11] Attribute ::= QName Eq AttValue
+ *
+ * Also the case QName == xmlns:??? is handled independently as a namespace
+ * definition.
+ *
+ * Returns the attribute name, and the value in *value.
+ */
+
+xmlChar *
+htmlParseAttribute(htmlParserCtxtPtr ctxt, xmlChar **value) {
+    xmlChar *name, *val = NULL;
+
+    *value = NULL;
+    name = htmlParseHTMLName(ctxt);
+    if (name == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
+	ctxt->wellFormed = 0;
+        return(NULL);
+    }
+
+    /*
+     * read the value
+     */
+    SKIP_BLANKS;
+    if (CUR == '=') {
+        NEXT;
+	SKIP_BLANKS;
+	val = htmlParseAttValue(ctxt);
+	/******
+    } else {
+        * TODO : some attribute must have values, some may not
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->warning(ctxt->userData,
+	       "No value for attribute %s\n", name); */
+    }
+
+    *value = val;
+    return(name);
+}
+
+/**
+ * htmlCheckEncoding:
+ * @ctxt:  an HTML parser context
+ * @attvalue: the attribute value
+ *
+ * Checks an http-equiv attribute from a Meta tag to detect
+ * the encoding
+ * If a new encoding is detected the parser is switched to decode
+ * it and pass UTF8
+ */
+void
+htmlCheckEncoding(htmlParserCtxtPtr ctxt, const xmlChar *attvalue) {
+    const xmlChar *encoding;
+
+    if ((ctxt == NULL) || (attvalue == NULL))
+	return;
+
+    /* do not change encoding */	
+    if (ctxt->input->encoding != NULL)
+        return;
+
+    encoding = xmlStrcasestr(attvalue, BAD_CAST"charset=");
+    if (encoding != NULL) {
+	encoding += 8;
+    } else {
+	encoding = xmlStrcasestr(attvalue, BAD_CAST"charset =");
+	if (encoding != NULL)
+	    encoding += 9;
+    }
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+	xmlCharEncodingHandlerPtr handler;
+
+	while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
+
+	if (ctxt->input->encoding != NULL)
+	    xmlFree((xmlChar *) ctxt->input->encoding);
+	ctxt->input->encoding = xmlStrdup(encoding);
+
+	enc = xmlParseCharEncoding((const char *) encoding);
+	/*
+	 * registered set of known encodings
+	 */
+	if (enc != XML_CHAR_ENCODING_ERROR) {
+	    xmlSwitchEncoding(ctxt, enc);
+	    ctxt->charset = XML_CHAR_ENCODING_UTF8;
+	} else {
+	    /*
+	     * fallback for unknown encodings
+	     */
+	    handler = xmlFindCharEncodingHandler((const char *) encoding);
+	    if (handler != NULL) {
+		xmlSwitchToEncoding(ctxt, handler);
+		ctxt->charset = XML_CHAR_ENCODING_UTF8;
+	    } else {
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+	    }
+	}
+
+	if ((ctxt->input->buf != NULL) &&
+	    (ctxt->input->buf->encoder != NULL) &&
+	    (ctxt->input->buf->raw != NULL) &&
+	    (ctxt->input->buf->buffer != NULL)) {
+	    int nbchars;
+	    int processed;
+
+	    /*
+	     * convert as much as possible to the parser reading buffer.
+	     */
+	    processed = ctxt->input->cur - ctxt->input->base;
+	    xmlBufferShrink(ctxt->input->buf->buffer, processed);
+	    nbchars = xmlCharEncInFunc(ctxt->input->buf->encoder,
+		                       ctxt->input->buf->buffer,
+				       ctxt->input->buf->raw);
+	    if (nbchars < 0) {
+		ctxt->errNo = XML_ERR_INVALID_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		     "htmlCheckEncoding: encoder error\n");
+	    }
+	    ctxt->input->base =
+	    ctxt->input->cur = ctxt->input->buf->buffer->content;
+	}
+    }
+}
+
+/**
+ * htmlCheckMeta:
+ * @ctxt:  an HTML parser context
+ * @atts:  the attributes values
+ *
+ * Checks an attributes from a Meta tag
+ */
+void
+htmlCheckMeta(htmlParserCtxtPtr ctxt, const xmlChar **atts) {
+    int i;
+    const xmlChar *att, *value;
+    int http = 0;
+    const xmlChar *content = NULL;
+
+    if ((ctxt == NULL) || (atts == NULL))
+	return;
+
+    i = 0;
+    att = atts[i++];
+    while (att != NULL) {
+	value = atts[i++];
+	if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"http-equiv"))
+	 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
+	    http = 1;
+	else if ((value != NULL) && (!xmlStrcasecmp(att, BAD_CAST"content")))
+	    content = value;
+	att = atts[i++];
+    }
+    if ((http) && (content != NULL))
+	htmlCheckEncoding(ctxt, content);
+
+}
+
+/**
+ * htmlParseStartTag:
+ * @ctxt:  an HTML parser context
+ * 
+ * parse a start of tag either for rule element or
+ * EmptyElement. In both case we don't parse the tag closing chars.
+ *
+ * [40] STag ::= '<' Name (S Attribute)* S? '>'
+ *
+ * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
+ *
+ * With namespace:
+ *
+ * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
+ *
+ * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
+ *
+ */
+
+void
+htmlParseStartTag(htmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *attname;
+    xmlChar *attvalue;
+    const xmlChar **atts = NULL;
+    int nbatts = 0;
+    int maxatts = 0;
+    int meta = 0;
+    int i;
+
+    if (CUR != '<') return;
+    NEXT;
+
+    GROW;
+    name = htmlParseHTMLName(ctxt);
+    if (name == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	     "htmlParseStartTag: invalid element name\n");
+	ctxt->wellFormed = 0;
+	/* Dump the bogus tag like browsers do */
+	while ((IS_CHAR(CUR)) && (CUR != '>'))
+	    NEXT;
+        return;
+    }
+    if (xmlStrEqual(name, BAD_CAST"meta"))
+	meta = 1;
+
+    /*
+     * Check for auto-closure of HTML elements.
+     */
+    htmlAutoClose(ctxt, name);
+
+    /*
+     * Check for implied HTML elements.
+     */
+    htmlCheckImplied(ctxt, name);
+
+    /*
+     * Avoid html at any level > 0, head at any level != 1
+     * or any attempt to recurse body
+     */
+    if ((ctxt->nameNr > 0) && (xmlStrEqual(name, BAD_CAST"html"))) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	     "htmlParseStartTag: misplaced <html> tag\n");
+	ctxt->wellFormed = 0;
+	xmlFree(name);
+	return;
+    }
+    if ((ctxt->nameNr != 1) && 
+	(xmlStrEqual(name, BAD_CAST"head"))) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	     "htmlParseStartTag: misplaced <head> tag\n");
+	ctxt->wellFormed = 0;
+	xmlFree(name);
+	return;
+    }
+    if (xmlStrEqual(name, BAD_CAST"body")) {
+	int i;
+	for (i = 0;i < ctxt->nameNr;i++) {
+	    if (xmlStrEqual(ctxt->nameTab[i], BAD_CAST"body")) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		     "htmlParseStartTag: misplaced <body> tag\n");
+		ctxt->wellFormed = 0;
+		xmlFree(name);
+		return;
+	    }
+	}
+    }
+
+    /*
+     * Now parse the attributes, it ends up with the ending
+     *
+     * (S Attribute)* S?
+     */
+    SKIP_BLANKS;
+    while ((IS_CHAR(CUR)) &&
+           (CUR != '>') && 
+	   ((CUR != '/') || (NXT(1) != '>'))) {
+	long cons = ctxt->nbChars;
+
+	GROW;
+	attname = htmlParseAttribute(ctxt, &attvalue);
+        if (attname != NULL) {
+
+	    /*
+	     * Well formedness requires at most one declaration of an attribute
+	     */
+	    for (i = 0; i < nbatts;i += 2) {
+	        if (xmlStrEqual(atts[i], attname)) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			                 "Attribute %s redefined\n",
+			                 attname);
+		    ctxt->wellFormed = 0;
+		    xmlFree(attname);
+		    if (attvalue != NULL)
+			xmlFree(attvalue);
+		    goto failed;
+		}
+	    }
+
+	    /*
+	     * Add the pair to atts
+	     */
+	    if (atts == NULL) {
+	        maxatts = 10;
+	        atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *));
+		if (atts == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "malloc of %ld byte failed\n",
+			    maxatts * (long)sizeof(xmlChar *));
+		    if (name != NULL) xmlFree(name);
+		    return;
+		}
+	    } else if (nbatts + 4 > maxatts) {
+	        maxatts *= 2;
+	        atts = (const xmlChar **) xmlRealloc((void *) atts,
+			                             maxatts * sizeof(xmlChar *));
+		if (atts == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "realloc of %ld byte failed\n",
+			    maxatts * (long)sizeof(xmlChar *));
+		    if (name != NULL) xmlFree(name);
+		    return;
+		}
+	    }
+	    atts[nbatts++] = attname;
+	    atts[nbatts++] = attvalue;
+	    atts[nbatts] = NULL;
+	    atts[nbatts + 1] = NULL;
+	}
+	else {
+	    /* Dump the bogus attribute string up to the next blank or
+	     * the end of the tag. */
+	    while ((IS_CHAR(CUR)) && !(IS_BLANK(CUR)) && (CUR != '>')
+	     && ((CUR != '/') || (NXT(1) != '>')))
+		NEXT;
+	}
+
+failed:
+	SKIP_BLANKS;
+        if (cons == ctxt->nbChars) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	         "htmlParseStartTag: problem parsing attributes\n");
+	    ctxt->wellFormed = 0;
+	    break;
+	}
+    }
+
+    /*
+     * Handle specific association to the META tag
+     */
+    if (meta)
+	htmlCheckMeta(ctxt, atts);
+
+    /*
+     * SAX: Start of Element !
+     */
+    htmlnamePush(ctxt, xmlStrdup(name));
+#ifdef DEBUG
+    xmlGenericError(xmlGenericErrorContext,"Start of element %s: pushed %s\n", name, ctxt->name);
+#endif    
+    if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL))
+        ctxt->sax->startElement(ctxt->userData, name, atts);
+
+    if (atts != NULL) {
+        for (i = 0;i < nbatts;i++) {
+	    if (atts[i] != NULL)
+		xmlFree((xmlChar *) atts[i]);
+	}
+	xmlFree((void *) atts);
+    }
+    if (name != NULL) xmlFree(name);
+}
+
+/**
+ * htmlParseEndTag:
+ * @ctxt:  an HTML parser context
+ *
+ * parse an end of tag
+ *
+ * [42] ETag ::= '</' Name S? '>'
+ *
+ * With namespace
+ *
+ * [NS 9] ETag ::= '</' QName S? '>'
+ */
+
+void
+htmlParseEndTag(htmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *oldname;
+    int i;
+
+    if ((CUR != '<') || (NXT(1) != '/')) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "htmlParseEndTag: '</' not found\n");
+	ctxt->wellFormed = 0;
+	return;
+    }
+    SKIP(2);
+
+    name = htmlParseHTMLName(ctxt);
+    if (name == NULL) return;
+
+    /*
+     * We should definitely be at the ending "S? '>'" part
+     */
+    SKIP_BLANKS;
+    if ((!IS_CHAR(CUR)) || (CUR != '>')) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
+	ctxt->wellFormed = 0;
+    } else
+	NEXT;
+
+    /*
+     * If the name read is not one of the element in the parsing stack
+     * then return, it's just an error.
+     */
+    for (i = (ctxt->nameNr - 1);i >= 0;i--) {
+        if (xmlStrEqual(name, ctxt->nameTab[i])) break;
+    }
+    if (i < 0) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	     "Unexpected end tag : %s\n", name);
+	xmlFree(name);
+	ctxt->wellFormed = 0;
+	return;
+    }
+
+
+    /*
+     * Check for auto-closure of HTML elements.
+     */
+
+    htmlAutoCloseOnClose(ctxt, name);
+
+    /*
+     * Well formedness constraints, opening and closing must match.
+     * With the exception that the autoclose may have popped stuff out
+     * of the stack.
+     */
+    if (!xmlStrEqual(name, ctxt->name)) {
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"End of tag %s: expecting %s\n", name, ctxt->name);
+#endif
+        if ((ctxt->name != NULL) && 
+	    (!xmlStrEqual(ctxt->name, name))) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		 "Opening and ending tag mismatch: %s and %s\n",
+		                 name, ctxt->name);
+	    ctxt->wellFormed = 0;
+        }
+    }
+
+    /*
+     * SAX: End of Tag
+     */
+    oldname = ctxt->name;
+    if ((oldname != NULL) && (xmlStrEqual(oldname, name))) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+	    ctxt->sax->endElement(ctxt->userData, name);
+	oldname = htmlnamePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"End of tag %s: popping out %s\n", name, oldname);
+#endif
+	    xmlFree(oldname);
+#ifdef DEBUG
+	} else {
+	    xmlGenericError(xmlGenericErrorContext,"End of tag %s: stack empty !!!\n", name);
+#endif
+	}
+    }
+
+    if (name != NULL)
+	xmlFree(name);
+
+    return;
+}
+
+
+/**
+ * htmlParseReference:
+ * @ctxt:  an HTML parser context
+ * 
+ * parse and handle entity references in content,
+ * this will end-up in a call to character() since this is either a
+ * CharRef, or a predefined entity.
+ */
+void
+htmlParseReference(htmlParserCtxtPtr ctxt) {
+    htmlEntityDescPtr ent;
+    xmlChar out[6];
+    xmlChar *name;
+    if (CUR != '&') return;
+
+    if (NXT(1) == '#') {
+	unsigned int c;
+	int bits, i = 0;
+
+	c = htmlParseCharRef(ctxt);
+	if (c == 0)
+	    return;
+
+        if      (c <    0x80) { out[i++]= c;                bits= -6; }
+        else if (c <   0x800) { out[i++]=((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+        else if (c < 0x10000) { out[i++]=((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+        else                  { out[i++]=((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+ 
+        for ( ; bits >= 0; bits-= 6) {
+            out[i++]= ((c >> bits) & 0x3F) | 0x80;
+        }
+	out[i] = 0;
+
+	htmlCheckParagraph(ctxt);
+	if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
+	    ctxt->sax->characters(ctxt->userData, out, i);
+    } else {
+	ent = htmlParseEntityRef(ctxt, &name);
+	if (name == NULL) {
+	    htmlCheckParagraph(ctxt);
+	    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
+	        ctxt->sax->characters(ctxt->userData, BAD_CAST "&", 1);
+	    return;
+	}
+	if ((ent == NULL) || (ent->value <= 0)) {
+	    htmlCheckParagraph(ctxt);
+	    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL)) {
+		ctxt->sax->characters(ctxt->userData, BAD_CAST "&", 1);
+		ctxt->sax->characters(ctxt->userData, name, xmlStrlen(name));
+		/* ctxt->sax->characters(ctxt->userData, BAD_CAST ";", 1); */
+	    }
+	} else {
+	    unsigned int c;
+	    int bits, i = 0;
+
+	    c = ent->value;
+	    if      (c <    0x80)
+	            { out[i++]= c;                bits= -6; }
+	    else if (c <   0x800)
+	            { out[i++]=((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+	    else if (c < 0x10000)
+	            { out[i++]=((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+	    else                 
+	            { out[i++]=((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+     
+	    for ( ; bits >= 0; bits-= 6) {
+		out[i++]= ((c >> bits) & 0x3F) | 0x80;
+	    }
+	    out[i] = 0;
+
+	    htmlCheckParagraph(ctxt);
+	    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
+		ctxt->sax->characters(ctxt->userData, out, i);
+	}
+	xmlFree(name);
+    }
+}
+
+/**
+ * htmlParseContent:
+ * @ctxt:  an HTML parser context
+ * @name:  the node name
+ *
+ * Parse a content: comment, sub-element, reference or text.
+ *
+ */
+
+void
+htmlParseContent(htmlParserCtxtPtr ctxt) {
+    xmlChar *currentNode;
+    int depth;
+
+    currentNode = xmlStrdup(ctxt->name);
+    depth = ctxt->nameNr;
+    while (1) {
+	long cons = ctxt->nbChars;
+
+        GROW;
+	/*
+	 * Our tag or one of it's parent or children is ending.
+	 */
+        if ((CUR == '<') && (NXT(1) == '/')) {
+	    htmlParseEndTag(ctxt);
+	    if (currentNode != NULL) xmlFree(currentNode);
+	    return;
+        }
+
+	/*
+	 * Has this node been popped out during parsing of
+	 * the next element
+	 */
+        if ((!xmlStrEqual(currentNode, ctxt->name)) &&
+	    (depth >= ctxt->nameNr)) {
+	    if (currentNode != NULL) xmlFree(currentNode);
+	    return;
+	}
+
+	if ((xmlStrEqual(currentNode, BAD_CAST"script")) ||
+	    (xmlStrEqual(currentNode, BAD_CAST"style"))) {
+	    /*
+	     * Handle SCRIPT/STYLE separately
+	     */
+	    htmlParseScript(ctxt);
+	} else {
+	    /*
+	     * Sometimes DOCTYPE arrives in the middle of the document
+	     */
+	    if ((CUR == '<') && (NXT(1) == '!') &&
+		(UPP(2) == 'D') && (UPP(3) == 'O') &&
+		(UPP(4) == 'C') && (UPP(5) == 'T') &&
+		(UPP(6) == 'Y') && (UPP(7) == 'P') &&
+		(UPP(8) == 'E')) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+				     "Misplaced DOCTYPE declaration\n");
+		ctxt->wellFormed = 0;
+		htmlParseDocTypeDecl(ctxt);
+	    }
+
+	    /*
+	     * First case :  a comment
+	     */
+	    if ((CUR == '<') && (NXT(1) == '!') &&
+		(NXT(2) == '-') && (NXT(3) == '-')) {
+		htmlParseComment(ctxt);
+	    }
+
+	    /*
+	     * Second case :  a sub-element.
+	     */
+	    else if (CUR == '<') {
+		htmlParseElement(ctxt);
+	    }
+
+	    /*
+	     * Third case : a reference. If if has not been resolved,
+	     *    parsing returns it's Name, create the node 
+	     */
+	    else if (CUR == '&') {
+		htmlParseReference(ctxt);
+	    }
+
+	    /*
+	     * Fourth : end of the resource
+	     */
+	    else if (CUR == 0) {
+		htmlAutoClose(ctxt, NULL);
+	    }
+
+	    /*
+	     * Last case, text. Note that References are handled directly.
+	     */
+	    else {
+		htmlParseCharData(ctxt, 0);
+	    }
+
+	    if (cons == ctxt->nbChars) {
+		if (ctxt->node != NULL) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+					 "detected an error in element content\n");
+		    ctxt->wellFormed = 0;
+		}
+		break;
+	    }
+	}
+        GROW;
+    }
+    if (currentNode != NULL) xmlFree(currentNode);
+}
+
+/**
+ * htmlParseElement:
+ * @ctxt:  an HTML parser context
+ *
+ * parse an HTML element, this is highly recursive
+ *
+ * [39] element ::= EmptyElemTag | STag content ETag
+ *
+ * [41] Attribute ::= Name Eq AttValue
+ */
+
+void
+htmlParseElement(htmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *currentNode = NULL;
+    htmlElemDescPtr info;
+    htmlParserNodeInfo node_info;
+    xmlChar *oldname;
+    int depth = ctxt->nameNr;
+
+    /* Capture start position */
+    if (ctxt->record_info) {
+        node_info.begin_pos = ctxt->input->consumed +
+                          (CUR_PTR - ctxt->input->base);
+	node_info.begin_line = ctxt->input->line;
+    }
+
+    oldname = xmlStrdup(ctxt->name);
+    htmlParseStartTag(ctxt);
+    name = ctxt->name;
+#ifdef DEBUG
+    if (oldname == NULL)
+	xmlGenericError(xmlGenericErrorContext,
+		"Start of element %s\n", name);
+    else if (name == NULL)	
+	xmlGenericError(xmlGenericErrorContext,
+		"Start of element failed, was %s\n", oldname);
+    else	
+	xmlGenericError(xmlGenericErrorContext,
+		"Start of element %s, was %s\n", name, oldname);
+#endif
+    if (((depth == ctxt->nameNr) && (xmlStrEqual(oldname, ctxt->name))) ||
+        (name == NULL)) {
+	if (CUR == '>')
+	    NEXT;
+	if (oldname != NULL)
+	    xmlFree(oldname);
+        return;
+    }
+    if (oldname != NULL)
+	xmlFree(oldname);
+
+    /*
+     * Lookup the info for that element.
+     */
+    info = htmlTagLookup(name);
+    if (info == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Tag %s invalid\n",
+			     name);
+	ctxt->wellFormed = 0;
+    } else if (info->depr) {
+/***************************
+	if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	    ctxt->sax->warning(ctxt->userData, "Tag %s is deprecated\n",
+			       name);
+ ***************************/
+    }
+
+    /*
+     * Check for an Empty Element labelled the XML/SGML way
+     */
+    if ((CUR == '/') && (NXT(1) == '>')) {
+        SKIP(2);
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+	    ctxt->sax->endElement(ctxt->userData, name);
+	oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+        xmlGenericError(xmlGenericErrorContext,"End of tag the XML way: popping out %s\n", oldname);
+#endif
+	if (oldname != NULL)
+	    xmlFree(oldname);
+	return;
+    }
+
+    if (CUR == '>') {
+        NEXT;
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		             "Couldn't find end of Start Tag %s\n",
+	                     name);
+	ctxt->wellFormed = 0;
+
+	/*
+	 * end of parsing of this node.
+	 */
+	if (xmlStrEqual(name, ctxt->name)) { 
+	    nodePop(ctxt);
+	    oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+	    xmlGenericError(xmlGenericErrorContext,"End of start tag problem: popping out %s\n", oldname);
+#endif
+	    if (oldname != NULL)
+		xmlFree(oldname);
+	}    
+
+	/*
+	 * Capture end position and add node
+	 */
+	if ( currentNode != NULL && ctxt->record_info ) {
+	   node_info.end_pos = ctxt->input->consumed +
+			      (CUR_PTR - ctxt->input->base);
+	   node_info.end_line = ctxt->input->line;
+	   node_info.node = ctxt->node;
+	   xmlParserAddNodeInfo(ctxt, &node_info);
+	}
+	return;
+    }
+
+    /*
+     * Check for an Empty Element from DTD definition
+     */
+    if ((info != NULL) && (info->empty)) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+	    ctxt->sax->endElement(ctxt->userData, name);
+	oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"End of empty tag %s : popping out %s\n", name, oldname);
+#endif
+	if (oldname != NULL)
+	    xmlFree(oldname);
+	return;
+    }
+
+    /*
+     * Parse the content of the element:
+     */
+    currentNode = xmlStrdup(ctxt->name);
+    depth = ctxt->nameNr;
+    while (IS_CHAR(CUR)) {
+	htmlParseContent(ctxt);
+	if (ctxt->nameNr < depth) break; 
+    }	
+
+    if (!IS_CHAR(CUR)) {
+	/************
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	         "Premature end of data in tag %s\n", currentNode);
+	ctxt->wellFormed = 0;
+	 *************/
+
+	/*
+	 * end of parsing of this node.
+	 */
+	nodePop(ctxt);
+	oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+	xmlGenericError(xmlGenericErrorContext,"Premature end of tag %s : popping out %s\n", name, oldname);
+#endif
+	if (oldname != NULL)
+	    xmlFree(oldname);
+	if (currentNode != NULL)
+	    xmlFree(currentNode);
+	return;
+    }
+
+    /*
+     * Capture end position and add node
+     */
+    if ( currentNode != NULL && ctxt->record_info ) {
+       node_info.end_pos = ctxt->input->consumed +
+                          (CUR_PTR - ctxt->input->base);
+       node_info.end_line = ctxt->input->line;
+       node_info.node = ctxt->node;
+       xmlParserAddNodeInfo(ctxt, &node_info);
+    }
+    if (currentNode != NULL)
+	xmlFree(currentNode);
+}
+
+/**
+ * htmlParseDocument :
+ * @ctxt:  an HTML parser context
+ * 
+ * parse an HTML document (and build a tree if using the standard SAX
+ * interface).
+ *
+ * Returns 0, -1 in case of error. the parser context is augmented
+ *                as a result of the parsing.
+ */
+
+int
+htmlParseDocument(htmlParserCtxtPtr ctxt) {
+    xmlDtdPtr dtd;
+
+    htmlDefaultSAXHandlerInit();
+    ctxt->html = 1;
+
+    GROW;
+    /*
+     * SAX: beginning of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+        ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
+
+    /*
+     * Wipe out everything which is before the first '<'
+     */
+    SKIP_BLANKS;
+    if (CUR == 0) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Document is empty\n");
+	ctxt->wellFormed = 0;
+    }
+
+    if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX))
+	ctxt->sax->startDocument(ctxt->userData);
+
+
+    /*
+     * Parse possible comments before any content
+     */
+    while ((CUR == '<') && (NXT(1) == '!') &&
+           (NXT(2) == '-') && (NXT(3) == '-')) {
+        htmlParseComment(ctxt);	   
+	SKIP_BLANKS;
+    }	   
+
+
+    /*
+     * Then possibly doc type declaration(s) and more Misc
+     * (doctypedecl Misc*)?
+     */
+    if ((CUR == '<') && (NXT(1) == '!') &&
+	(UPP(2) == 'D') && (UPP(3) == 'O') &&
+	(UPP(4) == 'C') && (UPP(5) == 'T') &&
+	(UPP(6) == 'Y') && (UPP(7) == 'P') &&
+	(UPP(8) == 'E')) {
+	htmlParseDocTypeDecl(ctxt);
+    }
+    SKIP_BLANKS;
+
+    /*
+     * Parse possible comments before any content
+     */
+    while ((CUR == '<') && (NXT(1) == '!') &&
+           (NXT(2) == '-') && (NXT(3) == '-')) {
+        htmlParseComment(ctxt);	   
+	SKIP_BLANKS;
+    }	   
+
+    /*
+     * Time to start parsing the tree itself
+     */
+    htmlParseContent(ctxt);
+
+    /*
+     * autoclose
+     */
+    if (CUR == 0)
+	htmlAutoClose(ctxt, NULL);
+
+
+    /*
+     * SAX: end of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+        ctxt->sax->endDocument(ctxt->userData);
+
+    if (ctxt->myDoc != NULL) {
+	dtd = xmlGetIntSubset(ctxt->myDoc);
+	if (dtd == NULL)
+	    ctxt->myDoc->intSubset = 
+		xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "HTML", 
+		    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
+		    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
+    }
+    if (! ctxt->wellFormed) return(-1);
+    return(0);
+}
+
+
+/************************************************************************
+ *									*
+ *			Parser contexts handling			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlInitParserCtxt:
+ * @ctxt:  an HTML parser context
+ *
+ * Initialize a parser context
+ */
+
+void
+htmlInitParserCtxt(htmlParserCtxtPtr ctxt)
+{
+    htmlSAXHandler *sax;
+
+    if (ctxt == NULL) return;
+    memset(ctxt, 0, sizeof(htmlParserCtxt));
+
+    sax = (htmlSAXHandler *) xmlMalloc(sizeof(htmlSAXHandler));
+    if (sax == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlInitParserCtxt: out of memory\n");
+    }
+    else
+        memset(sax, 0, sizeof(htmlSAXHandler));
+
+    /* Allocate the Input stack */
+    ctxt->inputTab = (htmlParserInputPtr *) 
+                      xmlMalloc(5 * sizeof(htmlParserInputPtr));
+    if (ctxt->inputTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlInitParserCtxt: out of memory\n");
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	return;
+    }
+    ctxt->inputNr = 0;
+    ctxt->inputMax = 5;
+    ctxt->input = NULL;
+    ctxt->version = NULL;
+    ctxt->encoding = NULL;
+    ctxt->standalone = -1;
+    ctxt->instate = XML_PARSER_START;
+
+    /* Allocate the Node stack */
+    ctxt->nodeTab = (htmlNodePtr *) xmlMalloc(10 * sizeof(htmlNodePtr));
+    if (ctxt->nodeTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlInitParserCtxt: out of memory\n");
+	ctxt->nodeNr = 0;
+	ctxt->nodeMax = 0;
+	ctxt->node = NULL;
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	return;
+    }
+    ctxt->nodeNr = 0;
+    ctxt->nodeMax = 10;
+    ctxt->node = NULL;
+
+    /* Allocate the Name stack */
+    ctxt->nameTab = (xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
+    if (ctxt->nameTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlInitParserCtxt: out of memory\n");
+	ctxt->nameNr = 0;
+	ctxt->nameMax = 10;
+	ctxt->name = NULL;
+	ctxt->nodeNr = 0;
+	ctxt->nodeMax = 0;
+	ctxt->node = NULL;
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	return;
+    }
+    ctxt->nameNr = 0;
+    ctxt->nameMax = 10;
+    ctxt->name = NULL;
+
+    if (sax == NULL) ctxt->sax = &htmlDefaultSAXHandler;
+    else {
+        ctxt->sax = sax;
+	memcpy(sax, &htmlDefaultSAXHandler, sizeof(htmlSAXHandler));
+    }
+    ctxt->userData = ctxt;
+    ctxt->myDoc = NULL;
+    ctxt->wellFormed = 1;
+    ctxt->replaceEntities = 0;
+    ctxt->html = 1;
+    ctxt->record_info = 0;
+    ctxt->validate = 0;
+    ctxt->nbChars = 0;
+    ctxt->checkIndex = 0;
+    xmlInitNodeInfoSeq(&ctxt->node_seq);
+}
+
+/**
+ * htmlFreeParserCtxt:
+ * @ctxt:  an HTML parser context
+ *
+ * Free all the memory used by a parser context. However the parsed
+ * document in ctxt->myDoc is not freed.
+ */
+
+void
+htmlFreeParserCtxt(htmlParserCtxtPtr ctxt)
+{
+    xmlFreeParserCtxt(ctxt);
+}
+
+/**
+ * htmlCreateDocParserCtxt :
+ * @cur:  a pointer to an array of xmlChar
+ * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ *
+ * Create a parser context for an HTML document.
+ *
+ * Returns the new parser context or NULL
+ */
+htmlParserCtxtPtr
+htmlCreateDocParserCtxt(xmlChar *cur, const char *encoding) {
+    htmlParserCtxtPtr ctxt;
+    htmlParserInputPtr input;
+    /* htmlCharEncoding enc; */
+
+    ctxt = (htmlParserCtxtPtr) xmlMalloc(sizeof(htmlParserCtxt));
+    if (ctxt == NULL) {
+        perror("malloc");
+	return(NULL);
+    }
+    htmlInitParserCtxt(ctxt);
+    input = (htmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput));
+    if (input == NULL) {
+        perror("malloc");
+	xmlFree(ctxt);
+	return(NULL);
+    }
+    memset(input, 0, sizeof(htmlParserInput));
+
+    input->line = 1;
+    input->col = 1;
+    input->base = cur;
+    input->cur = cur;
+
+    inputPush(ctxt, input);
+    return(ctxt);
+}
+
+/************************************************************************
+ *									*
+ * 		Progressive parsing interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlParseLookupSequence:
+ * @ctxt:  an HTML parser context
+ * @first:  the first char to lookup
+ * @next:  the next char to lookup or zero
+ * @third:  the next char to lookup or zero
+ *
+ * Try to find if a sequence (first, next, third) or  just (first next) or
+ * (first) is available in the input stream.
+ * This function has a side effect of (possibly) incrementing ctxt->checkIndex
+ * to avoid rescanning sequences of bytes, it DOES change the state of the
+ * parser, do not use liberally.
+ * This is basically similar to xmlParseLookupSequence()
+ *
+ * Returns the index to the current parsing point if the full sequence
+ *      is available, -1 otherwise.
+ */
+int
+htmlParseLookupSequence(htmlParserCtxtPtr ctxt, xmlChar first,
+                       xmlChar next, xmlChar third) {
+    int base, len;
+    htmlParserInputPtr in;
+    const xmlChar *buf;
+
+    in = ctxt->input;
+    if (in == NULL) return(-1);
+    base = in->cur - in->base;
+    if (base < 0) return(-1);
+    if (ctxt->checkIndex > base)
+        base = ctxt->checkIndex;
+    if (in->buf == NULL) {
+	buf = in->base;
+	len = in->length;
+    } else {
+	buf = in->buf->buffer->content;
+	len = in->buf->buffer->use;
+    }
+    /* take into account the sequence length */
+    if (third) len -= 2;
+    else if (next) len --;
+    for (;base < len;base++) {
+        if (buf[base] == first) {
+	    if (third != 0) {
+		if ((buf[base + 1] != next) ||
+		    (buf[base + 2] != third)) continue;
+	    } else if (next != 0) {
+		if (buf[base + 1] != next) continue;
+	    }
+	    ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+	    if (next == 0)
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: lookup '%c' found at %d\n",
+			first, base);
+	    else if (third == 0)
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: lookup '%c%c' found at %d\n",
+			first, next, base);
+	    else 
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: lookup '%c%c%c' found at %d\n",
+			first, next, third, base);
+#endif
+	    return(base - (in->cur - in->base));
+	}
+    }
+    ctxt->checkIndex = base;
+#ifdef DEBUG_PUSH
+    if (next == 0)
+	xmlGenericError(xmlGenericErrorContext,
+		"HPP: lookup '%c' failed\n", first);
+    else if (third == 0)
+	xmlGenericError(xmlGenericErrorContext,
+		"HPP: lookup '%c%c' failed\n", first, next);
+    else	
+	xmlGenericError(xmlGenericErrorContext,
+		"HPP: lookup '%c%c%c' failed\n", first, next, third);
+#endif
+    return(-1);
+}
+
+/**
+ * htmlParseTryOrFinish:
+ * @ctxt:  an HTML parser context
+ * @terminate:  last chunk indicator
+ *
+ * Try to progress on parsing
+ *
+ * Returns zero if no parsing was possible
+ */
+int
+htmlParseTryOrFinish(htmlParserCtxtPtr ctxt, int terminate) {
+    int ret = 0;
+    htmlParserInputPtr in;
+    int avail = 0;
+    xmlChar cur, next;
+
+#ifdef DEBUG_PUSH
+    switch (ctxt->instate) {
+	case XML_PARSER_EOF:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try EOF\n"); break;
+	case XML_PARSER_START:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try START\n"); break;
+	case XML_PARSER_MISC:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try MISC\n");break;
+	case XML_PARSER_COMMENT:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try COMMENT\n");break;
+	case XML_PARSER_PROLOG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try PROLOG\n");break;
+	case XML_PARSER_START_TAG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try START_TAG\n");break;
+	case XML_PARSER_CONTENT:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try CONTENT\n");break;
+	case XML_PARSER_CDATA_SECTION:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try CDATA_SECTION\n");break;
+	case XML_PARSER_END_TAG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try END_TAG\n");break;
+	case XML_PARSER_ENTITY_DECL:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try ENTITY_DECL\n");break;
+	case XML_PARSER_ENTITY_VALUE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try ENTITY_VALUE\n");break;
+	case XML_PARSER_ATTRIBUTE_VALUE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try ATTRIBUTE_VALUE\n");break;
+	case XML_PARSER_DTD:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try DTD\n");break;
+	case XML_PARSER_EPILOG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try EPILOG\n");break;
+	case XML_PARSER_PI:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try PI\n");break;
+	case XML_PARSER_SYSTEM_LITERAL:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "HPP: try SYSTEM_LITERAL\n");break;
+    }
+#endif
+
+    while (1) {
+
+	in = ctxt->input;
+	if (in == NULL) break;
+	if (in->buf == NULL)
+	    avail = in->length - (in->cur - in->base);
+	else
+	    avail = in->buf->buffer->use - (in->cur - in->base);
+	if ((avail == 0) && (terminate)) {
+	    htmlAutoClose(ctxt, NULL);
+	    if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) { 
+		/*
+		 * SAX: end of the document processing.
+		 */
+		ctxt->instate = XML_PARSER_EOF;
+		if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+		    ctxt->sax->endDocument(ctxt->userData);
+	    }
+	}
+        if (avail < 1)
+	    goto done;
+        switch (ctxt->instate) {
+            case XML_PARSER_EOF:
+	        /*
+		 * Document parsing is done !
+		 */
+	        goto done;
+            case XML_PARSER_START:
+	        /*
+		 * Very first chars read from the document flow.
+		 */
+		cur = in->cur[0];
+		if (IS_BLANK(cur)) {
+		    SKIP_BLANKS;
+		    if (in->buf == NULL)
+			avail = in->length - (in->cur - in->base);
+		    else
+			avail = in->buf->buffer->use - (in->cur - in->base);
+		}
+		if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+		    ctxt->sax->setDocumentLocator(ctxt->userData,
+						  &xmlDefaultSAXLocator);
+		if ((ctxt->sax) && (ctxt->sax->startDocument) &&
+	            (!ctxt->disableSAX))
+		    ctxt->sax->startDocument(ctxt->userData);
+
+		cur = in->cur[0];
+		next = in->cur[1];
+		if ((cur == '<') && (next == '!') &&
+		    (UPP(2) == 'D') && (UPP(3) == 'O') &&
+		    (UPP(4) == 'C') && (UPP(5) == 'T') &&
+		    (UPP(6) == 'Y') && (UPP(7) == 'P') &&
+		    (UPP(8) == 'E')) {
+		    if ((!terminate) &&
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: Parsing internal subset\n");
+#endif
+		    htmlParseDocTypeDecl(ctxt);
+		    ctxt->instate = XML_PARSER_PROLOG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering PROLOG\n");
+#endif
+                } else {
+		    ctxt->instate = XML_PARSER_MISC;
+		}
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering MISC\n");
+#endif
+		break;
+            case XML_PARSER_MISC:
+		SKIP_BLANKS;
+		if (in->buf == NULL)
+		    avail = in->length - (in->cur - in->base);
+		else
+		    avail = in->buf->buffer->use - (in->cur - in->base);
+		if (avail < 2)
+		    goto done;
+		cur = in->cur[0];
+		next = in->cur[1];
+	        if ((cur == '<') && (next == '!') &&
+		    (in->cur[2] == '-') && (in->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (htmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: Parsing Comment\n");
+#endif
+		    htmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_MISC;
+		} else if ((cur == '<') && (next == '!') &&
+		    (UPP(2) == 'D') && (UPP(3) == 'O') &&
+		    (UPP(4) == 'C') && (UPP(5) == 'T') &&
+		    (UPP(6) == 'Y') && (UPP(7) == 'P') &&
+		    (UPP(8) == 'E')) {
+		    if ((!terminate) &&
+		        (htmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: Parsing internal subset\n");
+#endif
+		    htmlParseDocTypeDecl(ctxt);
+		    ctxt->instate = XML_PARSER_PROLOG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering PROLOG\n");
+#endif
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 9)) {
+		    goto done;
+		} else {
+		    ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering START_TAG\n");
+#endif
+		}
+		break;
+            case XML_PARSER_PROLOG:
+		SKIP_BLANKS;
+		if (in->buf == NULL)
+		    avail = in->length - (in->cur - in->base);
+		else
+		    avail = in->buf->buffer->use - (in->cur - in->base);
+		if (avail < 2) 
+		    goto done;
+		cur = in->cur[0];
+		next = in->cur[1];
+		if ((cur == '<') && (next == '!') &&
+		    (in->cur[2] == '-') && (in->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (htmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: Parsing Comment\n");
+#endif
+		    htmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_PROLOG;
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 4)) {
+		    goto done;
+		} else {
+		    ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering START_TAG\n");
+#endif
+		}
+		break;
+            case XML_PARSER_EPILOG:
+		if (in->buf == NULL)
+		    avail = in->length - (in->cur - in->base);
+		else
+		    avail = in->buf->buffer->use - (in->cur - in->base);
+		if (avail < 1)
+		    goto done;
+		cur = in->cur[0];
+		if (IS_BLANK(cur)) {
+		    htmlParseCharData(ctxt, 0);
+		    goto done;
+		}
+		if (avail < 2)
+		    goto done;
+		next = in->cur[1];
+	        if ((cur == '<') && (next == '!') &&
+		    (in->cur[2] == '-') && (in->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (htmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: Parsing Comment\n");
+#endif
+		    htmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_EPILOG;
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 4)) {
+		    goto done;
+		} else {
+		    ctxt->errNo = XML_ERR_DOCUMENT_END;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			    "Extra content at the end of the document\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering EOF\n");
+#endif
+		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+			ctxt->sax->endDocument(ctxt->userData);
+		    goto done;
+		}
+		break;
+            case XML_PARSER_START_TAG: {
+	        xmlChar *name, *oldname;
+		int depth = ctxt->nameNr;
+		htmlElemDescPtr info;
+
+		if (avail < 2)
+		    goto done;
+		cur = in->cur[0];
+	        if (cur != '<') {
+		    ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering CONTENT\n");
+#endif
+		    break;
+		}
+		if ((!terminate) &&
+		    (htmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+		    goto done;
+
+		oldname = xmlStrdup(ctxt->name);
+		htmlParseStartTag(ctxt);
+		name = ctxt->name;
+#ifdef DEBUG
+		if (oldname == NULL)
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Start of element %s\n", name);
+		else if (name == NULL)	
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Start of element failed, was %s\n",
+		            oldname);
+		else	
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Start of element %s, was %s\n",
+		            name, oldname);
+#endif
+		if (((depth == ctxt->nameNr) &&
+		     (xmlStrEqual(oldname, ctxt->name))) ||
+		    (name == NULL)) {
+		    if (CUR == '>')
+			NEXT;
+		    if (oldname != NULL)
+			xmlFree(oldname);
+		    break;
+		}
+		if (oldname != NULL)
+		    xmlFree(oldname);
+
+		/*
+		 * Lookup the info for that element.
+		 */
+		info = htmlTagLookup(name);
+		if (info == NULL) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, "Tag %s invalid\n",
+					 name);
+		    ctxt->wellFormed = 0;
+		} else if (info->depr) {
+		    /***************************
+		    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			ctxt->sax->warning(ctxt->userData,
+			                   "Tag %s is deprecated\n",
+					   name);
+		     ***************************/
+		}
+
+		/*
+		 * Check for an Empty Element labelled the XML/SGML way
+		 */
+		if ((CUR == '/') && (NXT(1) == '>')) {
+		    SKIP(2);
+		    if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+			ctxt->sax->endElement(ctxt->userData, name);
+		    oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+		    xmlGenericError(xmlGenericErrorContext,"End of tag the XML way: popping out %s\n",
+		            oldname);
+#endif
+		    if (oldname != NULL)
+			xmlFree(oldname);
+		    ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering CONTENT\n");
+#endif
+		    break;
+		}
+
+		if (CUR == '>') {
+		    NEXT;
+		} else {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+			                 "Couldn't find end of Start Tag %s\n",
+					 name);
+		    ctxt->wellFormed = 0;
+
+		    /*
+		     * end of parsing of this node.
+		     */
+		    if (xmlStrEqual(name, ctxt->name)) { 
+			nodePop(ctxt);
+			oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+			xmlGenericError(xmlGenericErrorContext,
+			 "End of start tag problem: popping out %s\n", oldname);
+#endif
+			if (oldname != NULL)
+			    xmlFree(oldname);
+		    }    
+
+		    ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "HPP: entering CONTENT\n");
+#endif
+		    break;
+		}
+
+		/*
+		 * Check for an Empty Element from DTD definition
+		 */
+		if ((info != NULL) && (info->empty)) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL))
+			ctxt->sax->endElement(ctxt->userData, name);
+		    oldname = htmlnamePop(ctxt);
+#ifdef DEBUG
+		    xmlGenericError(xmlGenericErrorContext,"End of empty tag %s : popping out %s\n", name, oldname);
+#endif
+		    if (oldname != NULL)
+			xmlFree(oldname);
+		}
+		ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+                break;
+	    }
+            case XML_PARSER_CONTENT: {
+		long cons;
+                /*
+		 * Handle preparsed entities and charRef
+		 */
+		if (ctxt->token != 0) {
+		    xmlChar chr[2] = { 0 , 0 } ;
+
+		    chr[0] = (xmlChar) ctxt->token;
+		    htmlCheckParagraph(ctxt);
+		    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL))
+			ctxt->sax->characters(ctxt->userData, chr, 1);
+		    ctxt->token = 0;
+		    ctxt->checkIndex = 0;
+		}
+		if ((avail == 1) && (terminate)) {
+		    cur = in->cur[0];
+		    if ((cur != '<') && (cur != '&')) {
+			if (ctxt->sax != NULL) {
+			    if (IS_BLANK(cur)) {
+				if (ctxt->sax->ignorableWhitespace != NULL)
+				    ctxt->sax->ignorableWhitespace(
+					    ctxt->userData, &cur, 1);
+			    } else {
+				htmlCheckParagraph(ctxt);
+				if (ctxt->sax->characters != NULL)
+				    ctxt->sax->characters(
+					    ctxt->userData, &cur, 1);
+			    }
+			}
+			ctxt->token = 0;
+			ctxt->checkIndex = 0;
+			NEXT;
+		    }
+		    break;
+		}
+		if (avail < 2)
+		    goto done;
+		cur = in->cur[0];
+		next = in->cur[1];
+		cons = ctxt->nbChars;
+		if ((xmlStrEqual(ctxt->name, BAD_CAST"script")) ||
+		    (xmlStrEqual(ctxt->name, BAD_CAST"style"))) {
+		    /*
+		     * Handle SCRIPT/STYLE separately
+		     */
+		    if ((!terminate) &&
+		        (htmlParseLookupSequence(ctxt, '<', '/', 0) < 0))
+			goto done;
+		    htmlParseScript(ctxt);
+		    if ((cur == '<') && (next == '/')) {
+			ctxt->instate = XML_PARSER_END_TAG;
+			ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"HPP: entering END_TAG\n");
+#endif
+			break;
+		    }
+		} else {
+		    /*
+		     * Sometimes DOCTYPE arrives in the middle of the document
+		     */
+		    if ((cur == '<') && (next == '!') &&
+			(UPP(2) == 'D') && (UPP(3) == 'O') &&
+			(UPP(4) == 'C') && (UPP(5) == 'T') &&
+			(UPP(6) == 'Y') && (UPP(7) == 'P') &&
+			(UPP(8) == 'E')) {
+			if ((!terminate) &&
+			    (htmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+			    goto done;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				 "Misplaced DOCTYPE declaration\n");
+			ctxt->wellFormed = 0;
+			htmlParseDocTypeDecl(ctxt);
+		    } else if ((cur == '<') && (next == '!') &&
+			(in->cur[2] == '-') && (in->cur[3] == '-')) {
+			if ((!terminate) &&
+			    (htmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			    goto done;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"HPP: Parsing Comment\n");
+#endif
+			htmlParseComment(ctxt);
+			ctxt->instate = XML_PARSER_CONTENT;
+		    } else if ((cur == '<') && (next == '!') && (avail < 4)) {
+			goto done;
+		    } else if ((cur == '<') && (next == '/')) {
+			ctxt->instate = XML_PARSER_END_TAG;
+			ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"HPP: entering END_TAG\n");
+#endif
+			break;
+		    } else if (cur == '<') {
+			ctxt->instate = XML_PARSER_START_TAG;
+			ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"HPP: entering START_TAG\n");
+#endif
+			break;
+		    } else if (cur == '&') {
+			if ((!terminate) &&
+			    (htmlParseLookupSequence(ctxt, ';', 0, 0) < 0))
+			    goto done;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"HPP: Parsing Reference\n");
+#endif
+			/* TODO: check generation of subtrees if noent !!! */
+			htmlParseReference(ctxt);
+		    } else {
+			/* TODO Avoid the extra copy, handle directly !!!!!! */
+			/*
+			 * Goal of the following test is :
+			 *  - minimize calls to the SAX 'character' callback
+			 *    when they are mergeable
+			 */
+			if ((ctxt->inputNr == 1) &&
+			    (avail < HTML_PARSER_BIG_BUFFER_SIZE)) {
+			    if ((!terminate) &&
+				(htmlParseLookupSequence(ctxt, '<', 0, 0) < 0))
+				goto done;
+			}
+			ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"HPP: Parsing char data\n");
+#endif
+			htmlParseCharData(ctxt, 0);
+		    }
+		}
+		if (cons == ctxt->nbChars) {
+		    if (ctxt->node != NULL) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				 "detected an error in element content\n");
+			ctxt->wellFormed = 0;
+		    }
+		    NEXT;
+		    break;
+		}
+
+		break;
+	    }
+            case XML_PARSER_END_TAG:
+		if (avail < 2)
+		    goto done;
+		if ((!terminate) &&
+		    (htmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+		    goto done;
+		htmlParseEndTag(ctxt);
+		if (ctxt->nameNr == 0) {
+		    ctxt->instate = XML_PARSER_EPILOG;
+		} else {
+		    ctxt->instate = XML_PARSER_CONTENT;
+		}
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+	        break;
+            case XML_PARSER_CDATA_SECTION:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == CDATA\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_DTD:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == DTD\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_COMMENT:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == COMMENT\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_PI:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == PI\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_ENTITY_DECL:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == ENTITY_DECL\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_ENTITY_VALUE:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == ENTITY_VALUE\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering DTD\n");
+#endif
+		break;
+            case XML_PARSER_ATTRIBUTE_VALUE:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == ATTRIBUTE_VALUE\n");
+		ctxt->instate = XML_PARSER_START_TAG;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering START_TAG\n");
+#endif
+		break;
+	    case XML_PARSER_SYSTEM_LITERAL:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == XML_PARSER_SYSTEM_LITERAL\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+	    case XML_PARSER_IGNORE:
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: internal error, state == XML_PARSER_IGNORE\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"HPP: entering CONTENT\n");
+#endif
+		break;
+	}
+    }
+done:    
+    if ((avail == 0) && (terminate)) {
+	htmlAutoClose(ctxt, NULL);
+	if ((ctxt->nameNr == 0) && (ctxt->instate != XML_PARSER_EOF)) { 
+	    /*
+	     * SAX: end of the document processing.
+	     */
+	    ctxt->instate = XML_PARSER_EOF;
+	    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+		ctxt->sax->endDocument(ctxt->userData);
+	}
+    }
+    if ((ctxt->myDoc != NULL) &&
+	((terminate) || (ctxt->instate == XML_PARSER_EOF) ||
+	 (ctxt->instate == XML_PARSER_EPILOG))) {
+	xmlDtdPtr dtd;
+	dtd = xmlGetIntSubset(ctxt->myDoc);
+	if (dtd == NULL)
+	    ctxt->myDoc->intSubset = 
+		xmlCreateIntSubset(ctxt->myDoc, BAD_CAST "HTML", 
+		    BAD_CAST "-//W3C//DTD HTML 4.0 Transitional//EN",
+		    BAD_CAST "http://www.w3.org/TR/REC-html40/loose.dtd");
+    }
+#ifdef DEBUG_PUSH
+    xmlGenericError(xmlGenericErrorContext, "HPP: done %d\n", ret);
+#endif
+    return(ret);
+}
+
+/**
+ * htmlParseTry:
+ * @ctxt:  an HTML parser context
+ *
+ * Try to progress on parsing
+ *
+ * Returns zero if no parsing was possible
+ */
+int
+htmlParseTry(htmlParserCtxtPtr ctxt) {
+    return(htmlParseTryOrFinish(ctxt, 0));
+}
+
+/**
+ * htmlParseChunk:
+ * @ctxt:  an XML parser context
+ * @chunk:  an char array
+ * @size:  the size in byte of the chunk
+ * @terminate:  last chunk indicator
+ *
+ * Parse a Chunk of memory
+ *
+ * Returns zero if no error, the xmlParserErrors otherwise.
+ */
+int
+htmlParseChunk(htmlParserCtxtPtr ctxt, const char *chunk, int size,
+              int terminate) {
+    if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
+        (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF))  {
+	int base = ctxt->input->base - ctxt->input->buf->buffer->content;
+	int cur = ctxt->input->cur - ctxt->input->base;
+	
+	xmlParserInputBufferPush(ctxt->input->buf, size, chunk);	      
+	ctxt->input->base = ctxt->input->buf->buffer->content + base;
+	ctxt->input->cur = ctxt->input->base + cur;
+#ifdef DEBUG_PUSH
+	xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
+#endif
+
+	if ((terminate) || (ctxt->input->buf->buffer->use > 80))
+	    htmlParseTryOrFinish(ctxt, terminate);
+    } else if (ctxt->instate != XML_PARSER_EOF) {
+	xmlParserInputBufferPush(ctxt->input->buf, 0, "");
+        htmlParseTryOrFinish(ctxt, terminate);
+    }
+    if (terminate) {
+	if ((ctxt->instate != XML_PARSER_EOF) &&
+	    (ctxt->instate != XML_PARSER_EPILOG) &&
+	    (ctxt->instate != XML_PARSER_MISC)) {
+	    ctxt->errNo = XML_ERR_DOCUMENT_END;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Extra content at the end of the document\n");
+	    ctxt->wellFormed = 0;
+	} 
+	if (ctxt->instate != XML_PARSER_EOF) {
+	    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+		ctxt->sax->endDocument(ctxt->userData);
+	}
+	ctxt->instate = XML_PARSER_EOF;
+    }
+    return((xmlParserErrors) ctxt->errNo);	      
+}
+
+/************************************************************************
+ *									*
+ *			User entry points				*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlCreatePushParserCtxt :
+ * @sax:  a SAX handler
+ * @user_data:  The user data returned on SAX callbacks
+ * @chunk:  a pointer to an array of chars
+ * @size:  number of chars in the array
+ * @filename:  an optional file name or URI
+ * @enc:  an optional encoding
+ *
+ * Create a parser context for using the HTML parser in push mode
+ * To allow content encoding detection, @size should be >= 4
+ * The value of @filename is used for fetching external entities
+ * and error/warning reports.
+ *
+ * Returns the new parser context or NULL
+ */
+htmlParserCtxtPtr
+htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax, void *user_data, 
+                         const char *chunk, int size, const char *filename,
+			 xmlCharEncoding enc) {
+    htmlParserCtxtPtr ctxt;
+    htmlParserInputPtr inputStream;
+    xmlParserInputBufferPtr buf;
+
+    buf = xmlAllocParserInputBuffer(enc);
+    if (buf == NULL) return(NULL);
+
+    ctxt = (htmlParserCtxtPtr) xmlMalloc(sizeof(htmlParserCtxt));
+    if (ctxt == NULL) {
+	xmlFree(buf);
+	return(NULL);
+    }
+    memset(ctxt, 0, sizeof(htmlParserCtxt));
+    htmlInitParserCtxt(ctxt);
+    if (sax != NULL) {
+	if (ctxt->sax != &htmlDefaultSAXHandler)
+	    xmlFree(ctxt->sax);
+	ctxt->sax = (htmlSAXHandlerPtr) xmlMalloc(sizeof(htmlSAXHandler));
+	if (ctxt->sax == NULL) {
+	    xmlFree(buf);
+	    xmlFree(ctxt);
+	    return(NULL);
+	}
+	memcpy(ctxt->sax, sax, sizeof(htmlSAXHandler));
+	if (user_data != NULL)
+	    ctxt->userData = user_data;
+    }	
+    if (filename == NULL) {
+	ctxt->directory = NULL;
+    } else {
+        ctxt->directory = xmlParserGetDirectory(filename);
+    }
+
+    inputStream = htmlNewInputStream(ctxt);
+    if (inputStream == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+
+    if (filename == NULL)
+	inputStream->filename = NULL;
+    else
+	inputStream->filename = xmlMemStrdup(filename);
+    inputStream->buf = buf;
+    inputStream->base = inputStream->buf->buffer->content;
+    inputStream->cur = inputStream->buf->buffer->content;
+
+    inputPush(ctxt, inputStream);
+
+    if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
+        (ctxt->input->buf != NULL))  {	      
+	xmlParserInputBufferPush(ctxt->input->buf, size, chunk);	      
+#ifdef DEBUG_PUSH
+	xmlGenericError(xmlGenericErrorContext, "HPP: pushed %d\n", size);
+#endif
+    }
+
+    return(ctxt);
+}
+
+/**
+ * htmlSAXParseDoc :
+ * @cur:  a pointer to an array of xmlChar
+ * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @sax:  the SAX handler block
+ * @userData: if using SAX, this pointer will be provided on callbacks. 
+ *
+ * parse an HTML in-memory document and build a tree.
+ * It use the given SAX function block to handle the parsing callback.
+ * If sax is NULL, fallback to the default DOM tree building routines.
+ * 
+ * Returns the resulting document tree
+ */
+
+htmlDocPtr
+htmlSAXParseDoc(xmlChar *cur, const char *encoding, htmlSAXHandlerPtr sax, void *userData) {
+    htmlDocPtr ret;
+    htmlParserCtxtPtr ctxt;
+
+    if (cur == NULL) return(NULL);
+
+
+    ctxt = htmlCreateDocParserCtxt(cur, encoding);
+    if (ctxt == NULL) return(NULL);
+    if (sax != NULL) { 
+        ctxt->sax = sax;
+        ctxt->userData = userData;
+    }
+
+    htmlParseDocument(ctxt);
+    ret = ctxt->myDoc;
+    if (sax != NULL) {
+	ctxt->sax = NULL;
+	ctxt->userData = NULL;
+    }
+    htmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * htmlParseDoc :
+ * @cur:  a pointer to an array of xmlChar
+ * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ *
+ * parse an HTML in-memory document and build a tree.
+ * 
+ * Returns the resulting document tree
+ */
+
+htmlDocPtr
+htmlParseDoc(xmlChar *cur, const char *encoding) {
+    return(htmlSAXParseDoc(cur, encoding, NULL, NULL));
+}
+
+
+/**
+ * htmlCreateFileParserCtxt :
+ * @filename:  the filename
+ * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ *
+ * Create a parser context for a file content. 
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ *
+ * Returns the new parser context or NULL
+ */
+htmlParserCtxtPtr
+htmlCreateFileParserCtxt(const char *filename, const char *encoding)
+{
+    htmlParserCtxtPtr ctxt;
+    htmlParserInputPtr inputStream;
+    xmlParserInputBufferPtr buf;
+    /* htmlCharEncoding enc; */
+    xmlChar *content, *content_line = (xmlChar *) "charset=";
+
+    buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) return(NULL);
+
+    ctxt = (htmlParserCtxtPtr) xmlMalloc(sizeof(htmlParserCtxt));
+    if (ctxt == NULL) {
+        perror("malloc");
+	return(NULL);
+    }
+    memset(ctxt, 0, sizeof(htmlParserCtxt));
+    htmlInitParserCtxt(ctxt);
+    inputStream = (htmlParserInputPtr) xmlMalloc(sizeof(htmlParserInput));
+    if (inputStream == NULL) {
+        perror("malloc");
+	xmlFree(ctxt);
+	return(NULL);
+    }
+    memset(inputStream, 0, sizeof(htmlParserInput));
+
+    inputStream->filename = xmlMemStrdup(filename);
+    inputStream->line = 1;
+    inputStream->col = 1;
+    inputStream->buf = buf;
+    inputStream->directory = NULL;
+
+    inputStream->base = inputStream->buf->buffer->content;
+    inputStream->cur = inputStream->buf->buffer->content;
+    inputStream->free = NULL;
+
+    inputPush(ctxt, inputStream);
+    
+    /* set encoding */
+    if (encoding) {
+        content = xmlMalloc (xmlStrlen(content_line) + strlen(encoding) + 1);
+	if (content) {  
+	    strcpy ((char *)content, (char *)content_line);
+            strcat ((char *)content, (char *)encoding);
+            htmlCheckEncoding (ctxt, content);
+	    xmlFree (content);
+	}
+    }
+    
+    return(ctxt);
+}
+
+/**
+ * htmlSAXParseFile :
+ * @filename:  the filename
+ * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ * @sax:  the SAX handler block
+ * @userData: if using SAX, this pointer will be provided on callbacks. 
+ *
+ * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
+ * compressed document is provided by default if found at compile-time.
+ * It use the given SAX function block to handle the parsing callback.
+ * If sax is NULL, fallback to the default DOM tree building routines.
+ *
+ * Returns the resulting document tree
+ */
+
+htmlDocPtr
+htmlSAXParseFile(const char *filename, const char *encoding, htmlSAXHandlerPtr sax, 
+                 void *userData) {
+    htmlDocPtr ret;
+    htmlParserCtxtPtr ctxt;
+    htmlSAXHandlerPtr oldsax = NULL;
+
+    ctxt = htmlCreateFileParserCtxt(filename, encoding);
+    if (ctxt == NULL) return(NULL);
+    if (sax != NULL) {
+	oldsax = ctxt->sax;
+        ctxt->sax = sax;
+        ctxt->userData = userData;
+    }
+
+    htmlParseDocument(ctxt);
+
+    ret = ctxt->myDoc;
+    if (sax != NULL) {
+        ctxt->sax = oldsax;
+        ctxt->userData = NULL;
+    }
+    htmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * htmlParseFile :
+ * @filename:  the filename
+ * @encoding:  a free form C string describing the HTML document encoding, or NULL
+ *
+ * parse an HTML file and build a tree. Automatic support for ZLIB/Compress
+ * compressed document is provided by default if found at compile-time.
+ *
+ * Returns the resulting document tree
+ */
+
+htmlDocPtr
+htmlParseFile(const char *filename, const char *encoding) {
+    return(htmlSAXParseFile(filename, encoding, NULL, NULL));
+}
+
+/**
+ * htmlHandleOmittedElem:
+ * @val:  int 0 or 1 
+ *
+ * Set and return the previous value for handling HTML omitted tags.
+ *
+ * Returns the last value for 0 for no handling, 1 for auto insertion.
+ */
+
+int
+htmlHandleOmittedElem(int val) {
+    int old = htmlOmittedDefaultValue;
+
+    htmlOmittedDefaultValue = val;
+    return(old);
+}
+
+#endif /* LIBXML_HTML_ENABLED */
diff --git a/HTMLparser.h b/HTMLparser.h
new file mode 100644
index 0000000..c79ad09
--- /dev/null
+++ b/HTMLparser.h
@@ -0,0 +1,115 @@
+/*
+ * HTMLparser.h : inf=terface for an HTML 4.0 non-verifying parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __HTML_PARSER_H__
+#define __HTML_PARSER_H__
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Most of the back-end structures from XML and HTML are shared
+ */
+typedef xmlParserCtxt htmlParserCtxt;
+typedef xmlParserCtxtPtr htmlParserCtxtPtr;
+typedef xmlParserNodeInfo htmlParserNodeInfo;
+typedef xmlSAXHandler htmlSAXHandler;
+typedef xmlSAXHandlerPtr htmlSAXHandlerPtr;
+typedef xmlParserInput htmlParserInput;
+typedef xmlParserInputPtr htmlParserInputPtr;
+typedef xmlDocPtr htmlDocPtr;
+typedef xmlNodePtr htmlNodePtr;
+
+/*
+ * Internal description of an HTML element
+ */
+typedef struct _htmlElemDesc htmlElemDesc;
+typedef htmlElemDesc *htmlElemDescPtr;
+struct _htmlElemDesc {
+    const char *name;	/* The tag name */
+    char startTag;       /* Whether the start tag can be implied */
+    char endTag;         /* Whether the end tag can be implied */
+    char saveEndTag;     /* Whether the end tag should be saved */
+    char empty;          /* Is this an empty element ? */
+    char depr;           /* Is this a deprecated element ? */
+    char dtd;            /* 1: only in Loose DTD, 2: only Frameset one */
+    const char *desc;   /* the description */
+};
+
+/*
+ * Internal description of an HTML entity
+ */
+typedef struct _htmlEntityDesc htmlEntityDesc;
+typedef htmlEntityDesc *htmlEntityDescPtr;
+struct _htmlEntityDesc {
+    int value;		/* the UNICODE value for the character */
+    const char *name;	/* The entity name */
+    const char *desc;   /* the description */
+};
+
+/*
+ * There is only few public functions.
+ */
+htmlElemDescPtr		htmlTagLookup	(const xmlChar *tag);
+htmlEntityDescPtr	htmlEntityLookup(const xmlChar *name);
+htmlEntityDescPtr	htmlEntityValueLookup(int value);
+
+int			htmlIsAutoClosed(htmlDocPtr doc,
+					 htmlNodePtr elem);
+int			htmlAutoCloseTag(htmlDocPtr doc,
+					 const xmlChar *name,
+					 htmlNodePtr elem);
+htmlEntityDescPtr	htmlParseEntityRef(htmlParserCtxtPtr ctxt,
+					 xmlChar **str);
+int			htmlParseCharRef(htmlParserCtxtPtr ctxt);
+void			htmlParseElement(htmlParserCtxtPtr ctxt);
+
+htmlDocPtr		htmlSAXParseDoc	(xmlChar *cur,
+					 const char *encoding,
+					 htmlSAXHandlerPtr sax,
+					 void *userData);
+htmlDocPtr		htmlParseDoc	(xmlChar *cur,
+					 const char *encoding);
+htmlDocPtr		htmlSAXParseFile(const char *filename,
+					 const char *encoding,
+					 htmlSAXHandlerPtr sax,
+					 void *userData);
+htmlDocPtr		htmlParseFile	(const char *filename,
+					 const char *encoding);
+int			UTF8ToHtml	(unsigned char* out,
+					 int *outlen,
+					 const unsigned char* in,
+					 int *inlen);
+int			htmlEncodeEntities(unsigned char* out,
+					 int *outlen,
+					 const unsigned char* in,
+					 int *inlen, int quoteChar);
+int			htmlIsScriptAttribute(const xmlChar *name);
+int			htmlHandleOmittedElem(int val);
+
+/**
+ * Interfaces for the Push mode
+ */
+void			htmlFreeParserCtxt	(htmlParserCtxtPtr ctxt);
+htmlParserCtxtPtr	htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax,
+						 void *user_data,
+						 const char *chunk,
+						 int size,
+						 const char *filename,
+						 xmlCharEncoding enc);
+int			htmlParseChunk		(htmlParserCtxtPtr ctxt,
+						 const char *chunk,
+						 int size,
+						 int terminate);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HTML_PARSER_H__ */
diff --git a/HTMLtree.c b/HTMLtree.c
new file mode 100644
index 0000000..8c6354a
--- /dev/null
+++ b/HTMLtree.c
@@ -0,0 +1,1155 @@
+/*
+ * HTMLtree.c : implemetation of access function for an HTML tree.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_HTML_ENABLED
+
+#include <stdio.h>
+#include <string.h> /* for memset() only ! */
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/HTMLparser.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/entities.h>
+#include <libxml/valid.h>
+#include <libxml/xmlerror.h>
+#include <libxml/parserInternals.h>
+
+/************************************************************************
+ *									*
+ *   		Getting/Setting encoding meta tags			*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlGetMetaEncoding:
+ * @doc:  the document
+ * 
+ * Encoding definition lookup in the Meta tags
+ *
+ * Returns the current encoding as flagged in the HTML source
+ */
+const xmlChar *
+htmlGetMetaEncoding(htmlDocPtr doc) {
+    htmlNodePtr cur;
+    const xmlChar *content;
+    const xmlChar *encoding;
+
+    if (doc == NULL)
+	return(NULL);
+    cur = doc->children;
+
+    /*
+     * Search the html
+     */
+    while (cur != NULL) {
+	if (cur->name != NULL) {
+	    if (xmlStrEqual(cur->name, BAD_CAST"html"))
+		break;
+	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
+		goto found_head;
+	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
+		goto found_meta;
+	}
+	cur = cur->next;
+    }
+    if (cur == NULL)
+	return(NULL);
+    cur = cur->children;
+
+    /*
+     * Search the head
+     */
+    while (cur != NULL) {
+	if (cur->name != NULL) {
+	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
+		break;
+	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
+		goto found_meta;
+	}
+	cur = cur->next;
+    }
+    if (cur == NULL)
+	return(NULL);
+found_head:
+    cur = cur->children;
+
+    /*
+     * Search the meta elements
+     */
+found_meta:
+    while (cur != NULL) {
+	if (cur->name != NULL) {
+	    if (xmlStrEqual(cur->name, BAD_CAST"meta")) {
+		xmlAttrPtr attr = cur->properties;
+		int http;
+		const xmlChar *value;
+
+		content = NULL;
+		http = 0;
+		while (attr != NULL) {
+		    if ((attr->children != NULL) &&
+		        (attr->children->type == XML_TEXT_NODE) &&
+		        (attr->children->next == NULL)) {
+#ifndef XML_USE_BUFFER_CONTENT
+			value = attr->children->content;
+#else
+			value = xmlBufferContent(attr->children->content);
+#endif
+			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
+			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
+			    http = 1;
+			else if ((value != NULL)
+			 && (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
+			    content = value;
+			if ((http != 0) && (content != NULL))
+			    goto found_content;
+		    }
+		    attr = attr->next;
+		}
+	    }
+	}
+	cur = cur->next;
+    }
+    return(NULL);
+
+found_content:
+    encoding = xmlStrstr(content, BAD_CAST"charset=");
+    if (encoding == NULL) 
+	encoding = xmlStrstr(content, BAD_CAST"Charset=");
+    if (encoding == NULL) 
+	encoding = xmlStrstr(content, BAD_CAST"CHARSET=");
+    if (encoding != NULL) {
+	encoding += 8;
+    } else {
+	encoding = xmlStrstr(content, BAD_CAST"charset =");
+	if (encoding == NULL) 
+	    encoding = xmlStrstr(content, BAD_CAST"Charset =");
+	if (encoding == NULL) 
+	    encoding = xmlStrstr(content, BAD_CAST"CHARSET =");
+	if (encoding != NULL)
+	    encoding += 9;
+    }
+    if (encoding != NULL) {
+	while ((*encoding == ' ') || (*encoding == '\t')) encoding++;
+    }
+    return(encoding);
+}
+
+/**
+ * htmlSetMetaEncoding:
+ * @doc:  the document
+ * @encoding:  the encoding string
+ * 
+ * Sets the current encoding in the Meta tags
+ * NOTE: this will not change the document content encoding, just
+ * the META flag associated.
+ *
+ * Returns 0 in case of success and -1 in case of error
+ */
+int
+htmlSetMetaEncoding(htmlDocPtr doc, const xmlChar *encoding) {
+    htmlNodePtr cur, meta;
+    const xmlChar *content;
+    char newcontent[100];
+
+
+    if (doc == NULL)
+	return(-1);
+
+    if (encoding != NULL) {
+#ifdef HAVE_SNPRINTF
+	snprintf(newcontent, sizeof(newcontent), "text/html; charset=%s",
+                encoding);
+#else
+	sprintf(newcontent, "text/html; charset=%s", encoding);
+#endif
+	newcontent[sizeof(newcontent) - 1] = 0;
+    }
+
+    cur = doc->children;
+
+    /*
+     * Search the html
+     */
+    while (cur != NULL) {
+	if (cur->name != NULL) {
+	    if (xmlStrEqual(cur->name, BAD_CAST"html"))
+		break;
+	    if (xmlStrEqual(cur->name, BAD_CAST"body")) {
+		if (encoding == NULL)
+		    return(0);
+		meta = xmlNewDocNode(doc, NULL, BAD_CAST"head", NULL);
+		xmlAddPrevSibling(cur, meta);
+		cur = meta;
+		meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
+		xmlAddChild(cur, meta);
+		xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
+		xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
+		return(0);
+	    }
+	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
+		goto found_head;
+	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
+		goto found_meta;
+	}
+	cur = cur->next;
+    }
+    if (cur == NULL)
+	return(-1);
+    cur = cur->children;
+
+    /*
+     * Search the head
+     */
+    while (cur != NULL) {
+	if (cur->name != NULL) {
+	    if (xmlStrEqual(cur->name, BAD_CAST"head"))
+		break;
+	    if (xmlStrEqual(cur->name, BAD_CAST"body")) {
+		if (encoding == NULL)
+		    return(0);
+		meta = xmlNewDocNode(doc, NULL, BAD_CAST"head", NULL);
+		xmlAddPrevSibling(cur, meta);
+		cur = meta;
+		meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
+		xmlAddChild(cur, meta);
+		xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
+		xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
+		return(0);
+	    }
+	    if (xmlStrEqual(cur->name, BAD_CAST"meta"))
+		goto found_meta;
+	}
+	cur = cur->next;
+    }
+    if (cur == NULL)
+	return(-1);
+found_head:
+    if (cur->children == NULL) {
+	if (encoding == NULL)
+	    return(0);
+	meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
+	xmlAddChild(cur, meta);
+	xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
+	xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
+	return(0);
+    }
+    cur = cur->children;
+
+found_meta:
+    if (encoding != NULL) {
+	/*
+	 * Create a new Meta element with the right aatributes
+	 */
+
+	meta = xmlNewDocNode(doc, NULL, BAD_CAST"meta", NULL);
+	xmlAddPrevSibling(cur, meta);
+	xmlNewProp(meta, BAD_CAST"http-equiv", BAD_CAST"Content-Type");
+	xmlNewProp(meta, BAD_CAST"content", BAD_CAST newcontent);
+    }
+
+    /*
+     * Search and destroy all the remaining the meta elements carrying
+     * encoding informations
+     */
+    while (cur != NULL) {
+	if (cur->name != NULL) {
+	    if (xmlStrEqual(cur->name, BAD_CAST"meta")) {
+		xmlAttrPtr attr = cur->properties;
+		int http;
+		const xmlChar *value;
+
+		content = NULL;
+		http = 0;
+		while (attr != NULL) {
+		    if ((attr->children != NULL) &&
+		        (attr->children->type == XML_TEXT_NODE) &&
+		        (attr->children->next == NULL)) {
+#ifndef XML_USE_BUFFER_CONTENT
+			value = attr->children->content;
+#else
+			value = xmlBufferContent(attr->children->content);
+#endif
+			if ((!xmlStrcasecmp(attr->name, BAD_CAST"http-equiv"))
+			 && (!xmlStrcasecmp(value, BAD_CAST"Content-Type")))
+			    http = 1;
+			else if ((value != NULL)
+			 && (!xmlStrcasecmp(attr->name, BAD_CAST"content")))
+			    content = value;
+			if ((http != 0) && (content != NULL))
+			    break;
+		    }
+		    attr = attr->next;
+		}
+		if ((http != 0) && (content != NULL)) {
+		    meta = cur;
+		    cur = cur->next;
+		    xmlUnlinkNode(meta);
+                    xmlFreeNode(meta);
+		    continue;
+		}
+
+	    }
+	}
+	cur = cur->next;
+    }
+    return(0);
+}
+
+/************************************************************************
+ *									*
+ *   		Dumping HTML tree content to a simple buffer		*
+ *									*
+ ************************************************************************/
+
+static void
+htmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur);
+
+/**
+ * htmlDtdDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * 
+ * Dump the HTML document DTD, if any.
+ */
+static void
+htmlDtdDump(xmlBufferPtr buf, xmlDocPtr doc) {
+    xmlDtdPtr cur = doc->intSubset;
+
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlDtdDump : no internal subset\n");
+	return;
+    }
+    xmlBufferWriteChar(buf, "<!DOCTYPE ");
+    xmlBufferWriteCHAR(buf, cur->name);
+    if (cur->ExternalID != NULL) {
+	xmlBufferWriteChar(buf, " PUBLIC ");
+	xmlBufferWriteQuotedString(buf, cur->ExternalID);
+	if (cur->SystemID != NULL) {
+	    xmlBufferWriteChar(buf, " ");
+	    xmlBufferWriteQuotedString(buf, cur->SystemID);
+	} 
+    }  else if (cur->SystemID != NULL) {
+	xmlBufferWriteChar(buf, " SYSTEM ");
+	xmlBufferWriteQuotedString(buf, cur->SystemID);
+    }
+    xmlBufferWriteChar(buf, ">\n");
+}
+
+/**
+ * htmlAttrDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the attribute pointer
+ *
+ * Dump an HTML attribute
+ */
+static void
+htmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
+    xmlChar *value;
+
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlAttrDump : property == NULL\n");
+	return;
+    }
+    xmlBufferWriteChar(buf, " ");
+    xmlBufferWriteCHAR(buf, cur->name);
+    if (cur->children != NULL) {
+	value = xmlNodeListGetString(doc, cur->children, 0);
+	if (value) {
+	    xmlBufferWriteChar(buf, "=");
+	    xmlBufferWriteQuotedString(buf, value);
+	    xmlFree(value);
+	} else  {
+	    xmlBufferWriteChar(buf, "=\"\"");
+	}
+    }
+}
+
+/**
+ * htmlAttrListDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the first attribute pointer
+ *
+ * Dump a list of HTML attributes
+ */
+static void
+htmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlAttrListDump : property == NULL\n");
+	return;
+    }
+    while (cur != NULL) {
+        htmlAttrDump(buf, doc, cur);
+	cur = cur->next;
+    }
+}
+
+
+void
+htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
+/**
+ * htmlNodeListDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the first node
+ *
+ * Dump an HTML node list, recursive behaviour,children are printed too.
+ */
+static void
+htmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlNodeListDump : node == NULL\n");
+	return;
+    }
+    while (cur != NULL) {
+        htmlNodeDump(buf, doc, cur);
+	cur = cur->next;
+    }
+}
+
+/**
+ * htmlNodeDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the current node
+ *
+ * Dump an HTML node, recursive behaviour,children are printed too.
+ */
+void
+htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur) {
+    htmlElemDescPtr info;
+
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlNodeDump : node == NULL\n");
+	return;
+    }
+    /*
+     * Special cases.
+     */
+    if (cur->type == XML_DTD_NODE)
+	return;
+    if (cur->type == XML_HTML_DOCUMENT_NODE) {
+	htmlDocContentDump(buf, (xmlDocPtr) cur);
+	return;
+    }
+    if (cur->type == HTML_TEXT_NODE) {
+	if (cur->content != NULL) {
+	    if ((cur->name == xmlStringText) ||
+		(cur->name != xmlStringTextNoenc)) {
+		xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+		buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+#else
+		buffer = xmlEncodeEntitiesReentrant(doc, 
+					    xmlBufferContent(cur->content));
+#endif 
+		if (buffer != NULL) {
+		    xmlBufferWriteCHAR(buf, buffer);
+		    xmlFree(buffer);
+		}
+	    } else {
+		xmlBufferWriteCHAR(buf, cur->content);
+	    }
+	}
+	return;
+    }
+    if (cur->type == HTML_COMMENT_NODE) {
+	if (cur->content != NULL) {
+	    xmlBufferWriteChar(buf, "<!--");
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlBufferWriteCHAR(buf, cur->content);
+#else
+	    xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
+#endif
+	    xmlBufferWriteChar(buf, "-->");
+	}
+	return;
+    }
+    if (cur->type == HTML_ENTITY_REF_NODE) {
+        xmlBufferWriteChar(buf, "&");
+	xmlBufferWriteCHAR(buf, cur->name);
+        xmlBufferWriteChar(buf, ";");
+	return;
+    }
+
+    /*
+     * Get specific HTmL info for taht node.
+     */
+    info = htmlTagLookup(cur->name);
+
+    xmlBufferWriteChar(buf, "<");
+    xmlBufferWriteCHAR(buf, cur->name);
+    if (cur->properties != NULL)
+        htmlAttrListDump(buf, doc, cur->properties);
+
+    if ((info != NULL) && (info->empty)) {
+        xmlBufferWriteChar(buf, ">");
+	if (cur->next != NULL) {
+	    if ((cur->next->type != HTML_TEXT_NODE) &&
+		(cur->next->type != HTML_ENTITY_REF_NODE))
+		xmlBufferWriteChar(buf, "\n");
+	}
+	return;
+    }
+    if ((cur->content == NULL) && (cur->children == NULL)) {
+        if ((info != NULL) && (info->endTag != 0))
+	    xmlBufferWriteChar(buf, ">");
+	else {
+	    xmlBufferWriteChar(buf, "></");
+	    xmlBufferWriteCHAR(buf, cur->name);
+	    xmlBufferWriteChar(buf, ">");
+	}
+	if (cur->next != NULL) {
+	    if ((cur->next->type != HTML_TEXT_NODE) &&
+		(cur->next->type != HTML_ENTITY_REF_NODE))
+		xmlBufferWriteChar(buf, "\n");
+	}
+	return;
+    }
+    xmlBufferWriteChar(buf, ">");
+    if (cur->content != NULL) {
+	xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+    buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+#else
+    buffer = xmlEncodeEntitiesReentrant(doc, 
+                                        xmlBufferContent(cur->content));
+#endif
+	if (buffer != NULL) {
+	    xmlBufferWriteCHAR(buf, buffer);
+	    xmlFree(buffer);
+	}
+    }
+    if (cur->children != NULL) {
+        if ((cur->children->type != HTML_TEXT_NODE) &&
+	    (cur->children->type != HTML_ENTITY_REF_NODE) &&
+	    (cur->children != cur->last))
+	    xmlBufferWriteChar(buf, "\n");
+	htmlNodeListDump(buf, doc, cur->children);
+        if ((cur->last->type != HTML_TEXT_NODE) &&
+	    (cur->last->type != HTML_ENTITY_REF_NODE) &&
+	    (cur->children != cur->last))
+	    xmlBufferWriteChar(buf, "\n");
+    }
+    if (!htmlIsAutoClosed(doc, cur)) {
+	xmlBufferWriteChar(buf, "</");
+	xmlBufferWriteCHAR(buf, cur->name);
+	xmlBufferWriteChar(buf, ">");
+    }
+#if 0
+    if (!htmlIsAutoClosed(doc, cur)) {
+	xmlBufferWriteChar(buf, "</");
+	xmlBufferWriteCHAR(buf, cur->name);
+	xmlBufferWriteChar(buf, ">");
+    }
+#else
+    xmlBufferWriteChar(buf, "</");
+    xmlBufferWriteCHAR(buf, cur->name);
+    xmlBufferWriteChar(buf, ">");
+#endif
+    if (cur->next != NULL) {
+        if ((cur->next->type != HTML_TEXT_NODE) &&
+	    (cur->next->type != HTML_ENTITY_REF_NODE))
+	    xmlBufferWriteChar(buf, "\n");
+    }
+}
+
+/**
+ * htmlNodeDumpFile:
+ * @out:  the FILE pointer
+ * @doc:  the document
+ * @cur:  the current node
+ *
+ * Dump an HTML node, recursive behaviour,children are printed too.
+ */
+void
+htmlNodeDumpFile(FILE *out, xmlDocPtr doc, xmlNodePtr cur) {
+    xmlBufferPtr buf;
+
+    buf = xmlBufferCreate();
+    if (buf == NULL) return;
+    htmlNodeDump(buf, doc, cur);
+    xmlBufferDump(out, buf);
+    xmlBufferFree(buf);
+}
+
+/**
+ * htmlDocContentDump:
+ * @buf:  the HTML buffer output
+ * @cur:  the document
+ *
+ * Dump an HTML document.
+ */
+static void
+htmlDocContentDump(xmlBufferPtr buf, xmlDocPtr cur) {
+    int type;
+
+    /*
+     * force to output the stuff as HTML, especially for entities
+     */
+    type = cur->type;
+    cur->type = XML_HTML_DOCUMENT_NODE;
+    if (cur->intSubset != NULL)
+        htmlDtdDump(buf, cur);
+    else {
+	/* Default to HTML-4.0 transitionnal @@@@ */
+	xmlBufferWriteChar(buf, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">");
+
+    }
+    if (cur->children != NULL) {
+        htmlNodeListDump(buf, cur, cur->children);
+    }
+    xmlBufferWriteChar(buf, "\n");
+    cur->type = (xmlElementType) type;
+}
+
+/**
+ * htmlDocDumpMemory:
+ * @cur:  the document
+ * @mem:  OUT: the memory pointer
+ * @size:  OUT: the memory lenght
+ *
+ * Dump an HTML document in memory and return the xmlChar * and it's size.
+ * It's up to the caller to free the memory.
+ */
+void
+htmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
+    xmlBufferPtr buf;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlxmlDocDumpMemory : document == NULL\n");
+#endif
+	*mem = NULL;
+	*size = 0;
+	return;
+    }
+    buf = xmlBufferCreate();
+    if (buf == NULL) {
+	*mem = NULL;
+	*size = 0;
+	return;
+    }
+    htmlDocContentDump(buf, cur);
+    *mem = buf->content;
+    *size = buf->use;
+    memset(buf, -1, sizeof(xmlBuffer));
+    xmlFree(buf);
+}
+
+
+/************************************************************************
+ *									*
+ *   		Dumping HTML tree content to an I/O output buffer	*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlDtdDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @encoding:  the encoding string
+ * 
+ * Dump the HTML document DTD, if any.
+ */
+static void
+htmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, const char *encoding) {
+    xmlDtdPtr cur = doc->intSubset;
+
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlDtdDump : no internal subset\n");
+	return;
+    }
+    xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    if (cur->ExternalID != NULL) {
+	xmlOutputBufferWriteString(buf, " PUBLIC ");
+	xmlBufferWriteQuotedString(buf->buffer, cur->ExternalID);
+	if (cur->SystemID != NULL) {
+	    xmlOutputBufferWriteString(buf, " ");
+	    xmlBufferWriteQuotedString(buf->buffer, cur->SystemID);
+	} 
+    }  else if (cur->SystemID != NULL) {
+	xmlOutputBufferWriteString(buf, " SYSTEM ");
+	xmlBufferWriteQuotedString(buf->buffer, cur->SystemID);
+    }
+    xmlOutputBufferWriteString(buf, ">\n");
+}
+
+/**
+ * htmlAttrDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the attribute pointer
+ * @encoding:  the encoding string
+ *
+ * Dump an HTML attribute
+ */
+static void
+htmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, const char *encoding) {
+    xmlChar *value;
+
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlAttrDump : property == NULL\n");
+	return;
+    }
+    xmlOutputBufferWriteString(buf, " ");
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    if (cur->children != NULL) {
+	value = xmlNodeListGetString(doc, cur->children, 0);
+	if (value) {
+	    xmlOutputBufferWriteString(buf, "=");
+	    xmlBufferWriteQuotedString(buf->buffer, value);
+	    xmlFree(value);
+	} else  {
+	    xmlOutputBufferWriteString(buf, "=\"\"");
+	}
+    }
+}
+
+/**
+ * htmlAttrListDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the first attribute pointer
+ * @encoding:  the encoding string
+ *
+ * Dump a list of HTML attributes
+ */
+static void
+htmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur, const char *encoding) {
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlAttrListDump : property == NULL\n");
+	return;
+    }
+    while (cur != NULL) {
+        htmlAttrDumpOutput(buf, doc, cur, encoding);
+	cur = cur->next;
+    }
+}
+
+
+void htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
+	                xmlNodePtr cur, const char *encoding);
+
+/**
+ * htmlNodeListDump:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the first node
+ * @encoding:  the encoding string
+ *
+ * Dump an HTML node list, recursive behaviour,children are printed too.
+ */
+static void
+htmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const char *encoding) {
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlNodeListDump : node == NULL\n");
+	return;
+    }
+    while (cur != NULL) {
+        htmlNodeDumpOutput(buf, doc, cur, encoding);
+	cur = cur->next;
+    }
+}
+
+/**
+ * htmlNodeDumpOutput:
+ * @buf:  the HTML buffer output
+ * @doc:  the document
+ * @cur:  the current node
+ * @encoding:  the encoding string
+ *
+ * Dump an HTML node, recursive behaviour,children are printed too.
+ */
+void
+htmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, const char *encoding) {
+    htmlElemDescPtr info;
+
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlNodeDump : node == NULL\n");
+	return;
+    }
+    /*
+     * Special cases.
+     */
+    if (cur->type == XML_DTD_NODE)
+	return;
+    if (cur->type == XML_HTML_DOCUMENT_NODE) {
+	htmlDocContentDumpOutput(buf, (xmlDocPtr) cur, encoding);
+	return;
+    }
+    if (cur->type == HTML_TEXT_NODE) {
+	if (cur->content != NULL) {
+	    if ((cur->name == xmlStringText) ||
+		(cur->name != xmlStringTextNoenc)) {
+		xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+		buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+#else
+		buffer = xmlEncodeEntitiesReentrant(doc, 
+					    xmlBufferContent(cur->content));
+#endif 
+		if (buffer != NULL) {
+		    xmlOutputBufferWriteString(buf, (const char *)buffer);
+		    xmlFree(buffer);
+		}
+	    } else {
+		xmlOutputBufferWriteString(buf, (const char *)cur->content);
+	    }
+	}
+	return;
+    }
+    if (cur->type == HTML_COMMENT_NODE) {
+	if (cur->content != NULL) {
+	    xmlOutputBufferWriteString(buf, "<!--");
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
+#else
+	    xmlOutputBufferWriteString(buf, (const char *)
+		                       xmlBufferContent(cur->content));
+#endif
+	    xmlOutputBufferWriteString(buf, "-->");
+	}
+	return;
+    }
+    if (cur->type == HTML_ENTITY_REF_NODE) {
+        xmlOutputBufferWriteString(buf, "&");
+	xmlOutputBufferWriteString(buf, (const char *)cur->name);
+        xmlOutputBufferWriteString(buf, ";");
+	return;
+    }
+    if (cur->type == HTML_PRESERVE_NODE) {
+	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
+#else
+	    xmlOutputBufferWriteString(buf, (const char *)
+		                       xmlBufferContent(cur->content));
+#endif
+	}
+	return;
+    }
+
+    /*
+     * Get specific HTmL info for taht node.
+     */
+    info = htmlTagLookup(cur->name);
+
+    xmlOutputBufferWriteString(buf, "<");
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    if (cur->properties != NULL)
+        htmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
+
+    if ((info != NULL) && (info->empty)) {
+        xmlOutputBufferWriteString(buf, ">");
+	if (cur->next != NULL) {
+	    if ((cur->next->type != HTML_TEXT_NODE) &&
+		(cur->next->type != HTML_ENTITY_REF_NODE))
+		xmlOutputBufferWriteString(buf, "\n");
+	}
+	return;
+    }
+    if ((cur->content == NULL) && (cur->children == NULL)) {
+        if ((info != NULL) && (info->saveEndTag != 0) &&
+	    (strcmp(info->name, "html")) && (strcmp(info->name, "body"))) {
+	    xmlOutputBufferWriteString(buf, ">");
+	} else {
+	    xmlOutputBufferWriteString(buf, "></");
+	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+	    xmlOutputBufferWriteString(buf, ">");
+	}
+	if (cur->next != NULL) {
+	    if ((cur->next->type != HTML_TEXT_NODE) &&
+		(cur->next->type != HTML_ENTITY_REF_NODE))
+		xmlOutputBufferWriteString(buf, "\n");
+	}
+	return;
+    }
+    xmlOutputBufferWriteString(buf, ">");
+    if (cur->content != NULL) {
+	    /*
+	     * Uses the OutputBuffer property to automatically convert
+	     * invalids to charrefs
+	     */
+
+#ifndef XML_USE_BUFFER_CONTENT
+            xmlOutputBufferWriteString(buf, (const char *) cur->content);
+#else
+            xmlOutputBufferWriteString(buf, 
+		           (const char *) xmlBufferContent(cur->content));
+#endif 
+    }
+    if (cur->children != NULL) {
+        if ((cur->children->type != HTML_TEXT_NODE) &&
+	    (cur->children->type != HTML_ENTITY_REF_NODE) &&
+	    (cur->children != cur->last))
+	    xmlOutputBufferWriteString(buf, "\n");
+	htmlNodeListDumpOutput(buf, doc, cur->children, encoding);
+        if ((cur->last->type != HTML_TEXT_NODE) &&
+	    (cur->last->type != HTML_ENTITY_REF_NODE) &&
+	    (cur->children != cur->last))
+	    xmlOutputBufferWriteString(buf, "\n");
+    }
+#if 0
+    if (!htmlIsAutoClosed(doc, cur)) {
+	xmlOutputBufferWriteString(buf, "</");
+	xmlOutputBufferWriteString(buf, (const char *)cur->name);
+	xmlOutputBufferWriteString(buf, ">");
+    }
+#else
+    xmlOutputBufferWriteString(buf, "</");
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    xmlOutputBufferWriteString(buf, ">");
+#endif
+    if (cur->next != NULL) {
+        if ((cur->next->type != HTML_TEXT_NODE) &&
+	    (cur->next->type != HTML_ENTITY_REF_NODE))
+	    xmlOutputBufferWriteString(buf, "\n");
+    }
+}
+
+/**
+ * htmlDocContentDump:
+ * @buf:  the HTML buffer output
+ * @cur:  the document
+ * @encoding:  the encoding string
+ *
+ * Dump an HTML document.
+ */
+void
+htmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur, const char *encoding) {
+    int type;
+
+    /*
+     * force to output the stuff as HTML, especially for entities
+     */
+    type = cur->type;
+    cur->type = XML_HTML_DOCUMENT_NODE;
+    if (cur->intSubset != NULL)
+        htmlDtdDumpOutput(buf, cur, NULL);
+    else {
+	/* Default to HTML-4.0 transitionnal @@@@ */
+	xmlOutputBufferWriteString(buf, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\" \"http://www.w3.org/TR/REC-html40/loose.dtd\">\n");
+
+    }
+    if (cur->children != NULL) {
+        htmlNodeListDumpOutput(buf, cur, cur->children, encoding);
+    }
+    xmlOutputBufferWriteString(buf, "\n");
+    cur->type = (xmlElementType) type;
+}
+
+
+/************************************************************************
+ *									*
+ *		Saving functions front-ends				*
+ *									*
+ ************************************************************************/
+
+/**
+ * htmlDocDump:
+ * @f:  the FILE*
+ * @cur:  the document
+ *
+ * Dump an HTML document to an open FILE.
+ *
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+htmlDocDump(FILE *f, xmlDocPtr cur) {
+    xmlOutputBufferPtr buf;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    const char *encoding;
+    int ret;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"htmlDocDump : document == NULL\n");
+#endif
+	return(-1);
+    }
+
+    encoding = (const char *) htmlGetMetaEncoding(cur);
+
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+	if (enc != cur->charset) {
+	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
+		/*
+		 * Not supported yet
+		 */
+		return(-1);
+	    }
+
+	    handler = xmlFindCharEncodingHandler(encoding);
+	    if (handler == NULL)
+		return(-1);
+	}
+    }
+
+    /*
+     * Fallback to HTML or ASCII when the encoding is unspecified
+     */
+    if (handler == NULL)
+	handler = xmlFindCharEncodingHandler("HTML");
+    if (handler == NULL)
+	handler = xmlFindCharEncodingHandler("ascii");
+
+    buf = xmlOutputBufferCreateFile(f, handler);
+    if (buf == NULL) return(-1);
+    htmlDocContentDumpOutput(buf, cur, NULL);
+
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * htmlSaveFile:
+ * @filename:  the filename (or URL)
+ * @cur:  the document
+ *
+ * Dump an HTML document to a file. If @filename is "-" the stdout file is
+ * used.
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+htmlSaveFile(const char *filename, xmlDocPtr cur) {
+    xmlOutputBufferPtr buf;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    const char *encoding;
+    int ret;
+
+    encoding = (const char *) htmlGetMetaEncoding(cur);
+
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+	if (enc != cur->charset) {
+	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
+		/*
+		 * Not supported yet
+		 */
+		return(-1);
+	    }
+
+	    handler = xmlFindCharEncodingHandler(encoding);
+	    if (handler == NULL)
+		return(-1);
+	}
+    }
+
+    /*
+     * Fallback to HTML or ASCII when the encoding is unspecified
+     */
+    if (handler == NULL)
+	handler = xmlFindCharEncodingHandler("HTML");
+    if (handler == NULL)
+	handler = xmlFindCharEncodingHandler("ascii");
+
+    /* 
+     * save the content to a temp buffer.
+     */
+    buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
+    if (buf == NULL) return(0);
+
+    htmlDocContentDumpOutput(buf, cur, NULL);
+
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * htmlSaveFileEnc:
+ * @filename:  the filename
+ * @cur:  the document
+ *
+ * Dump an HTML document to a file using a given encoding.
+ * 
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+htmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
+    xmlOutputBufferPtr buf;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    int ret;
+
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+	if (enc != cur->charset) {
+	    if (cur->charset != XML_CHAR_ENCODING_UTF8) {
+		/*
+		 * Not supported yet
+		 */
+		return(-1);
+	    }
+
+	    handler = xmlFindCharEncodingHandler(encoding);
+	    if (handler == NULL)
+		return(-1);
+            htmlSetMetaEncoding(cur, (const xmlChar *) encoding);
+	}
+    }
+
+    /*
+     * Fallback to HTML or ASCII when the encoding is unspecified
+     */
+    if (handler == NULL)
+	handler = xmlFindCharEncodingHandler("HTML");
+    if (handler == NULL)
+	handler = xmlFindCharEncodingHandler("ascii");
+
+    /* 
+     * save the content to a temp buffer.
+     */
+    buf = xmlOutputBufferCreateFilename(filename, handler, 0);
+    if (buf == NULL) return(0);
+
+    htmlDocContentDumpOutput(buf, cur, encoding);
+
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+#endif /* LIBXML_HTML_ENABLED */
diff --git a/HTMLtree.h b/HTMLtree.h
new file mode 100644
index 0000000..543d693
--- /dev/null
+++ b/HTMLtree.h
@@ -0,0 +1,61 @@
+/*
+ * tree.h : describes the structures found in an tree resulting
+ *          from an XML parsing.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __HTML_TREE_H__
+#define __HTML_TREE_H__
+
+#include <stdio.h>
+#include <libxml/tree.h>
+#include <libxml/HTMLparser.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HTML_TEXT_NODE		XML_TEXT_NODE
+#define HTML_ENTITY_REF_NODE	XML_ENTITY_REF_NODE
+#define HTML_COMMENT_NODE	XML_COMMENT_NODE
+#define HTML_PRESERVE_NODE	XML_CDATA_SECTION_NODE
+
+htmlDocPtr	htmlNewDoc		(const xmlChar *URI,
+					 const xmlChar *ExternalID);
+htmlDocPtr	htmlNewDocNoDtD		(const xmlChar *URI,
+					 const xmlChar *ExternalID);
+const xmlChar *	htmlGetMetaEncoding	(htmlDocPtr doc);
+int		htmlSetMetaEncoding	(htmlDocPtr doc,
+					 const xmlChar *encoding);
+void		htmlDocDumpMemory	(xmlDocPtr cur,
+					 xmlChar**mem,
+					 int *size);
+int		htmlDocDump		(FILE *f,
+					 xmlDocPtr cur);
+int		htmlSaveFile		(const char *filename,
+					 xmlDocPtr cur);
+void		htmlNodeDump		(xmlBufferPtr buf,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur);
+void		htmlNodeDumpFile	(FILE *out,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur);
+int		htmlSaveFileEnc		(const char *filename,
+					 xmlDocPtr cur,
+					 const char *encoding);
+
+/* This one is imported from xmlIO.h
+void		htmlDocContentDumpOutput(xmlOutputBufferPtr buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HTML_TREE_H__ */
+
diff --git a/Makefile.am b/Makefile.am
index 34197ae..a682971 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,45 +1,87 @@
 ## Process this file with automake to produce Makefile.in
 
-SUBDIRS = libxml doc example
+SUBDIRS = . include doc example
 
-INCLUDES = $(CORBA_CFLAGS)
+INCLUDES = -I@srcdir@/include -I./include @Z_CFLAGS@ @CORBA_CFLAGS@ 
 
 noinst_PROGRAMS=testSAX testHTML testXPath testURI
 
-DEPS = $(top_builddir)/libxml/libxml2.la
-LDADDS = $(top_builddir)/libxml/libxml2.la
-
 bin_PROGRAMS = xmllint
 
-xmllint_SOURCES = xmllint.c
+bin_SCRIPTS=xml2-config
+
+lib_LTLIBRARIES = libxml2.la
+libxml2_la_LIBADD = @Z_LIBS@
+
+libxml2_la_LDFLAGS = -version-info @LIBXML_VERSION_INFO@
+
+libxml2_la_SOURCES = \
+		SAX.c \
+		entities.c \
+		encoding.c \
+		error.c \
+		parserInternals.c \
+		parser.c \
+		tree.c \
+		hash.c \
+		list.c \
+		xmlIO.c \
+		xmlmemory.c \
+		uri.c \
+		valid.c \
+		xlink.c \
+		HTMLparser.c \
+		HTMLtree.c \
+		debugXML.c \
+		xpath.c \
+		xpointer.c \
+		xinclude.c \
+		nanohttp.c \
+		nanoftp.c
+
+DEPS = $(top_builddir)/libxml2.la
+LDADDS = $(top_builddir)/libxml2.la @Z_LIBS@ @M_LIBS@
+
+man_MANS = xmllint.1 xml2-config.1 libxml.4
+
+m4datadir = $(datadir)/aclocal
+m4data_DATA = libxml.m4
+
+xmllint_SOURCES=xmllint.c
 xmllint_LDFLAGS = 
 xmllint_DEPENDENCIES = $(DEPS)
-xmllint_LDADD = $(RDL_LIBS) $(LDADDS)
+xmllint_LDADD=  @RDL_LIBS@ $(LDADDS)
 
-testSAX_SOURCES = testSAX.c
+testSAX_SOURCES=testSAX.c
 testSAX_LDFLAGS = 
 testSAX_DEPENDENCIES = $(DEPS)
-testSAX_LDADD = $(LDADDS)
+testSAX_LDADD= $(LDADDS)
 
-testHTML_SOURCES = testHTML.c
+testHTML_SOURCES=testHTML.c
 testHTML_LDFLAGS = 
 testHTML_DEPENDENCIES = $(DEPS)
-testHTML_LDADD = $(LDADDS)
+testHTML_LDADD= $(LDADDS)
 
-testXPath_SOURCES = testXPath.c
+testXPath_SOURCES=testXPath.c
 testXPath_LDFLAGS = 
 testXPath_DEPENDENCIES = $(DEPS)
-testXPath_LDADD = $(LDADDS)
+testXPath_LDADD= $(LDADDS)
 
-testURI_SOURCES = testURI.c
+testURI_SOURCES=testURI.c
 testURI_LDFLAGS = 
 testURI_DEPENDENCIES = $(DEPS)
-testURI_LDADD = $(LDADDS)
+testURI_LDADD= $(LDADDS)
 
 check-local: tests
 
+$(srcdir)/libxml:
+	-$(RM) $(srcdir)/libxml
+	ln -s $(srcdir)/. $(srcdir)/libxml
+
 install-data: $(srcdir)/libxml
 
+$(libxml2_la_SOURCES): $(srcdir)/libxml
+
 testall : tests SVGtests SAXtests
 
 tests: XMLtests XMLenttests HTMLtests Validtests URItests XPathtests XPtrtests XIncludetests
@@ -363,3 +405,34 @@
 
 rpm: cleantar distcheck
 	rpm -ta $(distdir).tar.gz
+
+## We create xml2Conf.sh here and not from configure because we want
+## to get the paths expanded correctly.  Macros like srcdir are given
+## the value NONE in configure if the user doesn't specify them (this
+## is an autoconf feature, not a bug).
+
+confexecdir=$(libdir)
+confexec_DATA = xml2Conf.sh
+
+CLEANFILES=xml2Conf.sh
+
+confexecdir=$(libdir)
+confexec_DATA = xml2Conf.sh
+EXTRA_DIST = xml2Conf.sh.in libxml.spec.in libxml.spec libxml.m4 \
+             example/Makefile.am example/gjobread.c example/gjobs.xml \
+	     $(man_MANS) libxml-2.0.pc.in xmlversion.h.in \
+	     win32/README.MSDev win32/Makefile.mingw \
+	     win32/libxml2/libxml2.dsp win32/libxml2/libxml2_so.dsp \
+	     win32/libxml2/libxml2_a.dsp vms/build_libxml.com vms/config.vms
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = libxml-2.0.pc
+
+#xml2Conf.sh: xml2Conf.sh.in Makefile
+### Use sed and then mv to avoid problems if the user interrupts.
+#	sed -e 's?\@XML_LIBDIR\@?$(XML_LIBDIR)?g' \
+#	    -e 's?\@XML_INCLUDEDIR\@?$(XML_INCLUDEDIR)?g' \
+#	    -e 's?\@XML_LIBS\@?$(XML_LIBS)?g' \
+#	    -e 's?\@VERSION\@?$(VERSION)?g' \
+#	      < $(srcdir)/xml2Conf.sh.in > xml2Conf.tmp \
+#	  && mv xml2Conf.tmp xml2Conf.sh
diff --git a/SAX.c b/SAX.c
new file mode 100644
index 0000000..d7e256b
--- /dev/null
+++ b/SAX.c
@@ -0,0 +1,1751 @@
+/*
+ * SAX.c : Default SAX handler to build a tree.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/valid.h>
+#include <libxml/entities.h>
+#include <libxml/xmlerror.h>
+#include <libxml/debugXML.h>
+#include <libxml/xmlIO.h>
+#include <libxml/SAX.h>
+#include <libxml/uri.h>
+#include <libxml/HTMLtree.h>
+
+/* #define DEBUG_SAX */
+/* #define DEBUG_SAX_TREE */
+
+/**
+ * getPublicId:
+ * @ctx: the user data (XML parser context)
+ *
+ * Return the public ID e.g. "-//SGMLSOURCE//DTD DEMO//EN"
+ *
+ * Returns a xmlChar *
+ */
+const xmlChar *
+getPublicId(void *ctx)
+{
+    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
+    return(NULL);
+}
+
+/**
+ * getSystemId:
+ * @ctx: the user data (XML parser context)
+ *
+ * Return the system ID, basically URL or filename e.g.
+ * http://www.sgmlsource.com/dtds/memo.dtd
+ *
+ * Returns a xmlChar *
+ */
+const xmlChar *
+getSystemId(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    return(BAD_CAST ctxt->input->filename); 
+}
+
+/**
+ * getLineNumber:
+ * @ctx: the user data (XML parser context)
+ *
+ * Return the line number of the current parsing point.
+ *
+ * Returns an int
+ */
+int
+getLineNumber(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    return(ctxt->input->line);
+}
+
+/**
+ * getColumnNumber:
+ * @ctx: the user data (XML parser context)
+ *
+ * Return the column number of the current parsing point.
+ *
+ * Returns an int
+ */
+int
+getColumnNumber(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    return(ctxt->input->col);
+}
+
+/*
+ * The default SAX Locator.
+ */
+
+xmlSAXLocator xmlDefaultSAXLocator = {
+    getPublicId, getSystemId, getLineNumber, getColumnNumber
+};
+
+/**
+ * isStandalone:
+ * @ctx: the user data (XML parser context)
+ *
+ * Is this document tagged standalone ?
+ *
+ * Returns 1 if true
+ */
+int
+isStandalone(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    return(ctxt->myDoc->standalone == 1);
+}
+
+/**
+ * hasInternalSubset:
+ * @ctx: the user data (XML parser context)
+ *
+ * Does this document has an internal subset
+ *
+ * Returns 1 if true
+ */
+int
+hasInternalSubset(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    return(ctxt->myDoc->intSubset != NULL);
+}
+
+/**
+ * hasExternalSubset:
+ * @ctx: the user data (XML parser context)
+ *
+ * Does this document has an external subset
+ *
+ * Returns 1 if true
+ */
+int
+hasExternalSubset(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    return(ctxt->myDoc->extSubset != NULL);
+}
+
+/**
+ * internalSubset:
+ * @ctx:  the user data (XML parser context)
+ * @name:  the root element name
+ * @ExternalID:  the external ID
+ * @SystemID:  the SYSTEM ID (e.g. filename or URL)
+ *
+ * Callback on internal subset declaration.
+ */
+void
+internalSubset(void *ctx, const xmlChar *name,
+	       const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlDtdPtr dtd;
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.internalSubset(%s, %s, %s)\n",
+            name, ExternalID, SystemID);
+#endif
+
+    if (ctxt->myDoc == NULL)
+	return;
+    dtd = xmlGetIntSubset(ctxt->myDoc);
+    if (dtd != NULL) {
+	if (ctxt->html)
+	    return;
+	xmlUnlinkNode((xmlNodePtr) dtd);
+	xmlFreeDtd(dtd);
+	ctxt->myDoc->intSubset = NULL;
+    }
+    ctxt->myDoc->intSubset = 
+	xmlCreateIntSubset(ctxt->myDoc, name, ExternalID, SystemID);
+}
+
+/**
+ * externalSubset:
+ * @ctx: the user data (XML parser context)
+ * @name:  the root element name
+ * @ExternalID:  the external ID
+ * @SystemID:  the SYSTEM ID (e.g. filename or URL)
+ *
+ * Callback on external subset declaration.
+ */
+void
+externalSubset(void *ctx, const xmlChar *name,
+	       const xmlChar *ExternalID, const xmlChar *SystemID)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.externalSubset(%s, %s, %s)\n",
+            name, ExternalID, SystemID);
+#endif
+    if (((ExternalID != NULL) || (SystemID != NULL)) &&
+        (((ctxt->validate) || (ctxt->loadsubset)) &&
+	 (ctxt->wellFormed && ctxt->myDoc))) {
+	/*
+	 * Try to fetch and parse the external subset.
+	 */
+	xmlParserInputPtr oldinput;
+	int oldinputNr;
+	int oldinputMax;
+	xmlParserInputPtr *oldinputTab;
+	int oldwellFormed;
+	xmlParserInputPtr input = NULL;
+	xmlCharEncoding enc;
+	int oldcharset;
+
+	/*
+	 * Ask the Entity resolver to load the damn thing
+	 */
+	if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
+	    input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID,
+	                                        SystemID);
+	if (input == NULL) {
+	    return;
+	}
+
+	xmlNewDtd(ctxt->myDoc, name, ExternalID, SystemID);
+
+	/*
+	 * make sure we won't destroy the main document context
+	 */
+	oldinput = ctxt->input;
+	oldinputNr = ctxt->inputNr;
+	oldinputMax = ctxt->inputMax;
+	oldinputTab = ctxt->inputTab;
+	oldwellFormed = ctxt->wellFormed;
+	oldcharset = ctxt->charset;
+
+	ctxt->inputTab = (xmlParserInputPtr *)
+	                 xmlMalloc(5 * sizeof(xmlParserInputPtr));
+	if (ctxt->inputTab == NULL) {
+	    ctxt->errNo = XML_ERR_NO_MEMORY;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		     "externalSubset: out of memory\n");
+	    ctxt->errNo = XML_ERR_NO_MEMORY;
+	    ctxt->input = oldinput;
+	    ctxt->inputNr = oldinputNr;
+	    ctxt->inputMax = oldinputMax;
+	    ctxt->inputTab = oldinputTab;
+	    ctxt->charset = oldcharset;
+	    return;
+	}
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 5;
+	ctxt->input = NULL;
+	xmlPushInput(ctxt, input);
+
+	/*
+	 * On the fly encoding conversion if needed
+	 */
+	enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
+	xmlSwitchEncoding(ctxt, enc);
+
+	if (input->filename == NULL)
+	    input->filename = (char *) xmlStrdup(SystemID);
+	input->line = 1;
+	input->col = 1;
+	input->base = ctxt->input->cur;
+	input->cur = ctxt->input->cur;
+	input->free = NULL;
+
+	/*
+	 * let's parse that entity knowing it's an external subset.
+	 */
+	xmlParseExternalSubset(ctxt, ExternalID, SystemID);
+
+        /*
+	 * Free up the external entities
+	 */
+
+	while (ctxt->inputNr > 1)
+	    xmlPopInput(ctxt);
+	xmlFreeInputStream(ctxt->input);
+        xmlFree(ctxt->inputTab);
+
+	/*
+	 * Restore the parsing context of the main entity
+	 */
+	ctxt->input = oldinput;
+	ctxt->inputNr = oldinputNr;
+	ctxt->inputMax = oldinputMax;
+	ctxt->inputTab = oldinputTab;
+	ctxt->charset = oldcharset;
+	/* ctxt->wellFormed = oldwellFormed; */
+    }
+}
+
+/**
+ * resolveEntity:
+ * @ctx: the user data (XML parser context)
+ * @publicId: The public ID of the entity
+ * @systemId: The system ID of the entity
+ *
+ * The entity loader, to control the loading of external entities,
+ * the application can either:
+ *    - override this resolveEntity() callback in the SAX block
+ *    - or better use the xmlSetExternalEntityLoader() function to
+ *      set up it's own entity resolution routine
+ *
+ * Returns the xmlParserInputPtr if inlined or NULL for DOM behaviour.
+ */
+xmlParserInputPtr
+resolveEntity(void *ctx, const xmlChar *publicId, const xmlChar *systemId)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlParserInputPtr ret;
+    xmlChar *URI;
+    const char *base = NULL;
+
+    if (ctxt->input != NULL)
+	base = ctxt->input->filename;
+    if (base == NULL)
+	base = ctxt->directory;
+
+    URI = xmlBuildURI(systemId, (const xmlChar *) base);
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.resolveEntity(%s, %s)\n", publicId, systemId);
+#endif
+
+    ret = xmlLoadExternalEntity((const char *) URI,
+				(const char *) publicId, ctxt);
+    if (URI != NULL)
+	xmlFree(URI);
+    return(ret);
+}
+
+/**
+ * getEntity:
+ * @ctx: the user data (XML parser context)
+ * @name: The entity name
+ *
+ * Get an entity by name
+ *
+ * Returns the xmlEntityPtr if found.
+ */
+xmlEntityPtr
+getEntity(void *ctx, const xmlChar *name)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlEntityPtr ret;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.getEntity(%s)\n", name);
+#endif
+
+    ret = xmlGetDocEntity(ctxt->myDoc, name);
+    if ((ret != NULL) && (ctxt->validate) && (ret->children == NULL) &&
+	(ret->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
+	/*
+	 * for validation purposes we really need to fetch and
+	 * parse the external entity
+	 */
+	int parse;
+	xmlNodePtr children;
+
+        parse = xmlParseCtxtExternalEntity(ctxt,
+		  ret->SystemID, ret->ExternalID, &children);
+	xmlAddChildList((xmlNodePtr) ret, children);
+    }
+    return(ret);
+}
+
+/**
+ * getParameterEntity:
+ * @ctx: the user data (XML parser context)
+ * @name: The entity name
+ *
+ * Get a parameter entity by name
+ *
+ * Returns the xmlEntityPtr if found.
+ */
+xmlEntityPtr
+getParameterEntity(void *ctx, const xmlChar *name)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlEntityPtr ret;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.getParameterEntity(%s)\n", name);
+#endif
+
+    ret = xmlGetParameterEntity(ctxt->myDoc, name);
+    return(ret);
+}
+
+
+/**
+ * entityDecl:
+ * @ctx: the user data (XML parser context)
+ * @name:  the entity name 
+ * @type:  the entity type 
+ * @publicId: The public ID of the entity
+ * @systemId: The system ID of the entity
+ * @content: the entity value (without processing).
+ *
+ * An entity definition has been parsed
+ */
+void
+entityDecl(void *ctx, const xmlChar *name, int type,
+          const xmlChar *publicId, const xmlChar *systemId, xmlChar *content)
+{
+    xmlEntityPtr ent;
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.entityDecl(%s, %d, %s, %s, %s)\n",
+            name, type, publicId, systemId, content);
+#endif
+    if (ctxt->inSubset == 1) {
+	ent = xmlAddDocEntity(ctxt->myDoc, name, type, publicId,
+		              systemId, content);
+	if ((ent == NULL) && (ctxt->pedantic) &&
+	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	    ctxt->sax->warning(ctxt, 
+	     "Entity(%s) already defined in the internal subset\n", name);
+	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
+	    xmlChar *URI;
+	    const char *base = NULL;
+
+	    if (ctxt->input != NULL)
+		base = ctxt->input->filename;
+	    if (base == NULL)
+		base = ctxt->directory;
+	
+	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
+	    ent->URI = URI;
+	}
+    } else if (ctxt->inSubset == 2) {
+	ent = xmlAddDtdEntity(ctxt->myDoc, name, type, publicId,
+		              systemId, content);
+	if ((ent == NULL) && (ctxt->pedantic) &&
+	    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	    ctxt->sax->warning(ctxt, 
+	     "Entity(%s) already defined in the external subset\n", name);
+	if ((ent != NULL) && (ent->URI == NULL) && (systemId != NULL)) {
+	    xmlChar *URI;
+	    const char *base = NULL;
+
+	    if (ctxt->input != NULL)
+		base = ctxt->input->filename;
+	    if (base == NULL)
+		base = ctxt->directory;
+	
+	    URI = xmlBuildURI(systemId, (const xmlChar *) base);
+	    ent->URI = URI;
+	}
+    } else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+	     "SAX.entityDecl(%s) called while not in subset\n", name);
+    }
+}
+
+/**
+ * attributeDecl:
+ * @ctx: the user data (XML parser context)
+ * @elem:  the name of the element
+ * @fullname:  the attribute name 
+ * @type:  the attribute type 
+ * @def:  the type of default value
+ * @defaultValue: the attribute default value
+ * @tree:  the tree of enumerated value set
+ *
+ * An attribute definition has been parsed
+ */
+void
+attributeDecl(void *ctx, const xmlChar *elem, const xmlChar *fullname,
+              int type, int def, const xmlChar *defaultValue,
+	      xmlEnumerationPtr tree)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlAttributePtr attr;
+    xmlChar *name = NULL, *prefix = NULL;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.attributeDecl(%s, %s, %d, %d, %s, ...)\n",
+            elem, fullname, type, def, defaultValue);
+#endif
+    name = xmlSplitQName(ctxt, fullname, &prefix);
+    if (ctxt->inSubset == 1)
+	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, elem,
+	       name, prefix, (xmlAttributeType) type,
+	       (xmlAttributeDefault) def, defaultValue, tree);
+    else if (ctxt->inSubset == 2)
+	attr = xmlAddAttributeDecl(&ctxt->vctxt, ctxt->myDoc->extSubset, elem,
+	   name, prefix, (xmlAttributeType) type, 
+	   (xmlAttributeDefault) def, defaultValue, tree);
+    else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+	     "SAX.attributeDecl(%s) called while not in subset\n", name);
+	return;
+    }
+    if (attr == 0) ctxt->valid = 0;
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+	ctxt->valid &= xmlValidateAttributeDecl(&ctxt->vctxt, ctxt->myDoc,
+	                                        attr);
+    if (prefix != NULL)
+	xmlFree(prefix);
+    if (name != NULL)
+	xmlFree(name);
+}
+
+/**
+ * elementDecl:
+ * @ctx: the user data (XML parser context)
+ * @name:  the element name 
+ * @type:  the element type 
+ * @content: the element value tree
+ *
+ * An element definition has been parsed
+ */
+void
+elementDecl(void *ctx, const xmlChar *name, int type,
+	    xmlElementContentPtr content)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlElementPtr elem = NULL;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.elementDecl(%s, %d, ...)\n",
+            fullname, type);
+#endif
+    
+    if (ctxt->inSubset == 1)
+	elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->intSubset,
+                             name, (xmlElementTypeVal) type, content);
+    else if (ctxt->inSubset == 2)
+	elem = xmlAddElementDecl(&ctxt->vctxt, ctxt->myDoc->extSubset,
+                             name, (xmlElementTypeVal) type, content);
+    else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+	     "SAX.elementDecl(%s) called while not in subset\n", name);
+	return;
+    }
+    if (elem == NULL) ctxt->valid = 0;
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+	ctxt->valid &= xmlValidateElementDecl(&ctxt->vctxt, ctxt->myDoc, elem);
+}
+
+/**
+ * notationDecl:
+ * @ctx: the user data (XML parser context)
+ * @name: The name of the notation
+ * @publicId: The public ID of the entity
+ * @systemId: The system ID of the entity
+ *
+ * What to do when a notation declaration has been parsed.
+ */
+void
+notationDecl(void *ctx, const xmlChar *name,
+	     const xmlChar *publicId, const xmlChar *systemId)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNotationPtr nota = NULL;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.notationDecl(%s, %s, %s)\n", name, publicId, systemId);
+#endif
+
+    if (ctxt->inSubset == 1)
+	nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
+                              publicId, systemId);
+    else if (ctxt->inSubset == 2)
+	nota = xmlAddNotationDecl(&ctxt->vctxt, ctxt->myDoc->intSubset, name,
+                              publicId, systemId);
+    else {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt, 
+	     "SAX.notationDecl(%s) called while not in subset\n", name);
+	return;
+    }
+    if (nota == NULL) ctxt->valid = 0;
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+	ctxt->valid &= xmlValidateNotationDecl(&ctxt->vctxt, ctxt->myDoc,
+	                                       nota);
+}
+
+/**
+ * unparsedEntityDecl:
+ * @ctx: the user data (XML parser context)
+ * @name: The name of the entity
+ * @publicId: The public ID of the entity
+ * @systemId: The system ID of the entity
+ * @notationName: the name of the notation
+ *
+ * What to do when an unparsed entity declaration is parsed
+ */
+void
+unparsedEntityDecl(void *ctx, const xmlChar *name,
+		   const xmlChar *publicId, const xmlChar *systemId,
+		   const xmlChar *notationName)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.unparsedEntityDecl(%s, %s, %s, %s)\n",
+            name, publicId, systemId, notationName);
+#endif
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+	ctxt->valid &= xmlValidateNotationUse(&ctxt->vctxt, ctxt->myDoc,
+	                                      notationName);
+    xmlAddDocEntity(ctxt->myDoc, name,
+                    XML_EXTERNAL_GENERAL_UNPARSED_ENTITY,
+		    publicId, systemId, notationName);
+}
+
+/**
+ * setDocumentLocator:
+ * @ctx: the user data (XML parser context)
+ * @loc: A SAX Locator
+ *
+ * Receive the document locator at startup, actually xmlDefaultSAXLocator
+ * Everything is available on the context, so this is useless in our case.
+ */
+void
+setDocumentLocator(void *ctx, xmlSAXLocatorPtr loc)
+{
+    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.setDocumentLocator()\n");
+#endif
+}
+
+/**
+ * startDocument:
+ * @ctx: the user data (XML parser context)
+ *
+ * called when the document start being processed.
+ */
+void
+startDocument(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlDocPtr doc;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.startDocument()\n");
+#endif
+    if (ctxt->html) {
+	if (ctxt->myDoc == NULL)
+#ifdef LIBXML_HTML_ENABLED
+	    ctxt->myDoc = htmlNewDocNoDtD(NULL, NULL);
+#else
+        xmlGenericError(xmlGenericErrorContext,
+		"libxml2 built without HTML support\n");
+#endif
+    } else {
+	doc = ctxt->myDoc = xmlNewDoc(ctxt->version);
+	if (doc != NULL) {
+	    if (ctxt->encoding != NULL)
+		doc->encoding = xmlStrdup(ctxt->encoding);
+	    else
+		doc->encoding = NULL;
+	    doc->standalone = ctxt->standalone;
+	}
+    }
+    if ((ctxt->myDoc != NULL) && (ctxt->myDoc->URL == NULL) &&
+	(ctxt->input != NULL) && (ctxt->input->filename != NULL)) {
+        ctxt->myDoc->URL = xmlStrdup((xmlChar *) ctxt->input->filename);
+    }
+}
+
+/**
+ * endDocument:
+ * @ctx: the user data (XML parser context)
+ *
+ * called when the document end has been detected.
+ */
+void
+endDocument(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.endDocument()\n");
+#endif
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+	ctxt->valid &= xmlValidateDocumentFinal(&ctxt->vctxt, ctxt->myDoc);
+
+    /*
+     * Grab the encoding if it was added on-the-fly
+     */
+    if ((ctxt->encoding != NULL) && (ctxt->myDoc != NULL) &&
+	(ctxt->myDoc->encoding == NULL)) {
+	ctxt->myDoc->encoding = ctxt->encoding;
+	ctxt->encoding = NULL;
+    }
+    if ((ctxt->inputTab[0]->encoding != NULL) && (ctxt->myDoc != NULL) &&
+	(ctxt->myDoc->encoding == NULL)) {
+	ctxt->myDoc->encoding = xmlStrdup(ctxt->inputTab[0]->encoding);
+    }
+    if ((ctxt->charset != XML_CHAR_ENCODING_NONE) && (ctxt->myDoc != NULL) &&
+	(ctxt->myDoc->charset == XML_CHAR_ENCODING_NONE)) {
+	ctxt->myDoc->charset = ctxt->charset;
+    }
+}
+
+/**
+ * attribute:
+ * @ctx: the user data (XML parser context)
+ * @fullname:  The attribute name, including namespace prefix
+ * @value:  The attribute value
+ *
+ * Handle an attribute that has been read by the parser.
+ * The default handling is to convert the attribute into an
+ * DOM subtree and past it in a new xmlAttr element added to
+ * the element.
+ */
+void
+attribute(void *ctx, const xmlChar *fullname, const xmlChar *value)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlAttrPtr ret;
+    xmlChar *name;
+    xmlChar *ns;
+    xmlChar *nval;
+    xmlNsPtr namespace;
+
+/****************
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+    "SAX.attribute(%s, %s)\n", fullname, value);
+#endif
+ ****************/
+    /*
+     * Split the full name into a namespace prefix and the tag name
+     */
+    name = xmlSplitQName(ctxt, fullname, &ns);
+
+    /*
+     * Do the last stage of the attribute normalization
+     * Needed for HTML too:
+     *   http://www.w3.org/TR/html4/types.html#h-6.2
+     */
+    nval = xmlValidNormalizeAttributeValue(ctxt->myDoc, ctxt->node,
+					   fullname, value);
+    if (nval != NULL)
+	value = nval;
+
+    /*
+     * Check whether it's a namespace definition
+     */
+    if ((!ctxt->html) && (ns == NULL) &&
+        (name[0] == 'x') && (name[1] == 'm') && (name[2] == 'l') &&
+        (name[3] == 'n') && (name[4] == 's') && (name[5] == 0)) {
+	if (value[0] != 0) {
+	    xmlURIPtr uri;
+
+	    uri = xmlParseURI((const char *)value);
+	    if (uri == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+		    ctxt->sax->warning(ctxt->userData, 
+			 "nmlns: %s not a valid URI\n", value);
+	    } else {
+		if (uri->scheme == NULL) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			ctxt->sax->warning(ctxt->userData, 
+			     "nmlns: URI %s is not absolute\n", value);
+		}
+		xmlFreeURI(uri);
+	    }
+	}
+
+	/* a default namespace definition */
+	xmlNewNs(ctxt->node, value, NULL);
+	if (name != NULL) 
+	    xmlFree(name);
+	if (nval != NULL)
+	    xmlFree(nval);
+	return;
+    }
+    if ((!ctxt->html) &&
+	(ns != NULL) && (ns[0] == 'x') && (ns[1] == 'm') && (ns[2] == 'l') &&
+        (ns[3] == 'n') && (ns[4] == 's') && (ns[5] == 0)) {
+	/*
+	 * Validate also for namespace decls, they are attributes from
+	 * an XML-1.0 perspective
+	 TODO ... doesn't map well with current API
+        if (ctxt->validate && ctxt->wellFormed &&
+	    ctxt->myDoc && ctxt->myDoc->intSubset)
+	    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
+					       ctxt->node, ret, value);
+	 */
+	/* a standard namespace definition */
+	xmlNewNs(ctxt->node, value, name);
+	xmlFree(ns);
+	if (name != NULL) 
+	    xmlFree(name);
+	if (nval != NULL)
+	    xmlFree(nval);
+	return;
+    }
+
+    if (ns != NULL)
+	namespace = xmlSearchNs(ctxt->myDoc, ctxt->node, ns);
+    else {
+	namespace = NULL;
+    }
+
+    /* !!!!!! <a toto:arg="" xmlns:toto="http://toto.com"> */
+    ret = xmlNewNsProp(ctxt->node, namespace, name, NULL);
+
+    if (ret != NULL) {
+        if ((ctxt->replaceEntities == 0) && (!ctxt->html)) {
+	    xmlNodePtr tmp;
+
+	    ret->children = xmlStringGetNodeList(ctxt->myDoc, value);
+	    tmp = ret->children;
+	    while (tmp != NULL) {
+		tmp->parent = (xmlNodePtr) ret;
+		if (tmp->next == NULL)
+		    ret->last = tmp;
+		tmp = tmp->next;
+	    }
+	} else if (value != NULL) {
+	    ret->children = xmlNewDocText(ctxt->myDoc, value);
+	    ret->last = ret->children;
+	    if (ret->children != NULL)
+		ret->children->parent = (xmlNodePtr) ret;
+	}
+    }
+
+    if ((!ctxt->html) && ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset) {
+	
+	/*
+	 * If we don't substitute entities, the validation should be
+	 * done on a value with replaced entities anyway.
+	 */
+        if (!ctxt->replaceEntities) {
+	    xmlChar *val;
+
+	    ctxt->depth++;
+	    val = xmlStringDecodeEntities(ctxt, value, XML_SUBSTITUTE_REF,
+		                          0,0,0);
+	    ctxt->depth--;
+	    if (val == NULL)
+		ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
+				ctxt->myDoc, ctxt->node, ret, value);
+	    else {
+		ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt,
+			        ctxt->myDoc, ctxt->node, ret, val);
+                xmlFree(val);
+	    }
+	} else {
+	    ctxt->valid &= xmlValidateOneAttribute(&ctxt->vctxt, ctxt->myDoc,
+					       ctxt->node, ret, value);
+	}
+    } else {
+        /*
+	 * when validating, the ID registration is done at the attribute
+	 * validation level. Otherwise we have to do specific handling here.
+	 */
+	if (xmlIsID(ctxt->myDoc, ctxt->node, ret))
+	    xmlAddID(&ctxt->vctxt, ctxt->myDoc, value, ret);
+	else if (xmlIsRef(ctxt->myDoc, ctxt->node, ret))
+	    xmlAddRef(&ctxt->vctxt, ctxt->myDoc, value, ret);
+    }
+
+    if (nval != NULL)
+	xmlFree(nval);
+    if (name != NULL) 
+	xmlFree(name);
+    if (ns != NULL) 
+	xmlFree(ns);
+}
+
+/**
+ * startElement:
+ * @ctx: the user data (XML parser context)
+ * @fullname:  The element name, including namespace prefix
+ * @atts:  An array of name/value attributes pairs, NULL terminated
+ *
+ * called when an opening tag has been processed.
+ */
+void
+startElement(void *ctx, const xmlChar *fullname, const xmlChar **atts)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr ret;
+    xmlNodePtr parent = ctxt->node;
+    xmlNsPtr ns;
+    xmlChar *name;
+    xmlChar *prefix;
+    const xmlChar *att;
+    const xmlChar *value;
+    int i;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.startElement(%s)\n", fullname);
+#endif
+
+    /*
+     * First check on validity:
+     */
+    if (ctxt->validate && (ctxt->myDoc->extSubset == NULL) && 
+        ((ctxt->myDoc->intSubset == NULL) ||
+	 ((ctxt->myDoc->intSubset->notations == NULL) && 
+	  (ctxt->myDoc->intSubset->elements == NULL) &&
+	  (ctxt->myDoc->intSubset->attributes == NULL) && 
+	  (ctxt->myDoc->intSubset->entities == NULL)))) {
+	if (ctxt->vctxt.error != NULL) {
+            ctxt->vctxt.error(ctxt->vctxt.userData,
+	      "Validation failed: no DTD found !\n");
+	}
+	ctxt->validate = 0;
+    }
+       
+
+    /*
+     * Split the full name into a namespace prefix and the tag name
+     */
+    name = xmlSplitQName(ctxt, fullname, &prefix);
+
+
+    /*
+     * Note : the namespace resolution is deferred until the end of the
+     *        attributes parsing, since local namespace can be defined as
+     *        an attribute at this level.
+     */
+    ret = xmlNewDocNode(ctxt->myDoc, NULL, name, NULL);
+    if (ret == NULL) return;
+    if (ctxt->myDoc->children == NULL) {
+#ifdef DEBUG_SAX_TREE
+	xmlGenericError(xmlGenericErrorContext, "Setting %s as root\n", name);
+#endif
+        xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
+    } else if (parent == NULL) {
+        parent = ctxt->myDoc->children;
+    }
+    ctxt->nodemem = -1;
+
+    /*
+     * We are parsing a new node.
+     */
+#ifdef DEBUG_SAX_TREE
+    xmlGenericError(xmlGenericErrorContext, "pushing(%s)\n", name);
+#endif
+    nodePush(ctxt, ret);
+
+    /*
+     * Link the child element
+     */
+    if (parent != NULL) {
+        if (parent->type == XML_ELEMENT_NODE) {
+#ifdef DEBUG_SAX_TREE
+	    xmlGenericError(xmlGenericErrorContext,
+		    "adding child %s to %s\n", name, parent->name);
+#endif
+	    xmlAddChild(parent, ret);
+	} else {
+#ifdef DEBUG_SAX_TREE
+	    xmlGenericError(xmlGenericErrorContext,
+		    "adding sibling %s to ", name);
+	    xmlDebugDumpOneNode(stderr, parent, 0);
+#endif
+	    xmlAddSibling(parent, ret);
+	}
+    }
+
+    /*
+     * process all the attributes whose name start with "xml"
+     */
+    if (atts != NULL) {
+        i = 0;
+	att = atts[i++];
+	value = atts[i++];
+	if (!ctxt->html) {
+	    while ((att != NULL) && (value != NULL)) {
+		if ((att[0] == 'x') && (att[1] == 'm') && (att[2] == 'l'))
+		    attribute(ctxt, att, value);
+
+		att = atts[i++];
+		value = atts[i++];
+	    }
+	}
+    }
+
+    /*
+     * Search the namespace, note that since the attributes have been
+     * processed, the local namespaces are available.
+     */
+    ns = xmlSearchNs(ctxt->myDoc, ret, prefix);
+    if ((ns == NULL) && (parent != NULL))
+	ns = xmlSearchNs(ctxt->myDoc, parent, prefix);
+    if ((prefix != NULL) && (ns == NULL)) {
+	ns = xmlNewNs(ret, NULL, prefix);
+	if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	    ctxt->sax->warning(ctxt->userData, 
+		 "Namespace prefix %s is not defined\n", prefix);
+    }
+    xmlSetNs(ret, ns);
+
+    /*
+     * process all the other attributes
+     */
+    if (atts != NULL) {
+        i = 0;
+	att = atts[i++];
+	value = atts[i++];
+	if (ctxt->html) {
+	    while (att != NULL) {
+		attribute(ctxt, att, value);
+		att = atts[i++];
+		value = atts[i++];
+	    }
+	} else {
+	    while ((att != NULL) && (value != NULL)) {
+		if ((att[0] != 'x') || (att[1] != 'm') || (att[2] != 'l'))
+		    attribute(ctxt, att, value);
+
+		/*
+		 * Next ones
+		 */
+		att = atts[i++];
+		value = atts[i++];
+	    }
+	}
+    }
+
+    /*
+     * If it's the Document root, finish the Dtd validation and
+     * check the document root element for validity
+     */
+    if ((ctxt->validate) && (ctxt->vctxt.finishDtd == 0)) {
+	ctxt->valid &= xmlValidateDtdFinal(&ctxt->vctxt, ctxt->myDoc);
+	ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
+	ctxt->vctxt.finishDtd = 1;
+    }
+
+    if (prefix != NULL)
+	xmlFree(prefix);
+    if (name != NULL)
+	xmlFree(name);
+
+}
+
+/**
+ * endElement:
+ * @ctx: the user data (XML parser context)
+ * @name:  The element name
+ *
+ * called when the end of an element has been detected.
+ */
+void
+endElement(void *ctx, const xmlChar *name)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlParserNodeInfo node_info;
+    xmlNodePtr cur = ctxt->node;
+
+#ifdef DEBUG_SAX
+    if (name == NULL)
+        xmlGenericError(xmlGenericErrorContext, "SAX.endElement(NULL)\n");
+    else
+	xmlGenericError(xmlGenericErrorContext, "SAX.endElement(%s)\n", name);
+#endif
+    
+    /* Capture end position and add node */
+    if (cur != NULL && ctxt->record_info) {
+      node_info.end_pos = ctxt->input->cur - ctxt->input->base;
+      node_info.end_line = ctxt->input->line;
+      node_info.node = cur;
+      xmlParserAddNodeInfo(ctxt, &node_info);
+    }
+    ctxt->nodemem = -1;
+
+    if (ctxt->validate && ctxt->wellFormed &&
+        ctxt->myDoc && ctxt->myDoc->intSubset)
+        ctxt->valid &= xmlValidateOneElement(&ctxt->vctxt, ctxt->myDoc,
+					     cur);
+
+    
+    /*
+     * end of parsing of this node.
+     */
+#ifdef DEBUG_SAX_TREE
+    xmlGenericError(xmlGenericErrorContext, "popping(%s)\n", cur->name);
+#endif
+    nodePop(ctxt);
+}
+
+/**
+ * reference:
+ * @ctx: the user data (XML parser context)
+ * @name:  The entity name
+ *
+ * called when an entity reference is detected. 
+ */
+void
+reference(void *ctx, const xmlChar *name)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr ret;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.reference(%s)\n", name);
+#endif
+    if (name[0] == '#')
+	ret = xmlNewCharRef(ctxt->myDoc, name);
+    else
+	ret = xmlNewReference(ctxt->myDoc, name);
+#ifdef DEBUG_SAX_TREE
+    xmlGenericError(xmlGenericErrorContext,
+	    "add reference %s to %s \n", name, ctxt->node->name);
+#endif
+    xmlAddChild(ctxt->node, ret);
+}
+
+/**
+ * characters:
+ * @ctx: the user data (XML parser context)
+ * @ch:  a xmlChar string
+ * @len: the number of xmlChar
+ *
+ * receiving some chars from the parser.
+ * Question: how much at a time ???
+ */
+void
+characters(void *ctx, const xmlChar *ch, int len)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr lastChild;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.characters(%.30s, %d)\n", ch, len);
+#endif
+    /*
+     * Handle the data if any. If there is no child
+     * add it as content, otherwise if the last child is text,
+     * concatenate it, else create a new node of type text.
+     */
+
+    if (ctxt->node == NULL) {
+#ifdef DEBUG_SAX_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"add chars: ctxt->node == NULL !\n");
+#endif
+        return;
+    }
+    lastChild = xmlGetLastChild(ctxt->node);
+#ifdef DEBUG_SAX_TREE
+    xmlGenericError(xmlGenericErrorContext,
+	    "add chars to %s \n", ctxt->node->name);
+#endif
+
+    /*
+     * Here we needed an accelerator mechanism in case of very large
+     * elements. Use an attribute in the structure !!!
+     */
+    if (lastChild == NULL) {
+	/* first node, first time */
+	xmlNodeAddContentLen(ctxt->node, ch, len);
+#ifndef XML_USE_BUFFER_CONTENT
+	if (ctxt->node->children != NULL) {
+	    ctxt->nodelen = len;
+	    ctxt->nodemem = len + 1;
+	}
+#endif
+    } else {
+	if ((xmlNodeIsText(lastChild)) && (ctxt->nodemem != 0)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    /*
+	     * The whole point of maintaining nodelen and nodemem,
+	     * xmlTextConcat is too costly, i.e. compute lenght,
+	     * reallocate a new buffer, move data, append ch. Here
+	     * We try to minimaze realloc() uses and avoid copying
+	     * and recomputing lenght over and over.
+	     */
+	    if (ctxt->nodelen + len >= ctxt->nodemem) {
+		xmlChar *newbuf;
+		int size;
+
+		size = ctxt->nodemem + len;
+		size *= 2;
+                newbuf = (xmlChar *) xmlRealloc(lastChild->content,size);
+		if (newbuf == NULL) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+			     "SAX.characters(): out of memory\n");
+		    return;
+		}
+		ctxt->nodemem = size;
+		lastChild->content = newbuf;
+	    }
+	    memcpy(&lastChild->content[ctxt->nodelen], ch, len);
+	    ctxt->nodelen += len;
+	    lastChild->content[ctxt->nodelen] = 0;
+#else
+	    xmlTextConcat(lastChild, ch, len);
+#endif
+	} else {
+	    /* Mixed content, first time */
+	    lastChild = xmlNewTextLen(ch, len);
+	    xmlAddChild(ctxt->node, lastChild);
+#ifndef XML_USE_BUFFER_CONTENT
+	    if (ctxt->node->children != NULL) {
+		ctxt->nodelen = len;
+		ctxt->nodemem = len + 1;
+	    }
+#endif
+	}
+    }
+}
+
+/**
+ * ignorableWhitespace:
+ * @ctx: the user data (XML parser context)
+ * @ch:  a xmlChar string
+ * @len: the number of xmlChar
+ *
+ * receiving some ignorable whitespaces from the parser.
+ * Question: how much at a time ???
+ */
+void
+ignorableWhitespace(void *ctx, const xmlChar *ch, int len)
+{
+    /* xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx; */
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.ignorableWhitespace(%.30s, %d)\n", ch, len);
+#endif
+}
+
+/**
+ * processingInstruction:
+ * @ctx: the user data (XML parser context)
+ * @target:  the target name
+ * @data: the PI data's
+ *
+ * A processing instruction has been parsed.
+ */
+void
+processingInstruction(void *ctx, const xmlChar *target,
+                      const xmlChar *data)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr ret;
+    xmlNodePtr parent = ctxt->node;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.processingInstruction(%s, %s)\n", target, data);
+#endif
+
+    ret = xmlNewPI(target, data);
+    if (ret == NULL) return;
+    parent = ctxt->node;
+
+    if (ctxt->inSubset == 1) {
+	xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
+	return;
+    } else if (ctxt->inSubset == 2) {
+	xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
+	return;
+    }
+    if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
+#ifdef DEBUG_SAX_TREE
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Setting PI %s as root\n", target);
+#endif
+        xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
+	return;
+    }
+    if (parent->type == XML_ELEMENT_NODE) {
+#ifdef DEBUG_SAX_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"adding PI %s child to %s\n", target, parent->name);
+#endif
+	xmlAddChild(parent, ret);
+    } else {
+#ifdef DEBUG_SAX_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"adding PI %s sibling to ", target);
+	xmlDebugDumpOneNode(stderr, parent, 0);
+#endif
+	xmlAddSibling(parent, ret);
+    }
+}
+
+/**
+ * globalNamespace:
+ * @ctx: the user data (XML parser context)
+ * @href:  the namespace associated URN
+ * @prefix: the namespace prefix
+ *
+ * An old global namespace has been parsed.
+ */
+void
+globalNamespace(void *ctx, const xmlChar *href, const xmlChar *prefix)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.globalNamespace(%s, %s)\n", href, prefix);
+#endif
+    xmlNewGlobalNs(ctxt->myDoc, href, prefix);
+}
+
+/**
+ * setNamespace:
+ * @ctx: the user data (XML parser context)
+ * @name:  the namespace prefix
+ *
+ * Set the current element namespace.
+ */
+
+void
+setNamespace(void *ctx, const xmlChar *name)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNsPtr ns;
+    xmlNodePtr parent;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext, "SAX.setNamespace(%s)\n", name);
+#endif
+    ns = xmlSearchNs(ctxt->myDoc, ctxt->node, name);
+    if (ns == NULL) { /* ctxt->node may not have a parent yet ! */
+        if (ctxt->nodeNr >= 2) {
+	    parent = ctxt->nodeTab[ctxt->nodeNr - 2];
+	    if (parent != NULL)
+		ns = xmlSearchNs(ctxt->myDoc, parent, name);
+	}
+    }
+    xmlSetNs(ctxt->node, ns);
+}
+
+/**
+ * getNamespace:
+ * @ctx: the user data (XML parser context)
+ *
+ * Get the current element namespace.
+ *
+ * Returns the xmlNsPtr or NULL if none
+ */
+
+xmlNsPtr
+getNamespace(void *ctx)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNsPtr ret;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext, "SAX.getNamespace()\n");
+#endif
+    ret = ctxt->node->ns;
+    return(ret);
+}
+
+/**
+ * checkNamespace:
+ * @ctx: the user data (XML parser context)
+ * @namespace: the namespace to check against
+ *
+ * Check that the current element namespace is the same as the
+ * one read upon parsing.
+ *
+ * Returns 1 if true 0 otherwise
+ */
+
+int
+checkNamespace(void *ctx, xmlChar *namespace)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr cur = ctxt->node;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.checkNamespace(%s)\n", namespace);
+#endif
+
+    /*
+     * Check that the Name in the ETag is the same as in the STag.
+     */
+    if (namespace == NULL) {
+        if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		 "End tags for %s don't hold the namespace %s\n",
+		                 cur->name, cur->ns->prefix);
+	    ctxt->wellFormed = 0;
+	}
+    } else {
+        if ((cur->ns == NULL) || (cur->ns->prefix == NULL)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+		 "End tags %s holds a prefix %s not used by the open tag\n",
+		                 cur->name, namespace);
+	    ctxt->wellFormed = 0;
+	} else if (!xmlStrEqual(namespace, cur->ns->prefix)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt, 
+    "Start and End tags for %s don't use the same namespaces: %s and %s\n",
+	                         cur->name, cur->ns->prefix, namespace);
+	    ctxt->wellFormed = 0;
+	} else
+	    return(1);
+    }
+    return(0);
+}
+
+/**
+ * namespaceDecl:
+ * @ctx: the user data (XML parser context)
+ * @href:  the namespace associated URN
+ * @prefix: the namespace prefix
+ *
+ * A namespace has been parsed.
+ */
+void
+namespaceDecl(void *ctx, const xmlChar *href, const xmlChar *prefix)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+#ifdef DEBUG_SAX
+    if (prefix == NULL)
+	xmlGenericError(xmlGenericErrorContext,
+		"SAX.namespaceDecl(%s, NULL)\n", href);
+    else
+	xmlGenericError(xmlGenericErrorContext,
+		"SAX.namespaceDecl(%s, %s)\n", href, prefix);
+#endif
+    xmlNewNs(ctxt->node, href, prefix);
+}
+
+/**
+ * comment:
+ * @ctx: the user data (XML parser context)
+ * @value:  the comment content
+ *
+ * A comment has been parsed.
+ */
+void
+comment(void *ctx, const xmlChar *value)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr ret;
+    xmlNodePtr parent = ctxt->node;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext, "SAX.comment(%s)\n", value);
+#endif
+    ret = xmlNewDocComment(ctxt->myDoc, value);
+    if (ret == NULL) return;
+
+    if (ctxt->inSubset == 1) {
+	xmlAddChild((xmlNodePtr) ctxt->myDoc->intSubset, ret);
+	return;
+    } else if (ctxt->inSubset == 2) {
+	xmlAddChild((xmlNodePtr) ctxt->myDoc->extSubset, ret);
+	return;
+    }
+    if ((ctxt->myDoc->children == NULL) || (parent == NULL)) {
+#ifdef DEBUG_SAX_TREE
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Setting comment as root\n");
+#endif
+        xmlAddChild((xmlNodePtr) ctxt->myDoc, (xmlNodePtr) ret);
+	return;
+    }
+    if (parent->type == XML_ELEMENT_NODE) {
+#ifdef DEBUG_SAX_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"adding comment child to %s\n", parent->name);
+#endif
+	xmlAddChild(parent, ret);
+    } else {
+#ifdef DEBUG_SAX_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"adding comment sibling to ");
+	xmlDebugDumpOneNode(stderr, parent, 0);
+#endif
+	xmlAddSibling(parent, ret);
+    }
+}
+
+/**
+ * cdataBlock:
+ * @ctx: the user data (XML parser context)
+ * @value:  The pcdata content
+ * @len:  the block length
+ *
+ * called when a pcdata block has been parsed
+ */
+void
+cdataBlock(void *ctx, const xmlChar *value, int len)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlNodePtr ret, lastChild;
+
+#ifdef DEBUG_SAX
+    xmlGenericError(xmlGenericErrorContext,
+	    "SAX.pcdata(%.10s, %d)\n", value, len);
+#endif
+    lastChild = xmlGetLastChild(ctxt->node);
+#ifdef DEBUG_SAX_TREE
+    xmlGenericError(xmlGenericErrorContext,
+	    "add chars to %s \n", ctxt->node->name);
+#endif
+    if ((lastChild != NULL) &&
+        (lastChild->type == XML_CDATA_SECTION_NODE)) {
+	xmlTextConcat(lastChild, value, len);
+    } else {
+	ret = xmlNewCDataBlock(ctxt->myDoc, value, len);
+	xmlAddChild(ctxt->node, ret);
+    }
+}
+
+/*
+ * Default handler for XML, builds the DOM tree
+ */
+xmlSAXHandler xmlDefaultSAXHandler = {
+    internalSubset,
+    isStandalone,
+    hasInternalSubset,
+    hasExternalSubset,
+    resolveEntity,
+    getEntity,
+    entityDecl,
+    notationDecl,
+    attributeDecl,
+    elementDecl,
+    unparsedEntityDecl,
+    setDocumentLocator,
+    startDocument,
+    endDocument,
+    startElement,
+    endElement,
+    reference,
+    characters,
+    ignorableWhitespace,
+    processingInstruction,
+    comment,
+    xmlParserWarning,
+    xmlParserError,
+    xmlParserError,
+    getParameterEntity,
+    cdataBlock,
+    externalSubset,
+};
+
+/**
+ * xmlDefaultSAXHandlerInit:
+ *
+ * Initialize the default SAX handler
+ */
+void
+xmlDefaultSAXHandlerInit(void)
+{
+    xmlDefaultSAXHandler.internalSubset = internalSubset;
+    xmlDefaultSAXHandler.externalSubset = externalSubset;
+    xmlDefaultSAXHandler.isStandalone = isStandalone;
+    xmlDefaultSAXHandler.hasInternalSubset = hasInternalSubset;
+    xmlDefaultSAXHandler.hasExternalSubset = hasExternalSubset;
+    xmlDefaultSAXHandler.resolveEntity = resolveEntity;
+    xmlDefaultSAXHandler.getEntity = getEntity;
+    xmlDefaultSAXHandler.getParameterEntity = getParameterEntity;
+    xmlDefaultSAXHandler.entityDecl = entityDecl;
+    xmlDefaultSAXHandler.attributeDecl = attributeDecl;
+    xmlDefaultSAXHandler.elementDecl = elementDecl;
+    xmlDefaultSAXHandler.notationDecl = notationDecl;
+    xmlDefaultSAXHandler.unparsedEntityDecl = unparsedEntityDecl;
+    xmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
+    xmlDefaultSAXHandler.startDocument = startDocument;
+    xmlDefaultSAXHandler.endDocument = endDocument;
+    xmlDefaultSAXHandler.startElement = startElement;
+    xmlDefaultSAXHandler.endElement = endElement;
+    xmlDefaultSAXHandler.reference = reference;
+    xmlDefaultSAXHandler.characters = characters;
+    xmlDefaultSAXHandler.cdataBlock = cdataBlock;
+    xmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
+    xmlDefaultSAXHandler.processingInstruction = processingInstruction;
+    xmlDefaultSAXHandler.comment = comment;
+    if (xmlGetWarningsDefaultValue == 0)
+	xmlDefaultSAXHandler.warning = NULL;
+    else
+	xmlDefaultSAXHandler.warning = xmlParserWarning;
+    xmlDefaultSAXHandler.error = xmlParserError;
+    xmlDefaultSAXHandler.fatalError = xmlParserError;
+}
+
+/*
+ * Default handler for HTML, builds the DOM tree
+ */
+xmlSAXHandler htmlDefaultSAXHandler = {
+    internalSubset,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    getEntity,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    setDocumentLocator,
+    startDocument,
+    endDocument,
+    startElement,
+    endElement,
+    NULL,
+    characters,
+    ignorableWhitespace,
+    NULL,
+    comment,
+    xmlParserWarning,
+    xmlParserError,
+    xmlParserError,
+    getParameterEntity,
+    cdataBlock,
+    NULL,
+};
+
+/**
+ * htmlDefaultSAXHandlerInit:
+ *
+ * Initialize the default SAX handler
+ */
+void
+htmlDefaultSAXHandlerInit(void)
+{
+    htmlDefaultSAXHandler.internalSubset = internalSubset;
+    htmlDefaultSAXHandler.externalSubset = NULL;
+    htmlDefaultSAXHandler.isStandalone = NULL;
+    htmlDefaultSAXHandler.hasInternalSubset = NULL;
+    htmlDefaultSAXHandler.hasExternalSubset = NULL;
+    htmlDefaultSAXHandler.resolveEntity = NULL;
+    htmlDefaultSAXHandler.getEntity = getEntity;
+    htmlDefaultSAXHandler.getParameterEntity = NULL;
+    htmlDefaultSAXHandler.entityDecl = NULL;
+    htmlDefaultSAXHandler.attributeDecl = NULL;
+    htmlDefaultSAXHandler.elementDecl = NULL;
+    htmlDefaultSAXHandler.notationDecl = NULL;
+    htmlDefaultSAXHandler.unparsedEntityDecl = NULL;
+    htmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
+    htmlDefaultSAXHandler.startDocument = startDocument;
+    htmlDefaultSAXHandler.endDocument = endDocument;
+    htmlDefaultSAXHandler.startElement = startElement;
+    htmlDefaultSAXHandler.endElement = endElement;
+    htmlDefaultSAXHandler.reference = NULL;
+    htmlDefaultSAXHandler.characters = characters;
+    htmlDefaultSAXHandler.cdataBlock = cdataBlock;
+    htmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
+    htmlDefaultSAXHandler.processingInstruction = NULL;
+    htmlDefaultSAXHandler.comment = comment;
+    htmlDefaultSAXHandler.warning = xmlParserWarning;
+    htmlDefaultSAXHandler.error = xmlParserError;
+    htmlDefaultSAXHandler.fatalError = xmlParserError;
+}
+
+/*
+ * Default handler for HTML, builds the DOM tree
+ */
+xmlSAXHandler sgmlDefaultSAXHandler = {
+    internalSubset,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    getEntity,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    NULL,
+    setDocumentLocator,
+    startDocument,
+    endDocument,
+    startElement,
+    endElement,
+    NULL,
+    characters,
+    ignorableWhitespace,
+    NULL,
+    comment,
+    xmlParserWarning,
+    xmlParserError,
+    xmlParserError,
+    getParameterEntity,
+    NULL,
+    NULL,
+};
+
+/**
+ * sgmlDefaultSAXHandlerInit:
+ *
+ * Initialize the default SAX handler
+ */
+void
+sgmlDefaultSAXHandlerInit(void)
+{
+    sgmlDefaultSAXHandler.internalSubset = internalSubset;
+    sgmlDefaultSAXHandler.externalSubset = NULL;
+    sgmlDefaultSAXHandler.isStandalone = NULL;
+    sgmlDefaultSAXHandler.hasInternalSubset = NULL;
+    sgmlDefaultSAXHandler.hasExternalSubset = NULL;
+    sgmlDefaultSAXHandler.resolveEntity = NULL;
+    sgmlDefaultSAXHandler.getEntity = getEntity;
+    sgmlDefaultSAXHandler.getParameterEntity = NULL;
+    sgmlDefaultSAXHandler.entityDecl = NULL;
+    sgmlDefaultSAXHandler.attributeDecl = NULL;
+    sgmlDefaultSAXHandler.elementDecl = NULL;
+    sgmlDefaultSAXHandler.notationDecl = NULL;
+    sgmlDefaultSAXHandler.unparsedEntityDecl = NULL;
+    sgmlDefaultSAXHandler.setDocumentLocator = setDocumentLocator;
+    sgmlDefaultSAXHandler.startDocument = startDocument;
+    sgmlDefaultSAXHandler.endDocument = endDocument;
+    sgmlDefaultSAXHandler.startElement = startElement;
+    sgmlDefaultSAXHandler.endElement = endElement;
+    sgmlDefaultSAXHandler.reference = NULL;
+    sgmlDefaultSAXHandler.characters = characters;
+    sgmlDefaultSAXHandler.cdataBlock = NULL;
+    sgmlDefaultSAXHandler.ignorableWhitespace = ignorableWhitespace;
+    sgmlDefaultSAXHandler.processingInstruction = NULL;
+    sgmlDefaultSAXHandler.comment = comment;
+    sgmlDefaultSAXHandler.warning = xmlParserWarning;
+    sgmlDefaultSAXHandler.error = xmlParserError;
+    sgmlDefaultSAXHandler.fatalError = xmlParserError;
+}
diff --git a/SAX.h b/SAX.h
new file mode 100644
index 0000000..4fabbdf
--- /dev/null
+++ b/SAX.h
@@ -0,0 +1,120 @@
+/*
+ * SAX.h : Default SAX handler interfaces.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+
+#ifndef __XML_SAX_H__
+#define __XML_SAX_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libxml/parser.h>
+#include <libxml/xlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+const xmlChar *	getPublicId			(void *ctx);
+const xmlChar *	getSystemId			(void *ctx);
+void	setDocumentLocator			(void *ctx,
+						 xmlSAXLocatorPtr loc);
+    
+int		getLineNumber			(void *ctx);
+int		getColumnNumber			(void *ctx);
+
+int		isStandalone			(void *ctx);
+int		hasInternalSubset		(void *ctx);
+int		hasExternalSubset		(void *ctx);
+
+void		internalSubset			(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID);
+void		externalSubset			(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID);
+xmlEntityPtr	getEntity			(void *ctx,
+						 const xmlChar *name);
+xmlEntityPtr	getParameterEntity		(void *ctx,
+						 const xmlChar *name);
+xmlParserInputPtr resolveEntity			(void *ctx,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId);
+
+void		entityDecl			(void *ctx,
+						 const xmlChar *name,
+						 int type,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId,
+						 xmlChar *content);
+void		attributeDecl			(void *ctx,
+						 const xmlChar *elem,
+						 const xmlChar *name,
+						 int type,
+						 int def,
+						 const xmlChar *defaultValue,
+						 xmlEnumerationPtr tree);
+void		elementDecl			(void *ctx,
+						 const xmlChar *name,
+						 int type,
+						 xmlElementContentPtr content);
+void		notationDecl			(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId);
+void		unparsedEntityDecl		(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId,
+						 const xmlChar *notationName);
+
+void		startDocument			(void *ctx);
+void		endDocument			(void *ctx);
+void		attribute			(void *ctx,
+						 const xmlChar *fullname,
+						 const xmlChar *value);
+void		startElement			(void *ctx,
+						 const xmlChar *fullname,
+						 const xmlChar **atts);
+void		endElement			(void *ctx,
+						 const xmlChar *name);
+void		reference			(void *ctx,
+						 const xmlChar *name);
+void		characters			(void *ctx,
+						 const xmlChar *ch,
+						 int len);
+void		ignorableWhitespace		(void *ctx,
+						 const xmlChar *ch,
+						 int len);
+void		processingInstruction		(void *ctx,
+						 const xmlChar *target,
+						 const xmlChar *data);
+void		globalNamespace			(void *ctx,
+						 const xmlChar *href,
+						 const xmlChar *prefix);
+void		setNamespace			(void *ctx,
+						 const xmlChar *name);
+xmlNsPtr	getNamespace			(void *ctx);
+int		checkNamespace			(void *ctx,
+						 xmlChar *nameSpace);
+void		namespaceDecl			(void *ctx,
+						 const xmlChar *href,
+						 const xmlChar *prefix);
+void		comment				(void *ctx,
+						 const xmlChar *value);
+void		cdataBlock			(void *ctx,
+						 const xmlChar *value,
+						 int len);
+
+void		xmlDefaultSAXHandlerInit	(void);
+void		htmlDefaultSAXHandlerInit	(void);
+void		sgmlDefaultSAXHandlerInit	(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_SAX_H__ */
diff --git a/autogen.sh b/autogen.sh
index 28088eb..e5a30eb 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -36,7 +36,7 @@
 	exit 1
 fi
 
-test -f libxml/entities.h || {
+test -f entities.h || {
 	echo "You must run this script in the top-level libxml directory"
 	exit 1
 }
diff --git a/configure.in b/configure.in
index 13dd7df..a505a80 100644
--- a/configure.in
+++ b/configure.in
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 AC_PREREQ(2.2)
-AC_INIT(libxml/entities.c)
+AC_INIT(entities.c)
 AM_CONFIG_HEADER(config.h)
 AC_CANONICAL_HOST
 
@@ -42,10 +42,32 @@
 AM_MAINTAINER_MODE
 
 dnl Checks for zlib library.
-AC_CHECK_HEADERS(zlib.h,
-    AC_CHECK_LIB(z, gzread, [AC_DEFINE(HAVE_LIBZ) LIBS="$LIBS -lz"])
-)
+_cppflags="${CPPFLAGS}"
+_ldflags="${LDFLAGS}"
 
+AC_ARG_WITH(zlib,
+[  --with-zlib[=DIR]       use libz in DIR],[
+  if test "$withval" != "no" -a "$withval" != "yes"; then
+    Z_DIR=$withval
+    CPPFLAGS="${CPPFLAGS} -I$withval/include"
+    LDFLAGS="${LDFLAGS} -L$withval/lib"
+  fi
+])
+
+AC_CHECK_HEADERS(zlib.h,
+    AC_CHECK_LIB(z, gzread,[
+	AC_DEFINE(HAVE_LIBZ)
+        if test "x${Z_DIR}" != "x"; then
+            Z_CFLAGS="-I${Z_DIR}/include"
+            Z_LIBS="-L${Z_DIR}/lib -lz"
+        else
+            Z_LIBS="-lz"
+        fi]))
+AC_SUBST(Z_CFLAGS)
+AC_SUBST(Z_LIBS)
+
+CPPFLAGS=${_cppflags}
+LDFLAGS=${_ldflags}
 
 dnl Checks for header files.
 AC_HEADER_DIRENT
@@ -343,15 +365,37 @@
 AC_SUBST(M_LIBS)
 AC_SUBST(RDL_LIBS)
 
-AC_OUTPUT([
-    Makefile
-    libxml/Makefile
-    libxml/xmlversion.h
-    libxml/xml2-config
-    libxml/libxml-2.0.pc
-    libxml/xml2Conf.sh
-    doc/Makefile
-    example/Makefile
-    libxml.spec
-])
+dnl
+dnl create the libxml and include links needed to get dependencies right
+dnl
+if test ! -d $srcdir/include/libxml
+then
+    if test ! -d $srcdir/include
+    then
+        rm -f $srcdir/include
+        mkdir $srcdir/include
+    fi
+    rm -f $srcdir/libxml
+    (cd $srcdir/include ; ln -s .. libxml)
+fi
+if test ! -r $srcdir/libxml
+then
+    (cd $srcdir ; ln -s include/libxml libxml)
+fi
+if test ! -r include/libxml
+then
+    if test ! -d include
+    then
+        rm -f include
+        mkdir include
+    fi
+    (cd include ; ln -s ../libxml libxml)
+fi
+if test ! -r libxml
+then
+    rm -rf libxml
+    ln -s $srcdir/include/libxml libxml
+fi
+
+AC_OUTPUT(libxml.spec Makefile include/Makefile doc/Makefile example/Makefile libxml/xmlversion.h xml2-config libxml-2.0.pc xml2Conf.sh)
 
diff --git a/debugXML.c b/debugXML.c
new file mode 100644
index 0000000..65d703d
--- /dev/null
+++ b/debugXML.c
@@ -0,0 +1,1888 @@
+/*
+ * debugXML.c : This is a set of routines used for debugging the tree
+ *              produced by the XML parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_DEBUG_ENABLED
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/valid.h>
+#include <libxml/debugXML.h>
+#include <libxml/HTMLtree.h>
+#include <libxml/HTMLparser.h>
+#include <libxml/xmlerror.h>
+
+#define IS_BLANK(c)							\
+  (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
+
+void xmlDebugDumpString(FILE *output, const xmlChar *str) {
+    int i;
+    if (str == NULL) {
+	fprintf(output, "(NULL)");
+	return;
+    }
+    for (i = 0;i < 40;i++)
+        if (str[i] == 0) return;
+	else if (IS_BLANK(str[i])) fputc(' ', output);
+	else if (str[i] >= 0x80)
+	     fprintf(output, "#%X", str[i]);
+	else fputc(str[i], output);
+    fprintf(output, "...");
+}
+
+void xmlDebugDumpDtd(FILE *output, xmlDtdPtr dtd, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    if (dtd->type != XML_DTD_NODE) {
+	fprintf(output, "PBM: not a DTD\n");
+	return;
+    }
+    if (dtd->name != NULL)
+	fprintf(output, "DTD(%s)", dtd->name);
+    else
+	fprintf(output, "DTD");
+    if (dtd->ExternalID != NULL)
+	fprintf(output, ", PUBLIC %s", dtd->ExternalID);
+    if (dtd->SystemID != NULL)
+	fprintf(output, ", SYSTEM %s", dtd->SystemID);
+    fprintf(output, "\n");
+    /*
+     * Do a bit of checking
+     */
+    if (dtd->parent == NULL)
+	fprintf(output, "PBM: Dtd has no parent\n");
+    if (dtd->doc == NULL)
+	fprintf(output, "PBM: Dtd has no doc\n");
+    if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
+	fprintf(output, "PBM: Dtd doc differs from parent's one\n");
+    if (dtd->prev == NULL) {
+	if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
+	    fprintf(output, "PBM: Dtd has no prev and not first of list\n");
+    } else {
+	if (dtd->prev->next != (xmlNodePtr) dtd)
+	    fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
+    }
+    if (dtd->next == NULL) {
+	if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
+	    fprintf(output, "PBM: Dtd has no next and not last of list\n");
+    } else {
+	if (dtd->next->prev != (xmlNodePtr) dtd)
+	    fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
+    }
+}
+
+void xmlDebugDumpAttrDecl(FILE *output, xmlAttributePtr attr, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    if (attr->type != XML_ATTRIBUTE_DECL) {
+	fprintf(output, "PBM: not a Attr\n");
+	return;
+    }
+    if (attr->name != NULL)
+	fprintf(output, "ATTRDECL(%s)", attr->name);
+    else
+	fprintf(output, "PBM ATTRDECL noname!!!");
+    if (attr->elem != NULL)
+	fprintf(output, " for %s", attr->elem);
+    else
+	fprintf(output, " PBM noelem!!!");
+    switch (attr->atype) {
+        case XML_ATTRIBUTE_CDATA:
+	    fprintf(output, " CDATA");
+	    break;
+        case XML_ATTRIBUTE_ID:
+	    fprintf(output, " ID");
+	    break;
+        case XML_ATTRIBUTE_IDREF:
+	    fprintf(output, " IDREF");
+	    break;
+        case XML_ATTRIBUTE_IDREFS:
+	    fprintf(output, " IDREFS");
+	    break;
+        case XML_ATTRIBUTE_ENTITY:
+	    fprintf(output, " ENTITY");
+	    break;
+        case XML_ATTRIBUTE_ENTITIES:
+	    fprintf(output, " ENTITIES");
+	    break;
+        case XML_ATTRIBUTE_NMTOKEN:
+	    fprintf(output, " NMTOKEN");
+	    break;
+        case XML_ATTRIBUTE_NMTOKENS:
+	    fprintf(output, " NMTOKENS");
+	    break;
+        case XML_ATTRIBUTE_ENUMERATION:
+	    fprintf(output, " ENUMERATION");
+	    break;
+        case XML_ATTRIBUTE_NOTATION:
+	    fprintf(output, " NOTATION ");
+	    break;
+    }
+    if (attr->tree != NULL) {
+	int i;
+	xmlEnumerationPtr cur = attr->tree;
+
+	for (i = 0;i < 5; i++) {
+	    if (i != 0)
+		fprintf(output, "|%s", cur->name);
+	    else
+		fprintf(output, " (%s", cur->name);
+	    cur = cur->next;
+	    if (cur == NULL) break;
+	}
+	if (cur == NULL)
+	    fprintf(output, ")");
+	else
+	    fprintf(output, "...)");
+    }
+    switch (attr->def) {
+        case XML_ATTRIBUTE_NONE:
+	    break;
+        case XML_ATTRIBUTE_REQUIRED:
+	    fprintf(output, " REQUIRED");
+	    break;
+        case XML_ATTRIBUTE_IMPLIED:
+	    fprintf(output, " IMPLIED");
+	    break;
+        case XML_ATTRIBUTE_FIXED:
+	    fprintf(output, " FIXED");
+	    break;
+    }
+    if (attr->defaultValue != NULL) {
+	fprintf(output, "\"");
+	xmlDebugDumpString(output, attr->defaultValue);
+	fprintf(output, "\"");
+    }
+    printf("\n");
+
+    /*
+     * Do a bit of checking
+     */
+    if (attr->parent == NULL)
+	fprintf(output, "PBM: Attr has no parent\n");
+    if (attr->doc == NULL)
+	fprintf(output, "PBM: Attr has no doc\n");
+    if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
+	fprintf(output, "PBM: Attr doc differs from parent's one\n");
+    if (attr->prev == NULL) {
+	if ((attr->parent != NULL) && (attr->parent->children != (xmlNodePtr)attr))
+	    fprintf(output, "PBM: Attr has no prev and not first of list\n");
+    } else {
+	if (attr->prev->next != (xmlNodePtr) attr)
+	    fprintf(output, "PBM: Attr prev->next : back link wrong\n");
+    }
+    if (attr->next == NULL) {
+	if ((attr->parent != NULL) && (attr->parent->last != (xmlNodePtr) attr))
+	    fprintf(output, "PBM: Attr has no next and not last of list\n");
+    } else {
+	if (attr->next->prev != (xmlNodePtr) attr)
+	    fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
+    }
+}
+
+void xmlDebugDumpElemDecl(FILE *output, xmlElementPtr elem, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    if (elem->type != XML_ELEMENT_DECL) {
+	fprintf(output, "PBM: not a Elem\n");
+	return;
+    }
+    if (elem->name != NULL) {
+	fprintf(output, "ELEMDECL(");
+	xmlDebugDumpString(output, elem->name);
+	fprintf(output, ")");
+    } else
+	fprintf(output, "PBM ELEMDECL noname!!!");
+    switch (elem->etype) {
+	case XML_ELEMENT_TYPE_EMPTY: 
+	    fprintf(output, ", EMPTY");
+	    break;
+	case XML_ELEMENT_TYPE_ANY: 
+	    fprintf(output, ", ANY");
+	    break;
+	case XML_ELEMENT_TYPE_MIXED: 
+	    fprintf(output, ", MIXED ");
+	    break;
+	case XML_ELEMENT_TYPE_ELEMENT: 
+	    fprintf(output, ", MIXED ");
+	    break;
+    }
+    if (elem->content != NULL) {
+	char buf[5001];
+
+	buf[0] = 0;
+	xmlSprintfElementContent(buf, elem->content, 1);
+	buf[5000] = 0;
+	fprintf(output, "%s", buf);
+    }
+    printf("\n");
+
+    /*
+     * Do a bit of checking
+     */
+    if (elem->parent == NULL)
+	fprintf(output, "PBM: Elem has no parent\n");
+    if (elem->doc == NULL)
+	fprintf(output, "PBM: Elem has no doc\n");
+    if ((elem->parent != NULL) && (elem->doc != elem->parent->doc))
+	fprintf(output, "PBM: Elem doc differs from parent's one\n");
+    if (elem->prev == NULL) {
+	if ((elem->parent != NULL) && (elem->parent->children != (xmlNodePtr)elem))
+	    fprintf(output, "PBM: Elem has no prev and not first of list\n");
+    } else {
+	if (elem->prev->next != (xmlNodePtr) elem)
+	    fprintf(output, "PBM: Elem prev->next : back link wrong\n");
+    }
+    if (elem->next == NULL) {
+	if ((elem->parent != NULL) && (elem->parent->last != (xmlNodePtr) elem))
+	    fprintf(output, "PBM: Elem has no next and not last of list\n");
+    } else {
+	if (elem->next->prev != (xmlNodePtr) elem)
+	    fprintf(output, "PBM: Elem next->prev : forward link wrong\n");
+    }
+}
+
+void xmlDebugDumpEntityDecl(FILE *output, xmlEntityPtr ent, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    if (ent->type != XML_ENTITY_DECL) {
+	fprintf(output, "PBM: not a Entity decl\n");
+	return;
+    }
+    if (ent->name != NULL) {
+	fprintf(output, "ENTITYDECL(");
+	xmlDebugDumpString(output, ent->name);
+	fprintf(output, ")");
+    } else
+	fprintf(output, "PBM ENTITYDECL noname!!!");
+    switch (ent->etype) {
+	case XML_INTERNAL_GENERAL_ENTITY: 
+	    fprintf(output, ", internal\n");
+	    break;
+	case XML_EXTERNAL_GENERAL_PARSED_ENTITY: 
+	    fprintf(output, ", external parsed\n");
+	    break;
+	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY: 
+	    fprintf(output, ", unparsed\n");
+	    break;
+	case XML_INTERNAL_PARAMETER_ENTITY: 
+	    fprintf(output, ", parameter\n");
+	    break;
+	case XML_EXTERNAL_PARAMETER_ENTITY: 
+	    fprintf(output, ", external parameter\n");
+	    break;
+	case XML_INTERNAL_PREDEFINED_ENTITY: 
+	    fprintf(output, ", predefined\n");
+	    break;
+    }
+    if (ent->ExternalID) {
+        fprintf(output, shift);
+        fprintf(output, " ExternalID=%s\n", ent->ExternalID);
+    }
+    if (ent->SystemID) {
+        fprintf(output, shift);
+        fprintf(output, " SystemID=%s\n", ent->SystemID);
+    }
+    if (ent->URI != NULL) {
+        fprintf(output, shift);
+        fprintf(output, " URI=%s\n", ent->URI);
+    }
+    if (ent->content) {
+        fprintf(output, shift);
+	fprintf(output, " content=");
+	xmlDebugDumpString(output, ent->content);
+	fprintf(output, "\n");
+    }
+
+    /*
+     * Do a bit of checking
+     */
+    if (ent->parent == NULL)
+	fprintf(output, "PBM: Ent has no parent\n");
+    if (ent->doc == NULL)
+	fprintf(output, "PBM: Ent has no doc\n");
+    if ((ent->parent != NULL) && (ent->doc != ent->parent->doc))
+	fprintf(output, "PBM: Ent doc differs from parent's one\n");
+    if (ent->prev == NULL) {
+	if ((ent->parent != NULL) && (ent->parent->children != (xmlNodePtr)ent))
+	    fprintf(output, "PBM: Ent has no prev and not first of list\n");
+    } else {
+	if (ent->prev->next != (xmlNodePtr) ent)
+	    fprintf(output, "PBM: Ent prev->next : back link wrong\n");
+    }
+    if (ent->next == NULL) {
+	if ((ent->parent != NULL) && (ent->parent->last != (xmlNodePtr) ent))
+	    fprintf(output, "PBM: Ent has no next and not last of list\n");
+    } else {
+	if (ent->next->prev != (xmlNodePtr) ent)
+	    fprintf(output, "PBM: Ent next->prev : forward link wrong\n");
+    }
+}
+
+void xmlDebugDumpNamespace(FILE *output, xmlNsPtr ns, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+    if (ns->type != XML_NAMESPACE_DECL) {
+        fprintf(output, "invalid namespace node %d\n", ns->type);
+	return;
+    }
+    if (ns->href == NULL) {
+	if (ns->prefix != NULL)
+	    fprintf(output, "incomplete namespace %s href=NULL\n", ns->prefix);
+	else
+	    fprintf(output, "incomplete default namespace href=NULL\n");
+    } else {
+	if (ns->prefix != NULL)
+	    fprintf(output, "namespace %s href=", ns->prefix);
+	else
+	    fprintf(output, "default namespace href=");
+
+	xmlDebugDumpString(output, ns->href);
+	fprintf(output, "\n");
+    }
+}
+
+void xmlDebugDumpNamespaceList(FILE *output, xmlNsPtr ns, int depth) {
+    while (ns != NULL) {
+        xmlDebugDumpNamespace(output, ns, depth);
+	ns = ns->next;
+    }
+}
+
+void xmlDebugDumpEntity(FILE *output, xmlEntityPtr ent, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+    switch (ent->etype) {
+        case XML_INTERNAL_GENERAL_ENTITY:
+	    fprintf(output, "INTERNAL_GENERAL_ENTITY ");
+	    break;
+        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+	    fprintf(output, "EXTERNAL_GENERAL_PARSED_ENTITY ");
+	    break;
+        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+	    fprintf(output, "EXTERNAL_GENERAL_UNPARSED_ENTITY ");
+	    break;
+        case XML_INTERNAL_PARAMETER_ENTITY:
+	    fprintf(output, "INTERNAL_PARAMETER_ENTITY ");
+	    break;
+        case XML_EXTERNAL_PARAMETER_ENTITY:
+	    fprintf(output, "EXTERNAL_PARAMETER_ENTITY ");
+	    break;
+	default:
+	    fprintf(output, "ENTITY_%d ! ", ent->etype);
+    }
+    fprintf(output, "%s\n", ent->name);
+    if (ent->ExternalID) {
+        fprintf(output, shift);
+        fprintf(output, "ExternalID=%s\n", ent->ExternalID);
+    }
+    if (ent->SystemID) {
+        fprintf(output, shift);
+        fprintf(output, "SystemID=%s\n", ent->SystemID);
+    }
+    if (ent->URI) {
+        fprintf(output, shift);
+        fprintf(output, "URI=%s\n", ent->URI);
+    }
+    if (ent->content) {
+        fprintf(output, shift);
+	fprintf(output, "content=");
+	xmlDebugDumpString(output, ent->content);
+	fprintf(output, "\n");
+    }
+}
+
+void xmlDebugDumpAttr(FILE *output, xmlAttrPtr attr, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    fprintf(output, "ATTRIBUTE ");
+    xmlDebugDumpString(output, attr->name);
+    fprintf(output, "\n");
+    if (attr->children != NULL) 
+        xmlDebugDumpNodeList(output, attr->children, depth + 1);
+
+    /*
+     * Do a bit of checking
+     */
+    if (attr->parent == NULL)
+	fprintf(output, "PBM: Attr has no parent\n");
+    if (attr->doc == NULL)
+	fprintf(output, "PBM: Attr has no doc\n");
+    if ((attr->parent != NULL) && (attr->doc != attr->parent->doc))
+	fprintf(output, "PBM: Attr doc differs from parent's one\n");
+    if (attr->prev == NULL) {
+	if ((attr->parent != NULL) && (attr->parent->properties != attr))
+	    fprintf(output, "PBM: Attr has no prev and not first of list\n");
+    } else {
+	if (attr->prev->next != attr)
+	    fprintf(output, "PBM: Attr prev->next : back link wrong\n");
+    }
+    if (attr->next != NULL) {
+	if (attr->next->prev != attr)
+	    fprintf(output, "PBM: Attr next->prev : forward link wrong\n");
+    }
+}
+
+void xmlDebugDumpAttrList(FILE *output, xmlAttrPtr attr, int depth) {
+    while (attr != NULL) {
+        xmlDebugDumpAttr(output, attr, depth);
+	attr = attr->next;
+    }
+}
+
+void xmlDebugDumpOneNode(FILE *output, xmlNodePtr node, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    switch (node->type) {
+	case XML_ELEMENT_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "ELEMENT ");
+	    if ((node->ns != NULL) && (node->ns->prefix != NULL)) {
+		xmlDebugDumpString(output, node->ns->prefix);
+	        fprintf(output, ":");
+	    }
+	    xmlDebugDumpString(output, node->name);
+	    fprintf(output, "\n");
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "Error, ATTRIBUTE found here\n");
+	    break;
+	case XML_TEXT_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "TEXT\n");
+	    break;
+	case XML_CDATA_SECTION_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "CDATA_SECTION\n");
+	    break;
+	case XML_ENTITY_REF_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "ENTITY_REF(%s)\n", node->name);
+	    break;
+	case XML_ENTITY_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "ENTITY\n");
+	    break;
+	case XML_PI_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "PI %s\n", node->name);
+	    break;
+	case XML_COMMENT_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "COMMENT\n");
+	    break;
+	case XML_DOCUMENT_NODE:
+	case XML_HTML_DOCUMENT_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "Error, DOCUMENT found here\n");
+	    break;
+	case XML_DOCUMENT_TYPE_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "DOCUMENT_TYPE\n");
+	    break;
+	case XML_DOCUMENT_FRAG_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "DOCUMENT_FRAG\n");
+	    break;
+	case XML_NOTATION_NODE:
+	    fprintf(output, shift);
+	    fprintf(output, "NOTATION\n");
+	    break;
+	case XML_DTD_NODE:
+	    xmlDebugDumpDtd(output, (xmlDtdPtr) node, depth);
+	    return;
+	case XML_ELEMENT_DECL:
+	    xmlDebugDumpElemDecl(output, (xmlElementPtr) node, depth);
+	    return;
+	case XML_ATTRIBUTE_DECL:
+	    xmlDebugDumpAttrDecl(output, (xmlAttributePtr) node, depth);
+	    return;
+        case XML_ENTITY_DECL:
+	    xmlDebugDumpEntityDecl(output, (xmlEntityPtr) node, depth);
+	    return;
+        case XML_NAMESPACE_DECL:
+	    xmlDebugDumpNamespace(output, (xmlNsPtr) node, depth);
+	    return;
+        case XML_XINCLUDE_START:
+	    fprintf(output, shift);
+	    fprintf(output, "INCLUDE START\n");
+	    return;
+        case XML_XINCLUDE_END:
+	    fprintf(output, shift);
+	    fprintf(output, "INCLUDE END\n");
+	    return;
+	default:
+	    fprintf(output, shift);
+	    fprintf(output, "NODE_%d !!!\n", node->type);
+	    return;
+    }
+    if (node->doc == NULL) {
+        fprintf(output, shift);
+	fprintf(output, "doc == NULL !!!\n");
+    }
+    if (node->nsDef != NULL) 
+        xmlDebugDumpNamespaceList(output, node->nsDef, depth + 1);
+    if (node->properties != NULL)
+	xmlDebugDumpAttrList(output, node->properties, depth + 1);
+    if (node->type != XML_ENTITY_REF_NODE) {
+	if (node->content != NULL) {
+            shift[2 * i] = shift[2 * i + 1] = ' ' ;
+            shift[2 * i + 2] = shift[2 * i + 3] = 0 ;
+	    fprintf(output, shift);
+	    fprintf(output, "content=");
+#ifndef XML_USE_BUFFER_CONTENT	    
+	    xmlDebugDumpString(output, node->content);
+#else
+	    xmlDebugDumpString(output, xmlBufferContent(node->content));
+#endif
+	    fprintf(output, "\n");
+	}
+    } else {
+        xmlEntityPtr ent;
+	ent = xmlGetDocEntity(node->doc, node->name);
+	if (ent != NULL)
+	    xmlDebugDumpEntity(output, ent, depth + 1);
+    }
+    /*
+     * Do a bit of checking
+     */
+    if (node->parent == NULL)
+	fprintf(output, "PBM: Node has no parent\n");
+    if (node->doc == NULL)
+	fprintf(output, "PBM: Node has no doc\n");
+    if ((node->parent != NULL) && (node->doc != node->parent->doc))
+	fprintf(output, "PBM: Node doc differs from parent's one\n");
+    if (node->prev == NULL) {
+	if ((node->parent != NULL) && (node->parent->children != node))
+	    fprintf(output, "PBM: Node has no prev and not first of list\n");
+    } else {
+	if (node->prev->next != node)
+	    fprintf(output, "PBM: Node prev->next : back link wrong\n");
+    }
+    if (node->next == NULL) {
+	if ((node->parent != NULL) && (node->parent->last != node))
+	    fprintf(output, "PBM: Node has no next and not last of list\n");
+    } else {
+	if (node->next->prev != node)
+	    fprintf(output, "PBM: Node next->prev : forward link wrong\n");
+    }
+}
+
+void xmlDebugDumpNode(FILE *output, xmlNodePtr node, int depth) {
+    xmlDebugDumpOneNode(output, node, depth);
+    if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE))
+	xmlDebugDumpNodeList(output, node->children, depth + 1);
+}
+
+void xmlDebugDumpNodeList(FILE *output, xmlNodePtr node, int depth) {
+    while (node != NULL) {
+        xmlDebugDumpNode(output, node, depth);
+	node = node->next;
+    }
+}
+
+
+void xmlDebugDumpDocumentHead(FILE *output, xmlDocPtr doc) {
+    if (output == NULL) output = stdout;
+    if (doc == NULL) {
+        fprintf(output, "DOCUMENT == NULL !\n");
+	return;
+    }
+
+    switch (doc->type) {
+	case XML_ELEMENT_NODE:
+	    fprintf(output, "Error, ELEMENT found here ");
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    fprintf(output, "Error, ATTRIBUTE found here\n");
+	    break;
+	case XML_TEXT_NODE:
+	    fprintf(output, "Error, TEXT\n");
+	    break;
+	case XML_CDATA_SECTION_NODE:
+	    fprintf(output, "Error, CDATA_SECTION\n");
+	    break;
+	case XML_ENTITY_REF_NODE:
+	    fprintf(output, "Error, ENTITY_REF\n");
+	    break;
+	case XML_ENTITY_NODE:
+	    fprintf(output, "Error, ENTITY\n");
+	    break;
+	case XML_PI_NODE:
+	    fprintf(output, "Error, PI\n");
+	    break;
+	case XML_COMMENT_NODE:
+	    fprintf(output, "Error, COMMENT\n");
+	    break;
+	case XML_DOCUMENT_NODE:
+	    fprintf(output, "DOCUMENT\n");
+	    break;
+	case XML_HTML_DOCUMENT_NODE:
+	    fprintf(output, "HTML DOCUMENT\n");
+	    break;
+	case XML_DOCUMENT_TYPE_NODE:
+	    fprintf(output, "Error, DOCUMENT_TYPE\n");
+	    break;
+	case XML_DOCUMENT_FRAG_NODE:
+	    fprintf(output, "Error, DOCUMENT_FRAG\n");
+	    break;
+	case XML_NOTATION_NODE:
+	    fprintf(output, "Error, NOTATION\n");
+	    break;
+	default:
+	    fprintf(output, "NODE_%d\n", doc->type);
+    }
+    if (doc->name != NULL) {
+	fprintf(output, "name=");
+        xmlDebugDumpString(output, BAD_CAST doc->name);
+	fprintf(output, "\n");
+    }
+    if (doc->version != NULL) {
+	fprintf(output, "version=");
+        xmlDebugDumpString(output, doc->version);
+	fprintf(output, "\n");
+    }
+    if (doc->encoding != NULL) {
+	fprintf(output, "encoding=");
+        xmlDebugDumpString(output, doc->encoding);
+	fprintf(output, "\n");
+    }
+    if (doc->URL != NULL) {
+	fprintf(output, "URL=");
+        xmlDebugDumpString(output, doc->URL);
+	fprintf(output, "\n");
+    }
+    if (doc->standalone)
+        fprintf(output, "standalone=true\n");
+    if (doc->oldNs != NULL) 
+        xmlDebugDumpNamespaceList(output, doc->oldNs, 0);
+}
+
+void xmlDebugDumpDocument(FILE *output, xmlDocPtr doc) {
+    if (output == NULL) output = stdout;
+    if (doc == NULL) {
+        fprintf(output, "DOCUMENT == NULL !\n");
+	return;
+    }
+    xmlDebugDumpDocumentHead(output, doc);
+    if (((doc->type == XML_DOCUMENT_NODE) ||
+         (doc->type == XML_HTML_DOCUMENT_NODE)) &&
+        (doc->children != NULL))
+        xmlDebugDumpNodeList(output, doc->children, 1);
+}    
+
+void xmlDebugDumpDTD(FILE *output, xmlDtdPtr dtd) {
+    if (dtd == NULL)
+	return;
+    if (dtd->type != XML_DTD_NODE) {
+	fprintf(output, "PBM: not a DTD\n");
+	return;
+    }
+    if (dtd->name != NULL)
+	fprintf(output, "DTD(%s)", dtd->name);
+    else
+	fprintf(output, "DTD");
+    if (dtd->ExternalID != NULL)
+	fprintf(output, ", PUBLIC %s", dtd->ExternalID);
+    if (dtd->SystemID != NULL)
+	fprintf(output, ", SYSTEM %s", dtd->SystemID);
+    fprintf(output, "\n");
+    /*
+     * Do a bit of checking
+     */
+    if ((dtd->parent != NULL) && (dtd->doc != dtd->parent->doc))
+	fprintf(output, "PBM: Dtd doc differs from parent's one\n");
+    if (dtd->prev == NULL) {
+	if ((dtd->parent != NULL) && (dtd->parent->children != (xmlNodePtr)dtd))
+	    fprintf(output, "PBM: Dtd has no prev and not first of list\n");
+    } else {
+	if (dtd->prev->next != (xmlNodePtr) dtd)
+	    fprintf(output, "PBM: Dtd prev->next : back link wrong\n");
+    }
+    if (dtd->next == NULL) {
+	if ((dtd->parent != NULL) && (dtd->parent->last != (xmlNodePtr) dtd))
+	    fprintf(output, "PBM: Dtd has no next and not last of list\n");
+    } else {
+	if (dtd->next->prev != (xmlNodePtr) dtd)
+	    fprintf(output, "PBM: Dtd next->prev : forward link wrong\n");
+    }
+    if (dtd->children == NULL)
+	fprintf(output, "    DTD is empty\n");
+    else
+        xmlDebugDumpNodeList(output, dtd->children, 1);
+}
+
+void xmlDebugDumpEntityCallback(xmlEntityPtr cur, FILE *output,
+	                        const xmlChar *name) {
+    fprintf(output, "%s : ", cur->name);
+    switch (cur->etype) {
+	case XML_INTERNAL_GENERAL_ENTITY:
+	    fprintf(output, "INTERNAL GENERAL, ");
+	    break;
+	case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+	    fprintf(output, "EXTERNAL PARSED, ");
+	    break;
+	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+	    fprintf(output, "EXTERNAL UNPARSED, ");
+	    break;
+	case XML_INTERNAL_PARAMETER_ENTITY:
+	    fprintf(output, "INTERNAL PARAMETER, ");
+	    break;
+	case XML_EXTERNAL_PARAMETER_ENTITY:
+	    fprintf(output, "EXTERNAL PARAMETER, ");
+	    break;
+	default:
+	    fprintf(output, "UNKNOWN TYPE %d",
+		    cur->etype);
+    }
+    if (cur->ExternalID != NULL) 
+	fprintf(output, "ID \"%s\"", cur->ExternalID);
+    if (cur->SystemID != NULL)
+	fprintf(output, "SYSTEM \"%s\"", cur->SystemID);
+    if (cur->orig != NULL)
+	fprintf(output, "\n orig \"%s\"", cur->orig);
+    if (cur->content != NULL)
+	fprintf(output, "\n content \"%s\"", cur->content);
+    fprintf(output, "\n");	
+}
+
+void xmlDebugDumpEntities(FILE *output, xmlDocPtr doc) {
+    if (output == NULL) output = stdout;
+    if (doc == NULL) {
+        fprintf(output, "DOCUMENT == NULL !\n");
+	return;
+    }
+
+    switch (doc->type) {
+	case XML_ELEMENT_NODE:
+	    fprintf(output, "Error, ELEMENT found here ");
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    fprintf(output, "Error, ATTRIBUTE found here\n");
+	    break;
+	case XML_TEXT_NODE:
+	    fprintf(output, "Error, TEXT\n");
+	    break;
+	case XML_CDATA_SECTION_NODE:
+	    fprintf(output, "Error, CDATA_SECTION\n");
+	    break;
+	case XML_ENTITY_REF_NODE:
+	    fprintf(output, "Error, ENTITY_REF\n");
+	    break;
+	case XML_ENTITY_NODE:
+	    fprintf(output, "Error, ENTITY\n");
+	    break;
+	case XML_PI_NODE:
+	    fprintf(output, "Error, PI\n");
+	    break;
+	case XML_COMMENT_NODE:
+	    fprintf(output, "Error, COMMENT\n");
+	    break;
+	case XML_DOCUMENT_NODE:
+	    fprintf(output, "DOCUMENT\n");
+	    break;
+	case XML_HTML_DOCUMENT_NODE:
+	    fprintf(output, "HTML DOCUMENT\n");
+	    break;
+	case XML_DOCUMENT_TYPE_NODE:
+	    fprintf(output, "Error, DOCUMENT_TYPE\n");
+	    break;
+	case XML_DOCUMENT_FRAG_NODE:
+	    fprintf(output, "Error, DOCUMENT_FRAG\n");
+	    break;
+	case XML_NOTATION_NODE:
+	    fprintf(output, "Error, NOTATION\n");
+	    break;
+	default:
+	    fprintf(output, "NODE_%d\n", doc->type);
+    }
+    if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
+        xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 
+	                            doc->intSubset->entities;
+	fprintf(output, "Entities in internal subset\n");
+	xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output);
+    } else
+	fprintf(output, "No entities in internal subset\n");
+    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
+        xmlEntitiesTablePtr table = (xmlEntitiesTablePtr) 
+	                            doc->extSubset->entities;
+	fprintf(output, "Entities in external subset\n");
+	xmlHashScan(table, (xmlHashScanner)xmlDebugDumpEntityCallback, output);
+    } else
+	fprintf(output, "No entities in external subset\n");
+}
+
+static int xmlLsCountNode(xmlNodePtr node) {
+    int ret = 0;
+    xmlNodePtr list = NULL;
+
+    switch (node->type) {
+	case XML_ELEMENT_NODE:
+	    list = node->children;
+	    break;
+	case XML_DOCUMENT_NODE:
+	case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    list = ((xmlDocPtr) node)->children;
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    list = ((xmlAttrPtr) node)->children;
+	    break;
+	case XML_TEXT_NODE:
+	case XML_CDATA_SECTION_NODE:
+	case XML_PI_NODE:
+	case XML_COMMENT_NODE:
+	    if (node->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT	    
+		ret = xmlStrlen(node->content);
+#else
+		ret = xmlBufferLength(node->content);
+#endif
+            }
+	    break;
+	case XML_ENTITY_REF_NODE:
+	case XML_DOCUMENT_TYPE_NODE:
+	case XML_ENTITY_NODE:
+	case XML_DOCUMENT_FRAG_NODE:
+	case XML_NOTATION_NODE:
+	case XML_DTD_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+	    ret = 1;
+	    break;
+    }
+    for (;list != NULL;ret++) 
+        list = list->next;
+    return(ret);
+}
+
+void xmlLsOneNode(FILE *output, xmlNodePtr node) {
+    switch (node->type) {
+	case XML_ELEMENT_NODE:
+	    fprintf(output, "-");
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    fprintf(output, "a");
+	    break;
+	case XML_TEXT_NODE:
+	    fprintf(output, "t");
+	    break;
+	case XML_CDATA_SECTION_NODE:
+	    fprintf(output, "c");
+	    break;
+	case XML_ENTITY_REF_NODE:
+	    fprintf(output, "e");
+	    break;
+	case XML_ENTITY_NODE:
+	    fprintf(output, "E");
+	    break;
+	case XML_PI_NODE:
+	    fprintf(output, "p");
+	    break;
+	case XML_COMMENT_NODE:
+	    fprintf(output, "c");
+	    break;
+	case XML_DOCUMENT_NODE:
+	    fprintf(output, "d");
+	    break;
+	case XML_HTML_DOCUMENT_NODE:
+	    fprintf(output, "h");
+	    break;
+	case XML_DOCUMENT_TYPE_NODE:
+	    fprintf(output, "T");
+	    break;
+	case XML_DOCUMENT_FRAG_NODE:
+	    fprintf(output, "F");
+	    break;
+	case XML_NOTATION_NODE:
+	    fprintf(output, "N");
+	    break;
+	default:
+	    fprintf(output, "?");
+    }
+    if (node->properties != NULL)
+	fprintf(output, "a");
+    else	
+	fprintf(output, "-");
+    if (node->nsDef != NULL) 
+	fprintf(output, "n");
+    else	
+	fprintf(output, "-");
+
+    fprintf(output, " %8d ", xmlLsCountNode(node));
+
+    switch (node->type) {
+	case XML_ELEMENT_NODE:
+	    if (node->name != NULL)
+		fprintf(output, "%s", node->name);
+	    break;
+	case XML_ATTRIBUTE_NODE:
+	    if (node->name != NULL)
+		fprintf(output, "%s", node->name);
+	    break;
+	case XML_TEXT_NODE:
+	    if (node->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT	    
+		xmlDebugDumpString(output, node->content);
+#else
+		xmlDebugDumpString(output, xmlBufferContent(node->content));
+#endif
+            }
+	    break;
+	case XML_CDATA_SECTION_NODE:
+	    break;
+	case XML_ENTITY_REF_NODE:
+	    if (node->name != NULL)
+		fprintf(output, "%s", node->name);
+	    break;
+	case XML_ENTITY_NODE:
+	    if (node->name != NULL)
+		fprintf(output, "%s", node->name);
+	    break;
+	case XML_PI_NODE:
+	    if (node->name != NULL)
+		fprintf(output, "%s", node->name);
+	    break;
+	case XML_COMMENT_NODE:
+	    break;
+	case XML_DOCUMENT_NODE:
+	    break;
+	case XML_HTML_DOCUMENT_NODE:
+	    break;
+	case XML_DOCUMENT_TYPE_NODE:
+	    break;
+	case XML_DOCUMENT_FRAG_NODE:
+	    break;
+	case XML_NOTATION_NODE:
+	    break;
+	default:
+	    if (node->name != NULL)
+		fprintf(output, "%s", node->name);
+    }
+    fprintf(output, "\n");
+}
+
+/****************************************************************
+ *								*
+ *	 	The XML shell related functions			*
+ *								*
+ ****************************************************************/
+
+/*
+ * TODO: Improvement/cleanups for the XML shell
+ *     - allow to shell out an editor on a subpart
+ *     - cleanup function registrations (with help) and calling
+ *     - provide registration routines
+ */
+
+/**
+ * xmlShellList:
+ * @ctxt:  the shell context
+ * @arg:  unused
+ * @node:  a node
+ * @node2:  unused
+ *
+ * Implements the XML shell function "ls"
+ * Does an Unix like listing of the given node (like a directory)
+ *
+ * Returns 0
+ */
+int
+xmlShellList(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
+                  xmlNodePtr node2) {
+    xmlNodePtr cur;
+
+    if ((node->type == XML_DOCUMENT_NODE) ||
+        (node->type == XML_HTML_DOCUMENT_NODE)) {
+        cur = ((xmlDocPtr) node)->children;
+    } else if (node->children != NULL) {
+        cur = node->children;
+    } else {
+	xmlLsOneNode(stdout, node);
+        return(0);
+    }
+    while (cur != NULL) {
+	xmlLsOneNode(stdout, cur);
+	cur = cur->next;
+    }
+    return(0);
+}
+
+/**
+ * xmlShellDir:
+ * @ctxt:  the shell context
+ * @arg:  unused
+ * @node:  a node
+ * @node2:  unused
+ *
+ * Implements the XML shell function "dir"
+ * dumps informations about the node (namespace, attributes, content).
+ *
+ * Returns 0
+ */
+int
+xmlShellDir(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
+                  xmlNodePtr node2) {
+    if ((node->type == XML_DOCUMENT_NODE) ||
+        (node->type == XML_HTML_DOCUMENT_NODE)) {
+	xmlDebugDumpDocumentHead(stdout, (xmlDocPtr) node);
+    } else if (node->type == XML_ATTRIBUTE_NODE) {
+	xmlDebugDumpAttr(stdout, (xmlAttrPtr) node, 0);
+    } else {
+	xmlDebugDumpOneNode(stdout, node, 0);
+    }
+    return(0);
+}
+
+/**
+ * xmlShellCat:
+ * @ctxt:  the shell context
+ * @arg:  unused
+ * @node:  a node
+ * @node2:  unused
+ *
+ * Implements the XML shell function "cat"
+ * dumps the serialization node content (XML or HTML).
+ *
+ * Returns 0
+ */
+int
+xmlShellCat(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr node,
+                  xmlNodePtr node2) {
+    if (ctxt->doc->type == XML_HTML_DOCUMENT_NODE) {
+#ifdef LIBXML_HTML_ENABLED
+	if (node->type == XML_HTML_DOCUMENT_NODE)
+	    htmlDocDump(stdout, (htmlDocPtr) node);
+	else
+	    htmlNodeDumpFile(stdout, ctxt->doc, node);
+#else
+	if (node->type == XML_DOCUMENT_NODE)
+	    xmlDocDump(stdout, (xmlDocPtr) node);
+	else
+	    xmlElemDump(stdout, ctxt->doc, node);
+#endif /* LIBXML_HTML_ENABLED */
+    } else {
+	if (node->type == XML_DOCUMENT_NODE)
+	    xmlDocDump(stdout, (xmlDocPtr) node);
+	else
+	    xmlElemDump(stdout, ctxt->doc, node);
+    }
+    printf("\n");
+    return(0);
+}
+
+/**
+ * xmlShellLoad:
+ * @ctxt:  the shell context
+ * @filename:  the file name
+ * @node:  unused
+ * @node2:  unused
+ *
+ * Implements the XML shell function "load"
+ * loads a new document specified by the filename
+ *
+ * Returns 0 or -1 if loading failed
+ */
+int
+xmlShellLoad(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
+             xmlNodePtr node2) {
+    xmlDocPtr doc;
+    int html = 0;
+
+    if (ctxt->doc != NULL)
+	html = (ctxt->doc->type == XML_HTML_DOCUMENT_NODE);
+
+    if (html) {
+#ifdef LIBXML_HTML_ENABLED
+	doc = htmlParseFile(filename, NULL);
+#else	
+	printf("HTML support not compiled in\n");
+	doc = NULL;
+#endif /* LIBXML_HTML_ENABLED */
+    } else {
+	doc = xmlParseFile(filename);
+    }
+    if (doc != NULL) {
+        if (ctxt->loaded == 1) {
+	    xmlFreeDoc(ctxt->doc);
+	}
+	ctxt->loaded = 1;
+#ifdef LIBXML_XPATH_ENABLED
+	xmlXPathFreeContext(ctxt->pctxt);
+#endif /* LIBXML_XPATH_ENABLED */
+	xmlFree(ctxt->filename);
+	ctxt->doc = doc;
+	ctxt->node = (xmlNodePtr) doc;	 
+#ifdef LIBXML_XPATH_ENABLED
+	ctxt->pctxt = xmlXPathNewContext(doc);
+#endif /* LIBXML_XPATH_ENABLED */
+	ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
+    } else
+        return(-1);
+    return(0);
+}
+
+/**
+ * xmlShellWrite:
+ * @ctxt:  the shell context
+ * @filename:  the file name
+ * @node:  a node in the tree
+ * @node2:  unused
+ *
+ * Implements the XML shell function "write"
+ * Write the current node to the filename, it saves the serailization
+ * of the subtree under the @node specified
+ *
+ * Returns 0 or -1 in case of error
+ */
+int
+xmlShellWrite(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
+                  xmlNodePtr node2) {
+    if (node == NULL)
+        return(-1);
+    if ((filename == NULL) || (filename[0] == 0)) {
+        xmlGenericError(xmlGenericErrorContext,
+		"Write command requires a filename argument\n");
+	return(-1);
+    }
+#ifdef W_OK
+    if (access((char *) filename, W_OK)) {
+        xmlGenericError(xmlGenericErrorContext,
+		"Cannot write to %s\n", filename);
+	return(-1);
+    }
+#endif    
+    switch(node->type) {
+        case XML_DOCUMENT_NODE:
+	    if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to write to %s\n", filename);
+		return(-1);
+	    }
+	    break;
+        case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_HTML_ENABLED
+	    if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to write to %s\n", filename);
+		return(-1);
+	    }
+#else
+	    if (xmlSaveFile((char *) filename, ctxt->doc) < -1) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to write to %s\n", filename);
+		return(-1);
+	    }
+#endif /* LIBXML_HTML_ENABLED */
+	    break;
+	default: {
+	    FILE *f;
+
+	    f = fopen((char *) filename, "w");
+	    if (f == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to write to %s\n", filename);
+		return(-1);
+	    }
+	    xmlElemDump(f, ctxt->doc, node);
+	    fclose(f);
+	}
+    }
+    return(0);
+}
+
+/**
+ * xmlShellSave:
+ * @ctxt:  the shell context
+ * @filename:  the file name (optionnal)
+ * @node:  unused
+ * @node2:  unused
+ *
+ * Implements the XML shell function "save"
+ * Write the current document to the filename, or it's original name
+ *
+ * Returns 0 or -1 in case of error
+ */
+int 
+xmlShellSave(xmlShellCtxtPtr ctxt, char *filename, xmlNodePtr node,
+             xmlNodePtr node2) {
+    if (ctxt->doc == NULL)
+	return(-1);
+    if ((filename == NULL) || (filename[0] == 0))
+        filename = ctxt->filename;
+#ifdef W_OK
+    if (access((char *) filename, W_OK)) {
+        xmlGenericError(xmlGenericErrorContext,
+		"Cannot save to %s\n", filename);
+	return(-1);
+    }
+#endif
+    switch(ctxt->doc->type) {
+        case XML_DOCUMENT_NODE:
+	    if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to save to %s\n", filename);
+	    }
+	    break;
+        case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_HTML_ENABLED
+	    if (htmlSaveFile((char *) filename, ctxt->doc) < 0) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to save to %s\n", filename);
+	    }
+#else
+	    if (xmlSaveFile((char *) filename, ctxt->doc) < 0) {
+		xmlGenericError(xmlGenericErrorContext,
+			"Failed to save to %s\n", filename);
+	    }
+#endif /* LIBXML_HTML_ENABLED */
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext, 
+	      "To save to subparts of a document use the 'write' command\n");
+	    return(-1);
+	    
+    }
+    return(0);
+}
+
+/**
+ * xmlShellValidate:
+ * @ctxt:  the shell context
+ * @dtd:  the DTD URI (optionnal)
+ * @node:  unused
+ * @node2:  unused
+ *
+ * Implements the XML shell function "validate"
+ * Validate the document, if a DTD path is provided, then the validation
+ * is done against the given DTD.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int 
+xmlShellValidate(xmlShellCtxtPtr ctxt, char *dtd, xmlNodePtr node,
+                 xmlNodePtr node2) {
+    xmlValidCtxt vctxt;
+    int res = -1;
+
+    vctxt.userData = stderr;
+    vctxt.error = (xmlValidityErrorFunc) fprintf;
+    vctxt.warning = (xmlValidityWarningFunc) fprintf;
+
+    if ((dtd == NULL) || (dtd[0] == 0)) {
+        res = xmlValidateDocument(&vctxt, ctxt->doc);
+    } else {
+        xmlDtdPtr subset;
+
+	subset = xmlParseDTD(NULL, (xmlChar *) dtd);
+	if (subset != NULL) {
+            res = xmlValidateDtd(&vctxt, ctxt->doc, subset);
+
+	    xmlFreeDtd(subset);
+	}
+    }
+    return(res);
+}
+
+/**
+ * xmlShellDu:
+ * @ctxt:  the shell context
+ * @arg:  unused
+ * @tree:  a node defining a subtree
+ * @node2:  unused
+ *
+ * Implements the XML shell function "du"
+ * show the structure of the subtree under node @tree
+ * If @tree is null, the command works on the current node.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int 
+xmlShellDu(xmlShellCtxtPtr ctxt, char *arg, xmlNodePtr tree,
+                  xmlNodePtr node2) {
+    xmlNodePtr node;
+    int indent = 0,i;
+
+    if (tree == NULL) return(-1);
+    node = tree;
+    while (node != NULL) {
+        if ((node->type == XML_DOCUMENT_NODE) ||
+            (node->type == XML_HTML_DOCUMENT_NODE)) {
+	    printf("/\n");
+	} else if (node->type == XML_ELEMENT_NODE) {
+	    for (i = 0;i < indent;i++)
+	        printf("  ");
+	    printf("%s\n", node->name);
+	} else {
+	}
+
+	/*
+	 * Browse the full subtree, deep first
+	 */
+
+        if ((node->type == XML_DOCUMENT_NODE) ||
+            (node->type == XML_HTML_DOCUMENT_NODE)) {
+	    node = ((xmlDocPtr) node)->children;
+        } else if ((node->children != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
+	    /* deep first */
+	    node = node->children;
+	    indent++;
+	} else if ((node != tree) && (node->next != NULL)) {
+	    /* then siblings */
+	    node = node->next;
+	} else if (node != tree) {
+	    /* go up to parents->next if needed */
+	    while (node != tree) {
+	        if (node->parent != NULL) {
+		    node = node->parent;
+		    indent--;
+		}
+		if ((node != tree) && (node->next != NULL)) {
+		    node = node->next;
+		    break;
+		}
+		if (node->parent == NULL) {
+		    node = NULL;
+		    break;
+		}
+		if (node == tree) {
+		    node = NULL;
+		    break;
+		}
+	    }
+	    /* exit condition */
+	    if (node == tree) 
+	        node = NULL;
+	} else
+	    node = NULL;
+    }
+    return(0);
+}
+
+/**
+ * xmlShellPwd:
+ * @ctxt:  the shell context
+ * @buffer:  the output buffer
+ * @tree:  a node 
+ * @node2:  unused
+ *
+ * Implements the XML shell function "pwd"
+ * Show the full path from the root to the node, if needed building
+ * thumblers when similar elements exists at a given ancestor level.
+ * The output is compatible with XPath commands.
+ *
+ * Returns 0 or -1 in case of error
+ */
+int 
+xmlShellPwd(xmlShellCtxtPtr ctxt, char *buffer, xmlNodePtr node,
+                  xmlNodePtr node2) {
+    xmlNodePtr cur, tmp, next;
+    char buf[500];
+    char sep;
+    const char *name;
+    int occur = 0;
+
+    buffer[0] = 0;
+    if (node == NULL) return(-1);
+    cur = node;
+    do {
+	name = "";
+	sep= '?';
+	occur = 0;
+	if ((cur->type == XML_DOCUMENT_NODE) ||
+	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	    sep = '/';
+	    next = NULL;
+	} else if (cur->type == XML_ELEMENT_NODE) {
+	    sep = '/';
+	    name = (const char *)cur->name;
+	    next = cur->parent;
+
+	    /*
+	     * Thumbler index computation
+	     */
+	    tmp = cur->prev;
+            while (tmp != NULL) {
+	        if (xmlStrEqual(cur->name, tmp->name))
+		    occur++;
+	        tmp = tmp->prev;
+	    }
+	    if (occur == 0) {
+	        tmp = cur->next;
+		while (tmp != NULL) {
+		    if (xmlStrEqual(cur->name, tmp->name))
+			occur++;
+		    tmp = tmp->next;
+		}
+		if (occur != 0) occur = 1;
+	    } else
+	        occur++;
+	} else if (cur->type == XML_ATTRIBUTE_NODE) {
+	    sep = '@';
+	    name = (const char *) (((xmlAttrPtr) cur)->name);
+	    next = ((xmlAttrPtr) cur)->parent;
+	} else {
+	    next = cur->parent;
+	}
+	if (occur == 0)
+#ifdef HAVE_SNPRINTF
+	    snprintf(buf, sizeof(buf), "%c%s%s", sep, name, buffer);
+#else
+	    sprintf(buf, "%c%s%s", sep, name, buffer);
+#endif
+        else
+#ifdef HAVE_SNPRINTF
+	    snprintf(buf, sizeof(buf), "%c%s[%d]%s",
+                    sep, name, occur, buffer);
+#else
+	    sprintf(buf, "%c%s[%d]%s", sep, name, occur, buffer);
+#endif
+        buf[sizeof(buf) - 1] = 0;
+        /*
+         * This test prevents buffer overflow, because this routine
+         * is only called by xmlShell, in which the second argument is
+         * 500 chars long.
+         * It is a dirty hack before a cleaner solution is found.
+         * Documentation should mention that the second argument must
+         * be at least 500 chars long, and could be stripped if too long.
+         */
+        if (strlen(buffer) + strlen(buf) > 499)
+           break;
+	strcpy(buffer, buf);
+        cur = next;
+    } while (cur != NULL);
+    return(0);
+}
+
+/**
+ * xmlShell
+ * @doc:  the initial document
+ * @filename:  the output buffer
+ * @input:  the line reading function
+ * @output:  the output FILE*
+ *
+ * Implements the XML shell 
+ * This allow to load, validate, view, modify and save a document
+ * using a environment similar to a UNIX commandline.
+ */
+void
+xmlShell(xmlDocPtr doc, char *filename, xmlShellReadlineFunc input,
+         FILE *output) {
+    char prompt[500] = "/ > ";
+    char *cmdline = NULL, *cur;
+    int nbargs;
+    char command[100];
+    char arg[400];
+    int i;
+    xmlShellCtxtPtr ctxt;
+    xmlXPathObjectPtr list;
+
+    if (doc == NULL)
+        return;
+    if (filename == NULL)
+        return;
+    if (input == NULL)
+        return;
+    if (output == NULL)
+        return;
+    ctxt = (xmlShellCtxtPtr) xmlMalloc(sizeof(xmlShellCtxt));
+    if (ctxt == NULL) 
+        return;
+    ctxt->loaded = 0;
+    ctxt->doc = doc;
+    ctxt->input = input;
+    ctxt->output = output;
+    ctxt->filename = (char *) xmlStrdup((xmlChar *) filename);
+    ctxt->node = (xmlNodePtr) ctxt->doc;	 
+
+#ifdef LIBXML_XPATH_ENABLED
+    ctxt->pctxt = xmlXPathNewContext(ctxt->doc);
+    if (ctxt->pctxt == NULL) {
+	xmlFree(ctxt);
+	return;
+    }
+#endif /* LIBXML_XPATH_ENABLED */
+    while (1) {
+        if (ctxt->node == (xmlNodePtr) ctxt->doc)
+	    sprintf(prompt, "%s > ", "/");
+	else if (ctxt->node->name)
+#ifdef HAVE_SNPRINTF
+	    snprintf(prompt, sizeof(prompt), "%s > ", ctxt->node->name);
+#else
+	    sprintf(prompt, "%s > ", ctxt->node->name);
+#endif
+        else
+	    sprintf(prompt, "? > ");
+        prompt[sizeof(prompt) - 1] = 0;
+
+	/*
+	 * Get a new command line
+	 */
+        cmdline = ctxt->input(prompt);
+        if (cmdline == NULL) break;
+
+	/*
+	 * Parse the command itself
+	 */
+	cur = cmdline;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	i = 0;
+	while ((*cur != ' ') && (*cur != '\t') &&
+	       (*cur != '\n') && (*cur != '\r')) {
+	    if (*cur == 0)
+		break;
+	    command[i++] = *cur++;
+	}
+	command[i] = 0;
+	if (i == 0) continue;
+	nbargs++;
+
+	/*
+	 * Parse the argument
+	 */
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	i = 0;
+	while ((*cur != '\n') && (*cur != '\r') && (*cur != 0)) {
+	    if (*cur == 0)
+		break;
+	    arg[i++] = *cur++;
+	}
+	arg[i] = 0;
+	if (i != 0) 
+	    nbargs++;
+
+	/*
+	 * start interpreting the command
+	 */
+        if (!strcmp(command, "exit"))
+	    break;
+        if (!strcmp(command, "quit"))
+	    break;
+        if (!strcmp(command, "bye"))
+	    break;
+	if (!strcmp(command, "validate")) {
+	    xmlShellValidate(ctxt, arg, NULL, NULL);
+	} else if (!strcmp(command, "load")) {
+	    xmlShellLoad(ctxt, arg, NULL, NULL);
+	} else if (!strcmp(command, "save")) {
+	    xmlShellSave(ctxt, arg, NULL, NULL);
+	} else if (!strcmp(command, "write")) {
+	    xmlShellWrite(ctxt, arg, NULL, NULL);
+	} else if (!strcmp(command, "free")) {
+	    if (arg[0] == 0) {
+		xmlMemShow(stdout, 0);
+	    } else {
+	        int len = 0;
+		sscanf(arg, "%d", &len);
+		xmlMemShow(stdout, len);
+	    }
+	} else if (!strcmp(command, "pwd")) {
+	    char dir[500];
+	    if (!xmlShellPwd(ctxt, dir, ctxt->node, NULL))
+		printf("%s\n", dir);
+	} else  if (!strcmp(command, "du")) {
+	    xmlShellDu(ctxt, NULL, ctxt->node, NULL);
+	} else  if ((!strcmp(command, "ls")) ||
+	      (!strcmp(command, "dir"))) {
+	    int dir = (!strcmp(command, "dir"));
+	    if (arg[0] == 0) {
+		if (dir)
+		    xmlShellDir(ctxt, NULL, ctxt->node, NULL);
+		else
+		    xmlShellList(ctxt, NULL, ctxt->node, NULL);
+	    } else {
+	        ctxt->pctxt->node = ctxt->node;
+#ifdef LIBXML_XPATH_ENABLED
+	        ctxt->pctxt->node = ctxt->node;
+		list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
+#else
+		list = NULL;
+#endif /* LIBXML_XPATH_ENABLED */
+		if (list != NULL) {
+		    switch (list->type) {
+			case XPATH_UNDEFINED:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s: no such node\n", arg);
+			    break;
+			case XPATH_NODESET: {
+			    int i;
+
+			    for (i = 0;i < list->nodesetval->nodeNr;i++) {
+				if (dir)
+				    xmlShellDir(ctxt, NULL,
+				       list->nodesetval->nodeTab[i], NULL);
+				else
+				    xmlShellList(ctxt, NULL,
+				       list->nodesetval->nodeTab[i], NULL);
+			    }
+			    break;
+			}
+			case XPATH_BOOLEAN:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a Boolean\n", arg);
+			    break;
+			case XPATH_NUMBER:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a number\n", arg);
+			    break;
+			case XPATH_STRING:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a string\n", arg);
+			    break;
+			case XPATH_POINT:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a point\n", arg);
+			    break;
+			case XPATH_RANGE:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a range\n", arg);
+			    break;
+			case XPATH_LOCATIONSET:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a range\n", arg);
+			    break;
+			case XPATH_USERS:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is user-defined\n", arg);
+			    break;
+			case XPATH_XSLT_TREE:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is an XSLT value tree\n", arg);
+			    break;
+		    }
+		    xmlXPathFreeNodeSetList(list);
+		} else {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "%s: no such node\n", arg);
+		}
+		ctxt->pctxt->node = NULL;
+	    }
+	} else if (!strcmp(command, "cd")) {
+	    if (arg[0] == 0) {
+		ctxt->node = (xmlNodePtr) ctxt->doc;
+	    } else {
+#ifdef LIBXML_XPATH_ENABLED
+	        ctxt->pctxt->node = ctxt->node;
+		list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
+#else
+		list = NULL;
+#endif /* LIBXML_XPATH_ENABLED */
+		if (list != NULL) {
+		    switch (list->type) {
+			case XPATH_UNDEFINED:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s: no such node\n", arg);
+			    break;
+			case XPATH_NODESET:
+			    if (list->nodesetval->nodeNr == 1) {
+				ctxt->node = list->nodesetval->nodeTab[0];
+			    } else 
+				xmlGenericError(xmlGenericErrorContext,
+					"%s is a %d Node Set\n",
+				        arg, list->nodesetval->nodeNr);
+			    break;
+			case XPATH_BOOLEAN:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a Boolean\n", arg);
+			    break;
+			case XPATH_NUMBER:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a number\n", arg);
+			    break;
+			case XPATH_STRING:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a string\n", arg);
+			    break;
+			case XPATH_POINT:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a point\n", arg);
+			    break;
+			case XPATH_RANGE:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a range\n", arg);
+			    break;
+			case XPATH_LOCATIONSET:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a range\n", arg);
+			    break;
+			case XPATH_USERS:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is user-defined\n", arg);
+			    break;
+			case XPATH_XSLT_TREE:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is an XSLT value tree\n", arg);
+			    break;
+		    }
+		    xmlXPathFreeNodeSetList(list);
+		} else {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "%s: no such node\n", arg);
+		}
+		ctxt->pctxt->node = NULL;
+	    }
+	} else if (!strcmp(command, "cat")) {
+	    if (arg[0] == 0) {
+		xmlShellCat(ctxt, NULL, ctxt->node, NULL);
+	    } else {
+	        ctxt->pctxt->node = ctxt->node;
+#ifdef LIBXML_XPATH_ENABLED
+	        ctxt->pctxt->node = ctxt->node;
+		list = xmlXPathEval((xmlChar *) arg, ctxt->pctxt);
+#else
+		list = NULL;
+#endif /* LIBXML_XPATH_ENABLED */
+		if (list != NULL) {
+		    switch (list->type) {
+			case XPATH_UNDEFINED:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s: no such node\n", arg);
+			    break;
+			case XPATH_NODESET: {
+			    int i;
+
+			    for (i = 0;i < list->nodesetval->nodeNr;i++) {
+			        if (i > 0) printf(" -------\n");
+				xmlShellCat(ctxt, NULL,
+				    list->nodesetval->nodeTab[i], NULL);
+			    }
+			    break;
+			}
+			case XPATH_BOOLEAN:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a Boolean\n", arg);
+			    break;
+			case XPATH_NUMBER:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a number\n", arg);
+			    break;
+			case XPATH_STRING:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a string\n", arg);
+			    break;
+			case XPATH_POINT:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a point\n", arg);
+			    break;
+			case XPATH_RANGE:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a range\n", arg);
+			    break;
+			case XPATH_LOCATIONSET:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is a range\n", arg);
+			    break;
+			case XPATH_USERS:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is user-defined\n", arg);
+			    break;
+			case XPATH_XSLT_TREE:
+			    xmlGenericError(xmlGenericErrorContext,
+				    "%s is an XSLT value tree\n", arg);
+			    break;
+		    }
+		    xmlXPathFreeNodeSetList(list);
+		} else {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "%s: no such node\n", arg);
+		}
+		ctxt->pctxt->node = NULL;
+	    }
+	} else {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Unknown command %s\n", command);
+	}
+	free(cmdline); /* not xmlFree here ! */
+    }
+#ifdef LIBXML_XPATH_ENABLED
+    xmlXPathFreeContext(ctxt->pctxt);
+#endif /* LIBXML_XPATH_ENABLED */
+    if (ctxt->loaded) {
+        xmlFreeDoc(ctxt->doc);
+    }
+    xmlFree(ctxt);
+    if (cmdline != NULL)
+        free(cmdline); /* not xmlFree here ! */
+}
+
+#endif /* LIBXML_DEBUG_ENABLED */
diff --git a/debugXML.h b/debugXML.h
new file mode 100644
index 0000000..4a55fa8
--- /dev/null
+++ b/debugXML.h
@@ -0,0 +1,113 @@
+/*
+ * debugXML.h : Interfaces to a set of routines used for debugging the tree
+ *              produced by the XML parser.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+#ifndef __DEBUG_XML__
+#define __DEBUG_XML__
+#include <stdio.h>
+#include <libxml/tree.h>
+
+#ifdef LIBXML_DEBUG_ENABLED
+
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The standard Dump routines
+ */
+void	xmlDebugDumpString	(FILE *output,
+				 const xmlChar *str);
+void	xmlDebugDumpAttr	(FILE *output,
+				 xmlAttrPtr attr,
+				 int depth);
+void	xmlDebugDumpAttrList	(FILE *output,
+				 xmlAttrPtr attr,
+				 int depth);
+void	xmlDebugDumpOneNode	(FILE *output,
+				 xmlNodePtr node,
+				 int depth);
+void	xmlDebugDumpNode	(FILE *output,
+				 xmlNodePtr node,
+				 int depth);
+void	xmlDebugDumpNodeList	(FILE *output,
+				 xmlNodePtr node,
+				 int depth);
+void	xmlDebugDumpDocumentHead(FILE *output,
+				 xmlDocPtr doc);
+void	xmlDebugDumpDocument	(FILE *output,
+				 xmlDocPtr doc);
+void	xmlDebugDumpDTD		(FILE *output,
+				 xmlDtdPtr doc);
+void	xmlDebugDumpEntities	(FILE *output,
+				 xmlDocPtr doc);
+void	xmlLsOneNode		(FILE *output,
+				 xmlNodePtr node);
+
+/****************************************************************
+ *								*
+ *	 The XML shell related structures and functions		*
+ *								*
+ ****************************************************************/
+
+/**
+ * xmlShellReadlineFunc:
+ * @prompt:  a string prompt
+ *
+ * This is a generic signature for the XML shell input function
+ *
+ * Returns a string which will be freed by the Shell
+ */
+typedef char * (* xmlShellReadlineFunc)(char *prompt);
+
+/*
+ * The shell context itself
+ * TODO: add the defined function tables.
+ */
+typedef struct _xmlShellCtxt xmlShellCtxt;
+typedef xmlShellCtxt *xmlShellCtxtPtr;
+struct _xmlShellCtxt {
+    char *filename;
+    xmlDocPtr doc;
+    xmlNodePtr node;
+    xmlXPathContextPtr pctxt;
+    int loaded;
+    FILE *output;
+    xmlShellReadlineFunc input;
+};
+
+/**
+ * xmlShellCmd:
+ * @ctxt:  a shell context
+ * @arg:  a string argument
+ * @node:  a first node
+ * @node2:  a second node
+ *
+ * This is a generic signature for the XML shell functions
+ *
+ * Returns an int, negative returns indicating errors
+ */
+typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt,
+                             char *arg,
+			     xmlNodePtr node,
+			     xmlNodePtr node2);
+
+/*
+ * The Shell interface.
+ */
+void	xmlShell	(xmlDocPtr doc,
+			 char *filename,
+			 xmlShellReadlineFunc input,
+			 FILE *output);
+			 
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBXML_DEBUG_ENABLED */
+#endif /* __DEBUG_XML__ */
diff --git a/encoding.c b/encoding.c
new file mode 100644
index 0000000..fab241e
--- /dev/null
+++ b/encoding.c
@@ -0,0 +1,2078 @@
+/*
+ * encoding.c : implements the encoding conversion functions needed for XML
+ *
+ * Related specs: 
+ * rfc2044        (UTF-8 and UTF-16) F. Yergeau Alis Technologies
+ * rfc2781        UTF-16, an encoding of ISO 10646, P. Hoffman, F. Yergeau
+ * [ISO-10646]    UTF-8 and UTF-16 in Annexes
+ * [ISO-8859-1]   ISO Latin-1 characters codes.
+ * [UNICODE]      The Unicode Consortium, "The Unicode Standard --
+ *                Worldwide Character Encoding -- Version 1.0", Addison-
+ *                Wesley, Volume 1, 1991, Volume 2, 1992.  UTF-8 is
+ *                described in Unicode Technical Report #4.
+ * [US-ASCII]     Coded Character Set--7-bit American Standard Code for
+ *                Information Interchange, ANSI X3.4-1986.
+ *
+ * Original code for IsoLatin1 and UTF-16 by "Martin J. Duerst" <duerst@w3.org>
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_ICONV_ENABLED
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#endif
+#include <libxml/encoding.h>
+#include <libxml/xmlmemory.h>
+#ifdef LIBXML_HTML_ENABLED
+#include <libxml/HTMLparser.h>
+#endif
+#include <libxml/xmlerror.h>
+
+xmlCharEncodingHandlerPtr xmlUTF16LEHandler = NULL;
+xmlCharEncodingHandlerPtr xmlUTF16BEHandler = NULL;
+
+typedef struct _xmlCharEncodingAlias xmlCharEncodingAlias;
+typedef xmlCharEncodingAlias *xmlCharEncodingAliasPtr;
+struct _xmlCharEncodingAlias {
+    const char *name;
+    const char *alias;
+};
+
+static xmlCharEncodingAliasPtr xmlCharEncodingAliases = NULL;
+static int xmlCharEncodingAliasesNb = 0;
+static int xmlCharEncodingAliasesMax = 0;
+
+#ifdef LIBXML_ICONV_ENABLED
+#if 0
+#define DEBUG_ENCODING  /* Define this to get encoding traces */
+#endif
+#endif
+
+static int xmlLittleEndian = 1;
+
+/*
+ * From rfc2044: encoding of the Unicode values on UTF-8:
+ *
+ * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+ * 0000 0000-0000 007F   0xxxxxxx
+ * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
+ *
+ * I hope we won't use values > 0xFFFF anytime soon !
+ */
+
+/**
+ * xmlGetUTF8Char:
+ * @utf:  a sequence of UTF-8 encoded bytes
+ * @len:  a pointer to @bytes len
+ *
+ * Read one UTF8 Char from @utf
+ *
+ * Returns the char value or -1 in case of error and update @len with the
+ *        number of bytes used
+ */
+int
+xmlGetUTF8Char(const unsigned char *utf, int *len) {
+    unsigned int c;
+
+    if (utf == NULL)
+	goto error;
+    if (len == NULL)
+	goto error;
+    if (*len < 1)
+	goto error;
+
+    c = utf[0];
+    if (c & 0x80) {
+	if (*len < 2)
+	    goto error;
+	if ((utf[1] & 0xc0) != 0x80)
+	    goto error;
+	if ((c & 0xe0) == 0xe0) {
+	    if (*len < 3)
+		goto error;
+	    if ((utf[2] & 0xc0) != 0x80)
+		goto error;
+	    if ((c & 0xf0) == 0xf0) {
+		if (*len < 4)
+		    goto error;
+		if ((c & 0xf8) != 0xf0 || (utf[3] & 0xc0) != 0x80)
+		    goto error;
+		*len = 4;
+		/* 4-byte code */
+		c = (utf[0] & 0x7) << 18;
+		c |= (utf[1] & 0x3f) << 12;
+		c |= (utf[2] & 0x3f) << 6;
+		c |= utf[3] & 0x3f;
+	    } else {
+	      /* 3-byte code */
+		*len = 3;
+		c = (utf[0] & 0xf) << 12;
+		c |= (utf[1] & 0x3f) << 6;
+		c |= utf[2] & 0x3f;
+	    }
+	} else {
+	  /* 2-byte code */
+	    *len = 2;
+	    c = (utf[0] & 0x1f) << 6;
+	    c |= utf[1] & 0x3f;
+	}
+    } else {
+	/* 1-byte code */
+	*len = 1;
+    }
+    return(c);
+
+error:
+    *len = 0;
+    return(-1);
+}
+
+/**
+ * xmlCheckUTF8: Check utf-8 string for legality.
+ * @utf: Pointer to putative utf-8 encoded string.
+ *
+ * Checks @utf for being valid utf-8. @utf is assumed to be
+ * null-terminated. This function is not super-strict, as it will
+ * allow longer utf-8 sequences than necessary. Note that Java is
+ * capable of producing these sequences if provoked. Also note, this
+ * routine checks for the 4-byte maxiumum size, but does not check for
+ * 0x10ffff maximum value.
+ *
+ * Return value: true if @utf is valid.
+ **/
+int
+xmlCheckUTF8(const unsigned char *utf)
+{
+    int ix;
+    unsigned char c;
+
+    for (ix = 0; (c = utf[ix]);) {
+        if (c & 0x80) {
+	    if ((utf[ix + 1] & 0xc0) != 0x80)
+	        return(0);
+	    if ((c & 0xe0) == 0xe0) {
+	        if ((utf[ix + 2] & 0xc0) != 0x80)
+		    return(0);
+	        if ((c & 0xf0) == 0xf0) {
+		    if ((c & 0xf8) != 0xf0 || (utf[ix + 3] & 0xc0) != 0x80)
+		        return(0);
+		    ix += 4;
+		    /* 4-byte code */
+	        } else
+		  /* 3-byte code */
+		    ix += 3;
+	    } else
+	      /* 2-byte code */
+	        ix += 2;
+	} else
+	    /* 1-byte code */
+	    ix++;
+      }
+      return(1);
+}
+
+/**
+ * asciiToUTF8:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of ASCII chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of ASCII chars in and try to convert it to an UTF-8
+ * block of chars out.
+ * Returns 0 if success, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+int
+asciiToUTF8(unsigned char* out, int *outlen,
+              const unsigned char* in, int *inlen) {
+    unsigned char* outstart = out;
+    const unsigned char* base = in;
+    const unsigned char* processed = in;
+    unsigned char* outend = out + *outlen;
+    const unsigned char* inend;
+    unsigned int c;
+    int bits;
+
+    inend = in + (*inlen);
+    while ((in < inend) && (out - outstart + 5 < *outlen)) {
+	c= *in++;
+
+	/* assertion: c is a single UTF-4 value */
+        if (out >= outend)
+	    break;
+        if      (c <    0x80) {  *out++=  c;                bits= -6; }
+        else { 
+	    *outlen = out - outstart;
+	    *inlen = processed - base;
+	    return(-1);
+	}
+ 
+        for ( ; bits >= 0; bits-= 6) {
+            if (out >= outend)
+	        break;
+            *out++= ((c >> bits) & 0x3F) | 0x80;
+        }
+	processed = (const unsigned char*) in;
+    }
+    *outlen = out - outstart;
+    *inlen = processed - base;
+    return(0);
+}
+
+/**
+ * UTF8Toascii:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of UTF-8 chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an ASCII
+ * block of chars out.
+ *
+ * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+int
+UTF8Toascii(unsigned char* out, int *outlen,
+              const unsigned char* in, int *inlen) {
+    const unsigned char* processed = in;
+    const unsigned char* outend;
+    const unsigned char* outstart = out;
+    const unsigned char* instart = in;
+    const unsigned char* inend;
+    unsigned int c, d;
+    int trailing;
+
+    if (in == NULL) {
+        /*
+	 * initialization nothing to do
+	 */
+	*outlen = 0;
+	*inlen = 0;
+	return(0);
+    }
+    inend = in + (*inlen);
+    outend = out + (*outlen);
+    while (in < inend) {
+	d = *in++;
+	if      (d < 0x80)  { c= d; trailing= 0; }
+	else if (d < 0xC0) {
+	    /* trailing byte in leading position */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+        } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
+        else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
+        else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
+	else {
+	    /* no chance for this in Ascii */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+	}
+
+	if (inend - in < trailing) {
+	    break;
+	} 
+
+	for ( ; trailing; trailing--) {
+	    if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
+		break;
+	    c <<= 6;
+	    c |= d & 0x3F;
+	}
+
+	/* assertion: c is a single UTF-4 value */
+	if (c < 0x80) {
+	    if (out >= outend)
+		break;
+	    *out++ = c;
+	} else {
+	    /* no chance for this in Ascii */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+	}
+	processed = in;
+    }
+    *outlen = out - outstart;
+    *inlen = processed - instart;
+    return(0);
+}
+
+/**
+ * isolat1ToUTF8:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of ISO Latin 1 chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of ISO Latin 1 chars in and try to convert it to an UTF-8
+ * block of chars out.
+ * Returns 0 if success, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+int
+isolat1ToUTF8(unsigned char* out, int *outlen,
+              const unsigned char* in, int *inlen) {
+    unsigned char* outstart = out;
+    const unsigned char* base = in;
+    const unsigned char* processed = in;
+    unsigned char* outend = out + *outlen;
+    const unsigned char* inend;
+    unsigned int c;
+    int bits;
+
+    inend = in + (*inlen);
+    while ((in < inend) && (out - outstart + 5 < *outlen)) {
+	c= *in++;
+
+	/* assertion: c is a single UTF-4 value */
+        if (out >= outend)
+	    break;
+        if      (c <    0x80) {  *out++=  c;                bits= -6; }
+        else                  {  *out++= ((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+ 
+        for ( ; bits >= 0; bits-= 6) {
+            if (out >= outend)
+	        break;
+            *out++= ((c >> bits) & 0x3F) | 0x80;
+        }
+	processed = (const unsigned char*) in;
+    }
+    *outlen = out - outstart;
+    *inlen = processed - base;
+    return(0);
+}
+
+/**
+ * UTF8Toisolat1:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of UTF-8 chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an ISO Latin 1
+ * block of chars out.
+ *
+ * Returns 0 if success, -2 if the transcoding fails, or -1 otherwise
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+int
+UTF8Toisolat1(unsigned char* out, int *outlen,
+              const unsigned char* in, int *inlen) {
+    const unsigned char* processed = in;
+    const unsigned char* outend;
+    const unsigned char* outstart = out;
+    const unsigned char* instart = in;
+    const unsigned char* inend;
+    unsigned int c, d;
+    int trailing;
+
+    if (in == NULL) {
+        /*
+	 * initialization nothing to do
+	 */
+	*outlen = 0;
+	*inlen = 0;
+	return(0);
+    }
+    inend = in + (*inlen);
+    outend = out + (*outlen);
+    while (in < inend) {
+	d = *in++;
+	if      (d < 0x80)  { c= d; trailing= 0; }
+	else if (d < 0xC0) {
+	    /* trailing byte in leading position */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+        } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
+        else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
+        else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
+	else {
+	    /* no chance for this in IsoLat1 */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+	}
+
+	if (inend - in < trailing) {
+	    break;
+	} 
+
+	for ( ; trailing; trailing--) {
+	    if (in >= inend)
+		break;
+	    if (((d= *in++) & 0xC0) != 0x80) {
+		*outlen = out - outstart;
+		*inlen = processed - instart;
+		return(-2);
+	    }
+	    c <<= 6;
+	    c |= d & 0x3F;
+	}
+
+	/* assertion: c is a single UTF-4 value */
+	if (c <= 0xFF) {
+	    if (out >= outend)
+		break;
+	    *out++ = c;
+	} else {
+	    /* no chance for this in IsoLat1 */
+	    *outlen = out - outstart;
+	    *inlen = processed - instart;
+	    return(-2);
+	}
+	processed = in;
+    }
+    *outlen = out - outstart;
+    *inlen = processed - instart;
+    return(0);
+}
+
+/**
+ * UTF16LEToUTF8:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @inb:  a pointer to an array of UTF-16LE passwd as a byte array
+ * @inlenb:  the length of @in in UTF-16LE chars
+ *
+ * Take a block of UTF-16LE ushorts in and try to convert it to an UTF-8
+ * block of chars out. This function assume the endian properity
+ * is the same between the native type of this machine and the
+ * inputed one.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding fails (for *in is not valid utf16 string)
+ *     The value of *inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ */
+int
+UTF16LEToUTF8(unsigned char* out, int *outlen,
+            const unsigned char* inb, int *inlenb)
+{
+    unsigned char* outstart = out;
+    const unsigned char* processed = inb;
+    unsigned char* outend = out + *outlen;
+    unsigned short* in = (unsigned short*) inb;
+    unsigned short* inend;
+    unsigned int c, d, inlen;
+    unsigned char *tmp;
+    int bits;
+
+    if ((*inlenb % 2) == 1)
+        (*inlenb)--;
+    inlen = *inlenb / 2;
+    inend = in + inlen;
+    while ((in < inend) && (out - outstart + 5 < *outlen)) {
+        if (xmlLittleEndian) {
+	    c= *in++;
+	} else {
+	    tmp = (unsigned char *) in;
+	    c = *tmp++;
+	    c = c | (((unsigned int)*tmp) << 8);
+	    in++;
+	}
+        if ((c & 0xFC00) == 0xD800) {    /* surrogates */
+	    if (in >= inend) {           /* (in > inend) shouldn't happens */
+		break;
+	    }
+	    if (xmlLittleEndian) {
+		d = *in++;
+	    } else {
+		tmp = (unsigned char *) in;
+		d = *tmp++;
+		d = d | (((unsigned int)*tmp) << 8);
+		in++;
+	    }
+            if ((d & 0xFC00) == 0xDC00) {
+                c &= 0x03FF;
+                c <<= 10;
+                c |= d & 0x03FF;
+                c += 0x10000;
+            }
+            else {
+		*outlen = out - outstart;
+		*inlenb = processed - inb;
+	        return(-2);
+	    }
+        }
+
+	/* assertion: c is a single UTF-4 value */
+        if (out >= outend)
+	    break;
+        if      (c <    0x80) {  *out++=  c;                bits= -6; }
+        else if (c <   0x800) {  *out++= ((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+        else if (c < 0x10000) {  *out++= ((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+        else                  {  *out++= ((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+ 
+        for ( ; bits >= 0; bits-= 6) {
+            if (out >= outend)
+	        break;
+            *out++= ((c >> bits) & 0x3F) | 0x80;
+        }
+	processed = (const unsigned char*) in;
+    }
+    *outlen = out - outstart;
+    *inlenb = processed - inb;
+    return(0);
+}
+
+/**
+ * UTF8ToUTF16LE:
+ * @outb:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @outb
+ * @in:  a pointer to an array of UTF-8 chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an UTF-16LE
+ * block of chars out.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding failed. 
+ */
+int
+UTF8ToUTF16LE(unsigned char* outb, int *outlen,
+            const unsigned char* in, int *inlen)
+{
+    unsigned short* out = (unsigned short*) outb;
+    const unsigned char* processed = in;
+    unsigned short* outstart= out;
+    unsigned short* outend;
+    const unsigned char* inend= in+*inlen;
+    unsigned int c, d;
+    int trailing;
+    unsigned char *tmp;
+    unsigned short tmp1, tmp2;
+
+    if (in == NULL) {
+        /*
+	 * initialization, add the Byte Order Mark
+	 */
+        if (*outlen >= 2) {
+	    outb[0] = 0xFF;
+	    outb[1] = 0xFE;
+	    *outlen = 2;
+	    *inlen = 0;
+#ifdef DEBUG_ENCODING
+            xmlGenericError(xmlGenericErrorContext,
+		    "Added FFFE Byte Order Mark\n");
+#endif
+	    return(2);
+	}
+	*outlen = 0;
+	*inlen = 0;
+	return(0);
+    }
+    outend = out + (*outlen / 2);
+    while (in < inend) {
+      d= *in++;
+      if      (d < 0x80)  { c= d; trailing= 0; }
+      else if (d < 0xC0) {
+          /* trailing byte in leading position */
+	  *outlen = (out - outstart) * 2;
+	  *inlen = processed - in;
+	  return(-2);
+      } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
+      else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
+      else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
+      else {
+	/* no chance for this in UTF-16 */
+	*outlen = (out - outstart) * 2;
+	*inlen = processed - in;
+	return(-2);
+      }
+
+      if (inend - in < trailing) {
+          break;
+      } 
+
+      for ( ; trailing; trailing--) {
+          if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))
+	      break;
+          c <<= 6;
+          c |= d & 0x3F;
+      }
+
+      /* assertion: c is a single UTF-4 value */
+        if (c < 0x10000) {
+            if (out >= outend)
+	        break;
+	    if (xmlLittleEndian) {
+		*out++ = c;
+	    } else {
+		tmp = (unsigned char *) out;
+		*tmp = c ;
+		*(tmp + 1) = c >> 8 ;
+		out++;
+	    }
+        }
+        else if (c < 0x110000) {
+            if (out+1 >= outend)
+	        break;
+            c -= 0x10000;
+	    if (xmlLittleEndian) {
+		*out++ = 0xD800 | (c >> 10);
+		*out++ = 0xDC00 | (c & 0x03FF);
+	    } else {
+		tmp1 = 0xD800 | (c >> 10);
+		tmp = (unsigned char *) out;
+		*tmp = (unsigned char) tmp1;
+		*(tmp + 1) = tmp1 >> 8;
+		out++;
+
+		tmp2 = 0xDC00 | (c & 0x03FF);
+		tmp = (unsigned char *) out;
+		*tmp  = (unsigned char) tmp2;
+		*(tmp + 1) = tmp2 >> 8;
+		out++;
+	    }
+        }
+        else
+	    break;
+	processed = in;
+    }
+    *outlen = (out - outstart) * 2;
+    *inlen = processed - in;
+    return(0);
+}
+
+/**
+ * UTF16BEToUTF8:
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @inb:  a pointer to an array of UTF-16 passwd as a byte array
+ * @inlenb:  the length of @in in UTF-16 chars
+ *
+ * Take a block of UTF-16 ushorts in and try to convert it to an UTF-8
+ * block of chars out. This function assume the endian properity
+ * is the same between the native type of this machine and the
+ * inputed one.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding fails (for *in is not valid utf16 string)
+ * The value of *inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ */
+int
+UTF16BEToUTF8(unsigned char* out, int *outlen,
+            const unsigned char* inb, int *inlenb)
+{
+    unsigned char* outstart = out;
+    const unsigned char* processed = inb;
+    unsigned char* outend = out + *outlen;
+    unsigned short* in = (unsigned short*) inb;
+    unsigned short* inend;
+    unsigned int c, d, inlen;
+    unsigned char *tmp;
+    int bits;
+
+    if ((*inlenb % 2) == 1)
+        (*inlenb)--;
+    inlen = *inlenb / 2;
+    inend= in + inlen;
+    while (in < inend) {
+	if (xmlLittleEndian) {
+	    tmp = (unsigned char *) in;
+	    c = *tmp++;
+	    c = c << 8;
+	    c = c | (unsigned int) *tmp;
+	    in++;
+	} else {
+	    c= *in++;
+	} 
+        if ((c & 0xFC00) == 0xD800) {    /* surrogates */
+	    if (in >= inend) {           /* (in > inend) shouldn't happens */
+		*outlen = out - outstart;
+		*inlenb = processed - inb;
+	        return(-2);
+	    }
+	    if (xmlLittleEndian) {
+		tmp = (unsigned char *) in;
+		d = *tmp++;
+		d = d << 8;
+		d = d | (unsigned int) *tmp;
+		in++;
+	    } else {
+		d= *in++;
+	    }
+            if ((d & 0xFC00) == 0xDC00) {
+                c &= 0x03FF;
+                c <<= 10;
+                c |= d & 0x03FF;
+                c += 0x10000;
+            }
+            else {
+		*outlen = out - outstart;
+		*inlenb = processed - inb;
+	        return(-2);
+	    }
+        }
+
+	/* assertion: c is a single UTF-4 value */
+        if (out >= outend) 
+	    break;
+        if      (c <    0x80) {  *out++=  c;                bits= -6; }
+        else if (c <   0x800) {  *out++= ((c >>  6) & 0x1F) | 0xC0;  bits=  0; }
+        else if (c < 0x10000) {  *out++= ((c >> 12) & 0x0F) | 0xE0;  bits=  6; }
+        else                  {  *out++= ((c >> 18) & 0x07) | 0xF0;  bits= 12; }
+ 
+        for ( ; bits >= 0; bits-= 6) {
+            if (out >= outend) 
+	        break;
+            *out++= ((c >> bits) & 0x3F) | 0x80;
+        }
+	processed = (const unsigned char*) in;
+    }
+    *outlen = out - outstart;
+    *inlenb = processed - inb;
+    return(0);
+}
+
+/**
+ * UTF8ToUTF16BE:
+ * @outb:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @outb
+ * @in:  a pointer to an array of UTF-8 chars
+ * @inlen:  the length of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an UTF-16BE
+ * block of chars out.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding failed. 
+ */
+int
+UTF8ToUTF16BE(unsigned char* outb, int *outlen,
+            const unsigned char* in, int *inlen)
+{
+    unsigned short* out = (unsigned short*) outb;
+    const unsigned char* processed = in;
+    unsigned short* outstart= out;
+    unsigned short* outend;
+    const unsigned char* inend= in+*inlen;
+    unsigned int c, d;
+    int trailing;
+    unsigned char *tmp;
+    unsigned short tmp1, tmp2;
+
+    if (in == NULL) {
+        /*
+	 * initialization, add the Byte Order Mark
+	 */
+        if (*outlen >= 2) {
+	    outb[0] = 0xFE;
+	    outb[1] = 0xFF;
+	    *outlen = 2;
+	    *inlen = 0;
+#ifdef DEBUG_ENCODING
+            xmlGenericError(xmlGenericErrorContext,
+		    "Added FEFF Byte Order Mark\n");
+#endif
+	    return(2);
+	}
+	*outlen = 0;
+	*inlen = 0;
+	return(0);
+    }
+    outend = out + (*outlen / 2);
+    while (in < inend) {
+      d= *in++;
+      if      (d < 0x80)  { c= d; trailing= 0; }
+      else if (d < 0xC0)  {
+          /* trailing byte in leading position */
+	  *outlen = out - outstart;
+	  *inlen = processed - in;
+	  return(-2);
+      } else if (d < 0xE0)  { c= d & 0x1F; trailing= 1; }
+      else if (d < 0xF0)  { c= d & 0x0F; trailing= 2; }
+      else if (d < 0xF8)  { c= d & 0x07; trailing= 3; }
+      else {
+          /* no chance for this in UTF-16 */
+	  *outlen = out - outstart;
+	  *inlen = processed - in;
+	  return(-2);
+      }
+
+      if (inend - in < trailing) {
+          break;
+      } 
+
+      for ( ; trailing; trailing--) {
+          if ((in >= inend) || (((d= *in++) & 0xC0) != 0x80))  break;
+          c <<= 6;
+          c |= d & 0x3F;
+      }
+
+      /* assertion: c is a single UTF-4 value */
+        if (c < 0x10000) {
+            if (out >= outend)  break;
+	    if (xmlLittleEndian) {
+		tmp = (unsigned char *) out;
+		*tmp = c >> 8;
+		*(tmp + 1) = c;
+		out++;
+	    } else {
+		*out++ = c;
+	    }
+        }
+        else if (c < 0x110000) {
+            if (out+1 >= outend)  break;
+            c -= 0x10000;
+	    if (xmlLittleEndian) {
+		tmp1 = 0xD800 | (c >> 10);
+		tmp = (unsigned char *) out;
+		*tmp = tmp1 >> 8;
+		*(tmp + 1) = (unsigned char) tmp1;
+		out++;
+
+		tmp2 = 0xDC00 | (c & 0x03FF);
+		tmp = (unsigned char *) out;
+		*tmp = tmp2 >> 8;
+		*(tmp + 1) = (unsigned char) tmp2;
+		out++;
+	    } else {
+		*out++ = 0xD800 | (c >> 10);
+		*out++ = 0xDC00 | (c & 0x03FF);
+	    }
+        }
+        else
+	    break;
+	processed = in;
+    }
+    *outlen = (out - outstart) * 2;
+    *inlen = processed - in;
+    return(0);
+}
+
+/**
+ * xmlDetectCharEncoding:
+ * @in:  a pointer to the first bytes of the XML entity, must be at least
+ *       4 bytes long.
+ * @len:  pointer to the length of the buffer
+ *
+ * Guess the encoding of the entity using the first bytes of the entity content
+ * accordingly of the non-normative appendix F of the XML-1.0 recommendation.
+ * 
+ * Returns one of the XML_CHAR_ENCODING_... values.
+ */
+xmlCharEncoding
+xmlDetectCharEncoding(const unsigned char* in, int len)
+{
+    if (len >= 4) {
+	if ((in[0] == 0x00) && (in[1] == 0x00) &&
+	    (in[2] == 0x00) && (in[3] == 0x3C))
+	    return(XML_CHAR_ENCODING_UCS4BE);
+	if ((in[0] == 0x3C) && (in[1] == 0x00) &&
+	    (in[2] == 0x00) && (in[3] == 0x00))
+	    return(XML_CHAR_ENCODING_UCS4LE);
+	if ((in[0] == 0x00) && (in[1] == 0x00) &&
+	    (in[2] == 0x3C) && (in[3] == 0x00))
+	    return(XML_CHAR_ENCODING_UCS4_2143);
+	if ((in[0] == 0x00) && (in[1] == 0x3C) &&
+	    (in[2] == 0x00) && (in[3] == 0x00))
+	    return(XML_CHAR_ENCODING_UCS4_3412);
+	if ((in[0] == 0x4C) && (in[1] == 0x6F) &&
+	    (in[2] == 0xA7) && (in[3] == 0x94))
+	    return(XML_CHAR_ENCODING_EBCDIC);
+	if ((in[0] == 0x3C) && (in[1] == 0x3F) &&
+	    (in[2] == 0x78) && (in[3] == 0x6D))
+	    return(XML_CHAR_ENCODING_UTF8);
+    }
+    if (len >= 2) {
+	if ((in[0] == 0xFE) && (in[1] == 0xFF))
+	    return(XML_CHAR_ENCODING_UTF16BE);
+	if ((in[0] == 0xFF) && (in[1] == 0xFE))
+	    return(XML_CHAR_ENCODING_UTF16LE);
+    }
+    return(XML_CHAR_ENCODING_NONE);
+}
+
+/**
+ * xmlCleanupEncodingAliases:
+ *
+ * Unregisters all aliases
+ */
+void
+xmlCleanupEncodingAliases(void) {
+    int i;
+
+    if (xmlCharEncodingAliases == NULL)
+	return;
+
+    for (i = 0;i < xmlCharEncodingAliasesNb;i++) {
+	if (xmlCharEncodingAliases[i].name != NULL)
+	    xmlFree((char *) xmlCharEncodingAliases[i].name);
+	if (xmlCharEncodingAliases[i].alias != NULL)
+	    xmlFree((char *) xmlCharEncodingAliases[i].alias);
+    }
+    xmlCharEncodingAliasesNb = 0;
+    xmlCharEncodingAliasesMax = 0;
+    xmlFree(xmlCharEncodingAliases);
+}
+
+/**
+ * xmlGetEncodingAlias:
+ * @alias:  the alias name as parsed, in UTF-8 format (ASCII actually)
+ *
+ * Lookup an encoding name for the given alias.
+ * 
+ * Returns NULL if not found the original name otherwise
+ */
+const char *
+xmlGetEncodingAlias(const char *alias) {
+    int i;
+    char upper[100];
+
+    if (alias == NULL)
+	return(NULL);
+
+    if (xmlCharEncodingAliases == NULL)
+	return(NULL);
+
+    for (i = 0;i < 99;i++) {
+        upper[i] = toupper(alias[i]);
+	if (upper[i] == 0) break;
+    }
+    upper[i] = 0;
+
+    /*
+     * Walk down the list looking for a definition of the alias
+     */
+    for (i = 0;i < xmlCharEncodingAliasesNb;i++) {
+	if (!strcmp(xmlCharEncodingAliases[i].alias, upper)) {
+	    return(xmlCharEncodingAliases[i].name);
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xmlAddEncodingAlias:
+ * @name:  the encoding name as parsed, in UTF-8 format (ASCII actually)
+ * @alias:  the alias name as parsed, in UTF-8 format (ASCII actually)
+ *
+ * Registers and alias @alias for an encoding named @name. Existing alias
+ * will be overwritten.
+ * 
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xmlAddEncodingAlias(const char *name, const char *alias) {
+    int i;
+    char upper[100];
+
+    if ((name == NULL) || (alias == NULL))
+	return(-1);
+
+    for (i = 0;i < 99;i++) {
+        upper[i] = toupper(alias[i]);
+	if (upper[i] == 0) break;
+    }
+    upper[i] = 0;
+
+    if (xmlCharEncodingAliases == NULL) {
+	xmlCharEncodingAliasesNb = 0;
+	xmlCharEncodingAliasesMax = 20;
+	xmlCharEncodingAliases = (xmlCharEncodingAliasPtr) 
+	      xmlMalloc(xmlCharEncodingAliasesMax * sizeof(xmlCharEncodingAlias));
+	if (xmlCharEncodingAliases == NULL)
+	    return(-1);
+    } else if (xmlCharEncodingAliasesNb >= xmlCharEncodingAliasesMax) {
+	xmlCharEncodingAliasesMax *= 2;
+	xmlCharEncodingAliases = (xmlCharEncodingAliasPtr) 
+	      xmlRealloc(xmlCharEncodingAliases,
+		         xmlCharEncodingAliasesMax * sizeof(xmlCharEncodingAlias));
+    }
+    /*
+     * Walk down the list looking for a definition of the alias
+     */
+    for (i = 0;i < xmlCharEncodingAliasesNb;i++) {
+	if (!strcmp(xmlCharEncodingAliases[i].alias, upper)) {
+	    /*
+	     * Replace the definition.
+	     */
+	    xmlFree((char *) xmlCharEncodingAliases[i].name);
+	    xmlCharEncodingAliases[i].name = xmlMemStrdup(name);
+	    return(0);
+	}
+    }
+    /*
+     * Add the definition
+     */
+    xmlCharEncodingAliases[xmlCharEncodingAliasesNb].name = xmlMemStrdup(name);
+    xmlCharEncodingAliases[xmlCharEncodingAliasesNb].alias = xmlMemStrdup(upper);
+    xmlCharEncodingAliasesNb++;
+    return(0);
+}
+
+/**
+ * xmlDelEncodingAlias:
+ * @alias:  the alias name as parsed, in UTF-8 format (ASCII actually)
+ *
+ * Unregisters an encoding alias @alias
+ * 
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xmlDelEncodingAlias(const char *alias) {
+    int i;
+
+    if (alias == NULL)
+	return(-1);
+
+    if (xmlCharEncodingAliases == NULL)
+	return(-1);
+    /*
+     * Walk down the list looking for a definition of the alias
+     */
+    for (i = 0;i < xmlCharEncodingAliasesNb;i++) {
+	if (!strcmp(xmlCharEncodingAliases[i].alias, alias)) {
+	    xmlFree((char *) xmlCharEncodingAliases[i].name);
+	    xmlFree((char *) xmlCharEncodingAliases[i].alias);
+	    xmlCharEncodingAliasesNb--;
+	    memmove(&xmlCharEncodingAliases[i], &xmlCharEncodingAliases[i + 1],
+		    sizeof(xmlCharEncodingAlias) * (xmlCharEncodingAliasesNb - i));
+	    return(0);
+	}
+    }
+    return(-1);
+}
+
+/**
+ * xmlParseCharEncoding:
+ * @name:  the encoding name as parsed, in UTF-8 format (ASCII actually)
+ *
+ * Conpare the string to the known encoding schemes already known. Note
+ * that the comparison is case insensitive accordingly to the section
+ * [XML] 4.3.3 Character Encoding in Entities.
+ * 
+ * Returns one of the XML_CHAR_ENCODING_... values or XML_CHAR_ENCODING_NONE
+ * if not recognized.
+ */
+xmlCharEncoding
+xmlParseCharEncoding(const char* name)
+{
+    const char *alias;
+    char upper[500];
+    int i;
+
+    if (name == NULL)
+	return(XML_CHAR_ENCODING_NONE);
+
+    /*
+     * Do the alias resolution
+     */
+    alias = xmlGetEncodingAlias(name);
+    if (alias != NULL)
+	name = alias;
+
+    for (i = 0;i < 499;i++) {
+        upper[i] = toupper(name[i]);
+	if (upper[i] == 0) break;
+    }
+    upper[i] = 0;
+
+    if (!strcmp(upper, "")) return(XML_CHAR_ENCODING_NONE);
+    if (!strcmp(upper, "UTF-8")) return(XML_CHAR_ENCODING_UTF8);
+    if (!strcmp(upper, "UTF8")) return(XML_CHAR_ENCODING_UTF8);
+
+    /*
+     * NOTE: if we were able to parse this, the endianness of UTF16 is
+     *       already found and in use
+     */
+    if (!strcmp(upper, "UTF-16")) return(XML_CHAR_ENCODING_UTF16LE);
+    if (!strcmp(upper, "UTF16")) return(XML_CHAR_ENCODING_UTF16LE);
+    
+    if (!strcmp(upper, "ISO-10646-UCS-2")) return(XML_CHAR_ENCODING_UCS2);
+    if (!strcmp(upper, "UCS-2")) return(XML_CHAR_ENCODING_UCS2);
+    if (!strcmp(upper, "UCS2")) return(XML_CHAR_ENCODING_UCS2);
+
+    /*
+     * NOTE: if we were able to parse this, the endianness of UCS4 is
+     *       already found and in use
+     */
+    if (!strcmp(upper, "ISO-10646-UCS-4")) return(XML_CHAR_ENCODING_UCS4LE);
+    if (!strcmp(upper, "UCS-4")) return(XML_CHAR_ENCODING_UCS4LE);
+    if (!strcmp(upper, "UCS4")) return(XML_CHAR_ENCODING_UCS4LE);
+
+    
+    if (!strcmp(upper,  "ISO-8859-1")) return(XML_CHAR_ENCODING_8859_1);
+    if (!strcmp(upper,  "ISO-LATIN-1")) return(XML_CHAR_ENCODING_8859_1);
+    if (!strcmp(upper,  "ISO LATIN 1")) return(XML_CHAR_ENCODING_8859_1);
+
+    if (!strcmp(upper,  "ISO-8859-2")) return(XML_CHAR_ENCODING_8859_2);
+    if (!strcmp(upper,  "ISO-LATIN-2")) return(XML_CHAR_ENCODING_8859_2);
+    if (!strcmp(upper,  "ISO LATIN 2")) return(XML_CHAR_ENCODING_8859_2);
+
+    if (!strcmp(upper,  "ISO-8859-3")) return(XML_CHAR_ENCODING_8859_3);
+    if (!strcmp(upper,  "ISO-8859-4")) return(XML_CHAR_ENCODING_8859_4);
+    if (!strcmp(upper,  "ISO-8859-5")) return(XML_CHAR_ENCODING_8859_5);
+    if (!strcmp(upper,  "ISO-8859-6")) return(XML_CHAR_ENCODING_8859_6);
+    if (!strcmp(upper,  "ISO-8859-7")) return(XML_CHAR_ENCODING_8859_7);
+    if (!strcmp(upper,  "ISO-8859-8")) return(XML_CHAR_ENCODING_8859_8);
+    if (!strcmp(upper,  "ISO-8859-9")) return(XML_CHAR_ENCODING_8859_9);
+
+    if (!strcmp(upper, "ISO-2022-JP")) return(XML_CHAR_ENCODING_2022_JP);
+    if (!strcmp(upper, "SHIFT_JIS")) return(XML_CHAR_ENCODING_SHIFT_JIS);
+    if (!strcmp(upper, "EUC-JP")) return(XML_CHAR_ENCODING_EUC_JP);
+
+#ifdef DEBUG_ENCODING
+    xmlGenericError(xmlGenericErrorContext, "Unknown encoding %s\n", name);
+#endif
+    return(XML_CHAR_ENCODING_ERROR);
+}
+
+/**
+ * xmlGetCharEncodingName:
+ * @enc:  the encoding
+ *
+ * The "canonical" name for XML encoding.
+ * C.f. http://www.w3.org/TR/REC-xml#charencoding
+ * Section 4.3.3  Character Encoding in Entities
+ *
+ * Returns the canonical name for the given encoding
+ */
+
+const char*
+xmlGetCharEncodingName(xmlCharEncoding enc) {
+    switch (enc) {
+        case XML_CHAR_ENCODING_ERROR:
+	    return(NULL);
+        case XML_CHAR_ENCODING_NONE:
+	    return(NULL);
+        case XML_CHAR_ENCODING_UTF8:
+	    return("UTF-8");
+        case XML_CHAR_ENCODING_UTF16LE:
+	    return("UTF-16");
+        case XML_CHAR_ENCODING_UTF16BE:
+	    return("UTF-16");
+        case XML_CHAR_ENCODING_EBCDIC:
+            return("EBCDIC");
+        case XML_CHAR_ENCODING_UCS4LE:
+            return("ISO-10646-UCS-4");
+        case XML_CHAR_ENCODING_UCS4BE:
+            return("ISO-10646-UCS-4");
+        case XML_CHAR_ENCODING_UCS4_2143:
+            return("ISO-10646-UCS-4");
+        case XML_CHAR_ENCODING_UCS4_3412:
+            return("ISO-10646-UCS-4");
+        case XML_CHAR_ENCODING_UCS2:
+            return("ISO-10646-UCS-2");
+        case XML_CHAR_ENCODING_8859_1:
+	    return("ISO-8859-1");
+        case XML_CHAR_ENCODING_8859_2:
+	    return("ISO-8859-2");
+        case XML_CHAR_ENCODING_8859_3:
+	    return("ISO-8859-3");
+        case XML_CHAR_ENCODING_8859_4:
+	    return("ISO-8859-4");
+        case XML_CHAR_ENCODING_8859_5:
+	    return("ISO-8859-5");
+        case XML_CHAR_ENCODING_8859_6:
+	    return("ISO-8859-6");
+        case XML_CHAR_ENCODING_8859_7:
+	    return("ISO-8859-7");
+        case XML_CHAR_ENCODING_8859_8:
+	    return("ISO-8859-8");
+        case XML_CHAR_ENCODING_8859_9:
+	    return("ISO-8859-9");
+        case XML_CHAR_ENCODING_2022_JP:
+            return("ISO-2022-JP");
+        case XML_CHAR_ENCODING_SHIFT_JIS:
+            return("Shift-JIS");
+        case XML_CHAR_ENCODING_EUC_JP:
+            return("EUC-JP");
+	case XML_CHAR_ENCODING_ASCII:
+	    return(NULL);
+    }
+    return(NULL);
+}
+
+/****************************************************************
+ *								*
+ *		Char encoding handlers				*
+ *								*
+ ****************************************************************/
+
+/* the size should be growable, but it's not a big deal ... */
+#define MAX_ENCODING_HANDLERS 50
+static xmlCharEncodingHandlerPtr *handlers = NULL;
+static int nbCharEncodingHandler = 0;
+
+/*
+ * The default is UTF-8 for XML, that's also the default used for the
+ * parser internals, so the default encoding handler is NULL
+ */
+
+static xmlCharEncodingHandlerPtr xmlDefaultCharEncodingHandler = NULL;
+
+/**
+ * xmlNewCharEncodingHandler:
+ * @name:  the encoding name, in UTF-8 format (ASCII actually)
+ * @input:  the xmlCharEncodingInputFunc to read that encoding
+ * @output:  the xmlCharEncodingOutputFunc to write that encoding
+ *
+ * Create and registers an xmlCharEncodingHandler.
+ * Returns the xmlCharEncodingHandlerPtr created (or NULL in case of error).
+ */
+xmlCharEncodingHandlerPtr
+xmlNewCharEncodingHandler(const char *name, 
+                          xmlCharEncodingInputFunc input,
+                          xmlCharEncodingOutputFunc output) {
+    xmlCharEncodingHandlerPtr handler;
+    const char *alias;
+    char upper[500];
+    int i;
+    char *up = 0;
+
+    /*
+     * Do the alias resolution
+     */
+    alias = xmlGetEncodingAlias(name);
+    if (alias != NULL)
+	name = alias;
+
+    /*
+     * Keep only the uppercase version of the encoding.
+     */
+    if (name == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewCharEncodingHandler : no name !\n");
+	return(NULL);
+    }
+    for (i = 0;i < 499;i++) {
+        upper[i] = toupper(name[i]);
+	if (upper[i] == 0) break;
+    }
+    upper[i] = 0;
+    up = xmlMemStrdup(upper);
+    if (up == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewCharEncodingHandler : out of memory !\n");
+	return(NULL);
+    }
+
+    /*
+     * allocate and fill-up an handler block.
+     */
+    handler = (xmlCharEncodingHandlerPtr)
+              xmlMalloc(sizeof(xmlCharEncodingHandler));
+    if (handler == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewCharEncodingHandler : out of memory !\n");
+	return(NULL);
+    }
+    handler->input = input;
+    handler->output = output;
+    handler->name = up;
+
+#ifdef LIBXML_ICONV_ENABLED
+    handler->iconv_in = NULL;
+    handler->iconv_out = NULL;
+#endif /* LIBXML_ICONV_ENABLED */
+
+    /*
+     * registers and returns the handler.
+     */
+    xmlRegisterCharEncodingHandler(handler);
+#ifdef DEBUG_ENCODING
+    xmlGenericError(xmlGenericErrorContext,
+	    "Registered encoding handler for %s\n", name);
+#endif
+    return(handler);
+}
+
+/**
+ * xmlInitCharEncodingHandlers:
+ *
+ * Initialize the char encoding support, it registers the default
+ * encoding supported.
+ * NOTE: while public, this function usually doesn't need to be called
+ *       in normal processing.
+ */
+void
+xmlInitCharEncodingHandlers(void) {
+    unsigned short int tst = 0x1234;
+    unsigned char *ptr = (unsigned char *) &tst; 
+
+    if (handlers != NULL) return;
+
+    handlers = (xmlCharEncodingHandlerPtr *)
+        xmlMalloc(MAX_ENCODING_HANDLERS * sizeof(xmlCharEncodingHandlerPtr));
+
+    if (*ptr == 0x12) xmlLittleEndian = 0;
+    else if (*ptr == 0x34) xmlLittleEndian = 1;
+    else xmlGenericError(xmlGenericErrorContext,
+	    "Odd problem at endianness detection\n");
+
+    if (handlers == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlInitCharEncodingHandlers : out of memory !\n");
+	return;
+    }
+    xmlNewCharEncodingHandler("UTF-8", NULL, NULL);
+    xmlUTF16LEHandler = 
+          xmlNewCharEncodingHandler("UTF-16LE", UTF16LEToUTF8, UTF8ToUTF16LE);
+    xmlUTF16BEHandler = 
+          xmlNewCharEncodingHandler("UTF-16BE", UTF16BEToUTF8, UTF8ToUTF16BE);
+    xmlNewCharEncodingHandler("ISO-8859-1", isolat1ToUTF8, UTF8Toisolat1);
+    xmlNewCharEncodingHandler("ASCII", asciiToUTF8, UTF8Toascii);
+#ifdef LIBXML_HTML_ENABLED
+    xmlNewCharEncodingHandler("HTML", NULL, UTF8ToHtml);
+#endif
+}
+
+/**
+ * xmlCleanupCharEncodingHandlers:
+ *
+ * Cleanup the memory allocated for the char encoding support, it
+ * unregisters all the encoding handlers and the aliases.
+ */
+void
+xmlCleanupCharEncodingHandlers(void) {
+    xmlCleanupEncodingAliases();
+
+    if (handlers == NULL) return;
+
+    for (;nbCharEncodingHandler > 0;) {
+        nbCharEncodingHandler--;
+	if (handlers[nbCharEncodingHandler] != NULL) {
+	    if (handlers[nbCharEncodingHandler]->name != NULL)
+		xmlFree(handlers[nbCharEncodingHandler]->name);
+	    xmlFree(handlers[nbCharEncodingHandler]);
+	}
+    }
+    xmlFree(handlers);
+    handlers = NULL;
+    nbCharEncodingHandler = 0;
+    xmlDefaultCharEncodingHandler = NULL;
+}
+
+/**
+ * xmlRegisterCharEncodingHandler:
+ * @handler:  the xmlCharEncodingHandlerPtr handler block
+ *
+ * Register the char encoding handler, surprizing, isn't it ?
+ */
+void
+xmlRegisterCharEncodingHandler(xmlCharEncodingHandlerPtr handler) {
+    if (handlers == NULL) xmlInitCharEncodingHandlers();
+    if (handler == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlRegisterCharEncodingHandler: NULL handler !\n");
+	return;
+    }
+
+    if (nbCharEncodingHandler >= MAX_ENCODING_HANDLERS) {
+        xmlGenericError(xmlGenericErrorContext, 
+	"xmlRegisterCharEncodingHandler: Too many handler registered\n");
+        xmlGenericError(xmlGenericErrorContext,
+		"\tincrease MAX_ENCODING_HANDLERS : %s\n", __FILE__);
+	return;
+    }
+    handlers[nbCharEncodingHandler++] = handler;
+}
+
+/**
+ * xmlGetCharEncodingHandler:
+ * @enc:  an xmlCharEncoding value.
+ *
+ * Search in the registrered set the handler able to read/write that encoding.
+ *
+ * Returns the handler or NULL if not found
+ */
+xmlCharEncodingHandlerPtr
+xmlGetCharEncodingHandler(xmlCharEncoding enc) {
+    xmlCharEncodingHandlerPtr handler;
+
+    if (handlers == NULL) xmlInitCharEncodingHandlers();
+    switch (enc) {
+        case XML_CHAR_ENCODING_ERROR:
+	    return(NULL);
+        case XML_CHAR_ENCODING_NONE:
+	    return(NULL);
+        case XML_CHAR_ENCODING_UTF8:
+	    return(NULL);
+        case XML_CHAR_ENCODING_UTF16LE:
+	    return(xmlUTF16LEHandler);
+        case XML_CHAR_ENCODING_UTF16BE:
+	    return(xmlUTF16BEHandler);
+        case XML_CHAR_ENCODING_EBCDIC:
+            handler = xmlFindCharEncodingHandler("EBCDIC");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("ebcdic");
+            if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_UCS4BE:
+            handler = xmlFindCharEncodingHandler("ISO-10646-UCS-4");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("UCS-4");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("UCS4");
+            if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_UCS4LE:
+            handler = xmlFindCharEncodingHandler("ISO-10646-UCS-4");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("UCS-4");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("UCS4");
+            if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_UCS4_2143:
+	    break;
+        case XML_CHAR_ENCODING_UCS4_3412:
+	    break;
+        case XML_CHAR_ENCODING_UCS2:
+            handler = xmlFindCharEncodingHandler("ISO-10646-UCS-2");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("UCS-2");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("UCS2");
+            if (handler != NULL) return(handler);
+	    break;
+
+	    /*
+	     * We used to keep ISO Latin encodings native in the
+	     * generated data. This led to so many problems that
+	     * this has been removed. One can still change this
+	     * back by registering no-ops encoders for those
+	     */
+        case XML_CHAR_ENCODING_8859_1:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-1");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_2:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-2");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_3:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-3");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_4:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-4");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_5:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-5");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_6:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-6");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_7:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-7");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_8:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-8");
+	    if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_8859_9:
+	    handler = xmlFindCharEncodingHandler("ISO-8859-9");
+	    if (handler != NULL) return(handler);
+	    break;
+
+
+        case XML_CHAR_ENCODING_2022_JP:
+            handler = xmlFindCharEncodingHandler("ISO-2022-JP");
+            if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_SHIFT_JIS:
+            handler = xmlFindCharEncodingHandler("SHIFT-JIS");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("SHIFT_JIS");
+            if (handler != NULL) return(handler);
+            handler = xmlFindCharEncodingHandler("Shift_JIS");
+            if (handler != NULL) return(handler);
+	    break;
+        case XML_CHAR_ENCODING_EUC_JP:
+            handler = xmlFindCharEncodingHandler("EUC-JP");
+            if (handler != NULL) return(handler);
+	    break;
+	default: 
+	    break;
+    }
+    
+#ifdef DEBUG_ENCODING
+    xmlGenericError(xmlGenericErrorContext,
+	    "No handler found for encoding %d\n", enc);
+#endif
+    return(NULL);
+}
+
+/**
+ * xmlGetCharEncodingHandler:
+ * @enc:  a string describing the char encoding.
+ *
+ * Search in the registrered set the handler able to read/write that encoding.
+ *
+ * Returns the handler or NULL if not found
+ */
+xmlCharEncodingHandlerPtr
+xmlFindCharEncodingHandler(const char *name) {
+    const char *nalias;
+    const char *norig;
+    xmlCharEncoding alias;
+#ifdef LIBXML_ICONV_ENABLED
+    xmlCharEncodingHandlerPtr enc;
+    iconv_t icv_in, icv_out;
+#endif /* LIBXML_ICONV_ENABLED */
+    char upper[100];
+    int i;
+
+    if (handlers == NULL) xmlInitCharEncodingHandlers();
+    if (name == NULL) return(xmlDefaultCharEncodingHandler);
+    if (name[0] == 0) return(xmlDefaultCharEncodingHandler);
+
+    /*
+     * Do the alias resolution
+     */
+    norig = name;
+    nalias = xmlGetEncodingAlias(name);
+    if (nalias != NULL)
+	name = nalias;
+
+    /*
+     * Check first for directly registered encoding names
+     */
+    for (i = 0;i < 99;i++) {
+        upper[i] = toupper(name[i]);
+	if (upper[i] == 0) break;
+    }
+    upper[i] = 0;
+
+    for (i = 0;i < nbCharEncodingHandler; i++)
+        if (!strcmp(upper, handlers[i]->name)) {
+#ifdef DEBUG_ENCODING
+            xmlGenericError(xmlGenericErrorContext,
+		    "Found registered handler for encoding %s\n", name);
+#endif
+	    return(handlers[i]);
+	}
+
+#ifdef LIBXML_ICONV_ENABLED
+    /* check whether iconv can handle this */
+    icv_in = iconv_open("UTF-8", name);
+    icv_out = iconv_open(name, "UTF-8");
+    if ((icv_in != (iconv_t) -1) && (icv_out != (iconv_t) -1)) {
+	    enc = (xmlCharEncodingHandlerPtr)
+	          xmlMalloc(sizeof(xmlCharEncodingHandler));
+	    if (enc == NULL) {
+	        iconv_close(icv_in);
+	        iconv_close(icv_out);
+		return(NULL);
+	    }
+	    enc->name = xmlMemStrdup(name);
+	    enc->input = NULL;
+	    enc->output = NULL;
+	    enc->iconv_in = icv_in;
+	    enc->iconv_out = icv_out;
+#ifdef DEBUG_ENCODING
+            xmlGenericError(xmlGenericErrorContext,
+		    "Found iconv handler for encoding %s\n", name);
+#endif
+	    return enc;
+    } else if ((icv_in != (iconv_t) -1) || icv_out != (iconv_t) -1) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "iconv : problems with filters for '%s'\n", name);
+    }
+#endif /* LIBXML_ICONV_ENABLED */
+
+#ifdef DEBUG_ENCODING
+    xmlGenericError(xmlGenericErrorContext,
+	    "No handler found for encoding %s\n", name);
+#endif
+
+    /*
+     * Fallback using the canonical names
+     */
+    alias = xmlParseCharEncoding(norig);
+    if (alias != XML_CHAR_ENCODING_ERROR) {
+        const char* canon;
+        canon = xmlGetCharEncodingName(alias);
+        if ((canon != NULL) && (strcmp(name, canon))) {
+	    return(xmlFindCharEncodingHandler(canon));
+        }
+    }
+
+    return(NULL);
+}
+
+#ifdef LIBXML_ICONV_ENABLED
+/**
+ * xmlIconvWrapper:
+ * @cd:		iconv converter data structure
+ * @out:  a pointer to an array of bytes to store the result
+ * @outlen:  the length of @out
+ * @in:  a pointer to an array of ISO Latin 1 chars
+ * @inlen:  the length of @in
+ *
+ * Returns 0 if success, or 
+ *     -1 by lack of space, or
+ *     -2 if the transcoding fails (for *in is not valid utf8 string or
+ *        the result of transformation can't fit into the encoding we want), or
+ *     -3 if there the last byte can't form a single output char.
+ *     
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+static int
+xmlIconvWrapper(iconv_t cd,
+	unsigned char *out, int *outlen,
+	const unsigned char *in, int *inlen) {
+
+	size_t icv_inlen = *inlen, icv_outlen = *outlen;
+	const char *icv_in = (const char *) in;
+	char *icv_out = (char *) out;
+	int ret;
+
+	ret = iconv(cd,
+		&icv_in, &icv_inlen,
+		&icv_out, &icv_outlen);
+	if (in != NULL) {
+	    *inlen -= icv_inlen;
+	    *outlen -= icv_outlen;
+	} else {
+	    *inlen = 0;
+	    *outlen = 0;
+	}
+	if (icv_inlen != 0 || ret == (size_t) -1) {
+#ifdef EILSEQ
+		if (errno == EILSEQ) {
+			return -2;
+		} else
+#endif
+#ifdef E2BIG
+		if (errno == E2BIG) {
+			return -1;
+		} else
+#endif
+#ifdef EINVAL
+		if (errno == EINVAL) {
+			return -3;
+		} else
+#endif
+		{
+			return -3;
+		}
+	}
+	return 0;
+}
+#endif /* LIBXML_ICONV_ENABLED */
+
+/**
+ * xmlCharEncFirstLine:
+ * @handler:	char enconding transformation data structure
+ * @out:  an xmlBuffer for the output.
+ * @in:  an xmlBuffer for the input
+ *     
+ * Front-end for the encoding handler input function, but handle only
+ * the very first line, i.e. limit itself to 45 chars.
+ *     
+ * Returns the number of byte written if success, or 
+ *     -1 general error
+ *     -2 if the transcoding fails (for *in is not valid utf8 string or
+ *        the result of transformation can't fit into the encoding we want), or
+ */
+int
+xmlCharEncFirstLine(xmlCharEncodingHandler *handler, xmlBufferPtr out,
+                 xmlBufferPtr in) {
+    int ret = -2;
+    int written;
+    int toconv;
+
+    if (handler == NULL) return(-1);
+    if (out == NULL) return(-1);
+    if (in == NULL) return(-1);
+
+    written = out->size - out->use;
+    toconv = in->use;
+    if (toconv * 2 >= written) {
+        xmlBufferGrow(out, toconv);
+	written = out->size - out->use - 1;
+    }
+
+    /*
+     * echo '<?xml version="1.0" encoding="UCS4"?>' | wc -c => 38
+     * 45 chars should be sufficient to reach the end of the encoding
+     * decalration without going too far inside the document content.
+     */
+    written = 45;
+
+    if (handler->input != NULL) {
+	ret = handler->input(&out->content[out->use], &written,
+	                     in->content, &toconv);
+	xmlBufferShrink(in, toconv);
+	out->use += written;
+	out->content[out->use] = 0;
+    }
+#ifdef LIBXML_ICONV_ENABLED
+    else if (handler->iconv_in != NULL) {
+	ret = xmlIconvWrapper(handler->iconv_in, &out->content[out->use],
+	                      &written, in->content, &toconv);
+	xmlBufferShrink(in, toconv);
+	out->use += written;
+	out->content[out->use] = 0;
+	if (ret == -1) ret = -3;
+    }
+#endif /* LIBXML_ICONV_ENABLED */
+#ifdef DEBUG_ENCODING
+    switch (ret) {
+        case 0:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "converted %d bytes to %d bytes of input\n",
+	            toconv, written);
+	    break;
+        case -1:
+	    xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of input, %d left\n",
+	            toconv, written, in->use);
+	    break;
+        case -2:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "input conversion failed due to input error\n");
+	    break;
+        case -3:
+	    xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of input, %d left\n",
+	            toconv, written, in->use);
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,"Unknown input conversion failed %d\n", ret);
+    }
+#endif
+    /*
+     * Ignore when input buffer is not on a boundary
+     */
+    if (ret == -3) ret = 0;
+    if (ret == -1) ret = 0;
+    return(ret);
+}
+
+/**
+ * xmlCharEncInFunc:
+ * @handler:	char enconding transformation data structure
+ * @out:  an xmlBuffer for the output.
+ * @in:  an xmlBuffer for the input
+ *     
+ * Generic front-end for the encoding handler input function
+ *     
+ * Returns the number of byte written if success, or 
+ *     -1 general error
+ *     -2 if the transcoding fails (for *in is not valid utf8 string or
+ *        the result of transformation can't fit into the encoding we want), or
+ */
+int
+xmlCharEncInFunc(xmlCharEncodingHandler *handler, xmlBufferPtr out,
+                 xmlBufferPtr in) {
+    int ret = -2;
+    int written;
+    int toconv;
+
+    if (handler == NULL) return(-1);
+    if (out == NULL) return(-1);
+    if (in == NULL) return(-1);
+
+    toconv = in->use;
+    if (toconv == 0)
+	return(0);
+    written = out->size - out->use;
+    if (toconv * 2 >= written) {
+        xmlBufferGrow(out, out->size + toconv * 2);
+	written = out->size - out->use - 1;
+    }
+    if (handler->input != NULL) {
+	ret = handler->input(&out->content[out->use], &written,
+	                     in->content, &toconv);
+	xmlBufferShrink(in, toconv);
+	out->use += written;
+	out->content[out->use] = 0;
+    }
+#ifdef LIBXML_ICONV_ENABLED
+    else if (handler->iconv_in != NULL) {
+	ret = xmlIconvWrapper(handler->iconv_in, &out->content[out->use],
+	                      &written, in->content, &toconv);
+	xmlBufferShrink(in, toconv);
+	out->use += written;
+	out->content[out->use] = 0;
+	if (ret == -1) ret = -3;
+    }
+#endif /* LIBXML_ICONV_ENABLED */
+    switch (ret) {
+#ifdef DEBUG_ENCODING
+        case 0:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "converted %d bytes to %d bytes of input\n",
+	            toconv, written);
+	    break;
+        case -1:
+	    xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of input, %d left\n",
+	            toconv, written, in->use);
+	    break;
+        case -3:
+	    xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of input, %d left\n",
+	            toconv, written, in->use);
+	    break;
+#endif
+        case -2:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "input conversion failed due to input error\n");
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+		    in->content[0], in->content[1],
+		    in->content[2], in->content[3]);
+    }
+    /*
+     * Ignore when input buffer is not on a boundary
+     */
+    if (ret == -3) ret = 0;
+    return(ret);
+}
+
+/**
+ * xmlCharEncOutFunc:
+ * @handler:	char enconding transformation data structure
+ * @out:  an xmlBuffer for the output.
+ * @in:  an xmlBuffer for the input
+ *     
+ * Generic front-end for the encoding handler output function
+ * a first call with @in == NULL has to be made firs to initiate the 
+ * output in case of non-stateless encoding needing to initiate their
+ * state or the output (like the BOM in UTF16).
+ * In case of UTF8 sequence conversion errors for the given encoder,
+ * the content will be automatically remapped to a CharRef sequence.
+ *     
+ * Returns the number of byte written if success, or 
+ *     -1 general error
+ *     -2 if the transcoding fails (for *in is not valid utf8 string or
+ *        the result of transformation can't fit into the encoding we want), or
+ */
+int
+xmlCharEncOutFunc(xmlCharEncodingHandler *handler, xmlBufferPtr out,
+                  xmlBufferPtr in) {
+    int ret = -2;
+    int written;
+    int writtentot = 0;
+    int toconv;
+    int output = 0;
+
+    if (handler == NULL) return(-1);
+    if (out == NULL) return(-1);
+
+retry:
+    
+    written = out->size - out->use;
+
+    /*
+     * First specific handling of in = NULL, i.e. the initialization call
+     */
+    if (in == NULL) {
+        toconv = 0;
+	if (handler->output != NULL) {
+	    ret = handler->output(&out->content[out->use], &written,
+				  NULL, &toconv);
+	    out->use += written;
+	    out->content[out->use] = 0;
+	}
+#ifdef LIBXML_ICONV_ENABLED
+	else if (handler->iconv_out != NULL) {
+	    ret = xmlIconvWrapper(handler->iconv_out, &out->content[out->use],
+				  &written, NULL, &toconv);
+	    out->use += written;
+	    out->content[out->use] = 0;
+	}
+#endif /* LIBXML_ICONV_ENABLED */
+#ifdef DEBUG_ENCODING
+	xmlGenericError(xmlGenericErrorContext,
+		"initialized encoder\n");
+#endif
+        return(0);
+    }
+
+    /*
+     * Convertion itself.
+     */
+    toconv = in->use;
+    if (toconv == 0)
+	return(0);
+    if (toconv * 2 >= written) {
+        xmlBufferGrow(out, toconv * 2);
+	written = out->size - out->use - 1;
+    }
+    if (handler->output != NULL) {
+	ret = handler->output(&out->content[out->use], &written,
+	                      in->content, &toconv);
+	xmlBufferShrink(in, toconv);
+	out->use += written;
+	writtentot += written;
+	out->content[out->use] = 0;
+    }
+#ifdef LIBXML_ICONV_ENABLED
+    else if (handler->iconv_out != NULL) {
+	ret = xmlIconvWrapper(handler->iconv_out, &out->content[out->use],
+	                      &written, in->content, &toconv);
+	xmlBufferShrink(in, toconv);
+	out->use += written;
+	writtentot += written;
+	out->content[out->use] = 0;
+	if (ret == -1) {
+	    if (written > 0) {
+		/*
+		 * Can be a limitation of iconv
+		 */
+		goto retry;
+	    }
+	    ret = -3;
+	}
+    }
+#endif /* LIBXML_ICONV_ENABLED */
+    else {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlCharEncOutFunc: no output function !\n");
+	return(-1);
+    }
+
+    if (ret >= 0) output += ret;
+
+    /*
+     * Attempt to handle error cases
+     */
+    switch (ret) {
+#ifdef DEBUG_ENCODING
+        case 0:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "converted %d bytes to %d bytes of output\n",
+	            toconv, written);
+	    break;
+        case -1:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "output conversion failed by lack of space\n");
+	    break;
+#endif
+        case -3:
+	    xmlGenericError(xmlGenericErrorContext,"converted %d bytes to %d bytes of output %d left\n",
+	            toconv, written, in->use);
+	    break;
+        case -2: {
+	    int len = in->use;
+	    const xmlChar *utf = (const xmlChar *) in->content;
+	    int cur;
+
+	    cur = xmlGetUTF8Char(utf, &len);
+	    if (cur > 0) {
+		xmlChar charref[20];
+
+#ifdef DEBUG_ENCODING
+		xmlGenericError(xmlGenericErrorContext,
+			"handling output conversion error\n");
+		xmlGenericError(xmlGenericErrorContext,
+			"Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+			in->content[0], in->content[1],
+			in->content[2], in->content[3]);
+#endif
+		/*
+		 * Removes the UTF8 sequence, and replace it by a charref
+		 * and continue the transcoding phase, hoping the error
+		 * did not mangle the encoder state.
+		 */
+		sprintf((char *) charref, "&#x%X;", cur);
+		xmlBufferShrink(in, len);
+		xmlBufferAddHead(in, charref, -1);
+
+		goto retry;
+	    } else {
+		xmlGenericError(xmlGenericErrorContext,
+			"output conversion failed due to conv error\n");
+		xmlGenericError(xmlGenericErrorContext,
+			"Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+			in->content[0], in->content[1],
+			in->content[2], in->content[3]);
+		in->content[0] = ' ';
+	    }
+	    break;
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlCharEncCloseFunc:
+ * @handler:	char enconding transformation data structure
+ *     
+ * Generic front-end for hencoding handler close function
+ *
+ * Returns 0 if success, or -1 in case of error
+ */
+int
+xmlCharEncCloseFunc(xmlCharEncodingHandler *handler) {
+    int ret = 0;
+    if (handler == NULL) return(-1);
+    if (handler->name == NULL) return(-1);
+#ifdef LIBXML_ICONV_ENABLED
+    /*
+     * Iconv handlers can be oused only once, free the whole block.
+     * and the associated icon resources.
+     */
+    if ((handler->iconv_out != NULL) || (handler->iconv_in != NULL)) {
+	if (handler->name != NULL)
+	    xmlFree(handler->name);
+	handler->name = NULL;
+	if (handler->iconv_out != NULL) {
+	    if (iconv_close(handler->iconv_out))
+		ret = -1;
+	    handler->iconv_out = NULL;
+	}
+	if (handler->iconv_in != NULL) {
+	    if (iconv_close(handler->iconv_in))
+		ret = -1;
+	    handler->iconv_in = NULL;
+	}
+	xmlFree(handler);
+    }
+#endif /* LIBXML_ICONV_ENABLED */
+#ifdef DEBUG_ENCODING
+    if (ret)
+        xmlGenericError(xmlGenericErrorContext,
+		"failed to close the encoding handler\n");
+    else
+        xmlGenericError(xmlGenericErrorContext,
+		"closed the encoding handler\n");
+
+#endif
+    return(ret);
+}
+
diff --git a/encoding.h b/encoding.h
new file mode 100644
index 0000000..62e81e3
--- /dev/null
+++ b/encoding.h
@@ -0,0 +1,187 @@
+/*
+ * encoding.h : interface for the encoding conversion functions needed for
+ *              XML
+ *
+ * Related specs: 
+ * rfc2044        (UTF-8 and UTF-16) F. Yergeau Alis Technologies
+ * [ISO-10646]    UTF-8 and UTF-16 in Annexes
+ * [ISO-8859-1]   ISO Latin-1 characters codes.
+ * [UNICODE]      The Unicode Consortium, "The Unicode Standard --
+ *                Worldwide Character Encoding -- Version 1.0", Addison-
+ *                Wesley, Volume 1, 1991, Volume 2, 1992.  UTF-8 is
+ *                described in Unicode Technical Report #4.
+ * [US-ASCII]     Coded Character Set--7-bit American Standard Code for
+ *                Information Interchange, ANSI X3.4-1986.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_CHAR_ENCODING_H__
+#define __XML_CHAR_ENCODING_H__
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_ICONV_ENABLED
+#include <iconv.h>
+#endif
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Predefined values for some standard encodings
+ * Libxml don't do beforehand translation on UTF8, ISOLatinX
+ * It also support UTF16 (LE and BE) by default.
+ *
+ * Anything else would have to be translated to UTF8 before being
+ * given to the parser itself. The BOM for UTF16 and the encoding
+ * declaration are looked at and a converter is looked for at that
+ * point. If not found the parser stops here as asked by the XML REC
+ * Converter can be registered by the user using xmlRegisterCharEncodingHandler
+ * but the currentl form doesn't allow stateful transcoding (a serious
+ * problem agreed !). If iconv has been found it will be used
+ * automatically and allow stateful transcoding, the simplest is then
+ * to be sure to enable icon and to provide iconv libs for the encoding
+ * support needed.
+ */
+typedef enum {
+    XML_CHAR_ENCODING_ERROR=   -1, /* No char encoding detected */
+    XML_CHAR_ENCODING_NONE=	0, /* No char encoding detected */
+    XML_CHAR_ENCODING_UTF8=	1, /* UTF-8 */
+    XML_CHAR_ENCODING_UTF16LE=	2, /* UTF-16 little endian */
+    XML_CHAR_ENCODING_UTF16BE=	3, /* UTF-16 big endian */
+    XML_CHAR_ENCODING_UCS4LE=	4, /* UCS-4 little endian */
+    XML_CHAR_ENCODING_UCS4BE=	5, /* UCS-4 big endian */
+    XML_CHAR_ENCODING_EBCDIC=	6, /* EBCDIC uh! */
+    XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */
+    XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */
+    XML_CHAR_ENCODING_UCS2=	9, /* UCS-2 */
+    XML_CHAR_ENCODING_8859_1=	10,/* ISO-8859-1 ISO Latin 1 */
+    XML_CHAR_ENCODING_8859_2=	11,/* ISO-8859-2 ISO Latin 2 */
+    XML_CHAR_ENCODING_8859_3=	12,/* ISO-8859-3 */
+    XML_CHAR_ENCODING_8859_4=	13,/* ISO-8859-4 */
+    XML_CHAR_ENCODING_8859_5=	14,/* ISO-8859-5 */
+    XML_CHAR_ENCODING_8859_6=	15,/* ISO-8859-6 */
+    XML_CHAR_ENCODING_8859_7=	16,/* ISO-8859-7 */
+    XML_CHAR_ENCODING_8859_8=	17,/* ISO-8859-8 */
+    XML_CHAR_ENCODING_8859_9=	18,/* ISO-8859-9 */
+    XML_CHAR_ENCODING_2022_JP=  19,/* ISO-2022-JP */
+    XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */
+    XML_CHAR_ENCODING_EUC_JP=   21,/* EUC-JP */
+    XML_CHAR_ENCODING_ASCII=    22 /* pure ASCII */
+} xmlCharEncoding;
+
+/**
+ * xmlCharEncodingInputFunc:
+ * @out:  a pointer ot an array of bytes to store the UTF-8 result
+ * @outlen:  the lenght of @out
+ * @in:  a pointer ot an array of chars in the original encoding
+ * @inlen:  the lenght of @in
+ *
+ * Take a block of chars in the original encoding and try to convert
+ * it to an UTF-8 block of chars out.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding failed.
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen,
+                                         const unsigned char* in, int *inlen);
+
+
+/**
+ * xmlCharEncodingOutputFunc:
+ * @out:  a pointer ot an array of bytes to store the result
+ * @outlen:  the lenght of @out
+ * @in:  a pointer ot an array of UTF-8 chars
+ * @inlen:  the lenght of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an other
+ * encoding.
+ * Note: a first call designed to produce heading info is called with
+ * in = NULL. If stateful this should also initialize the encoder state
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding failed.
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen,
+                                          const unsigned char* in, int *inlen);
+
+
+/*
+ * Block defining the handlers for non UTF-8 encodings.
+ * If iconv is supported, there is two extra fields 
+ */
+
+typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler;
+typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr;
+struct _xmlCharEncodingHandler {
+    char                       *name;
+    xmlCharEncodingInputFunc   input;
+    xmlCharEncodingOutputFunc  output;
+#ifdef LIBXML_ICONV_ENABLED
+    iconv_t                    iconv_in;
+    iconv_t                    iconv_out;
+#endif /* LIBXML_ICONV_ENABLED */
+};
+
+/*
+ * Interfaces for encoding handlers
+ */
+void	xmlInitCharEncodingHandlers	(void);
+void	xmlCleanupCharEncodingHandlers	(void);
+void	xmlRegisterCharEncodingHandler	(xmlCharEncodingHandlerPtr handler);
+xmlCharEncodingHandlerPtr
+	xmlGetCharEncodingHandler	(xmlCharEncoding enc);
+xmlCharEncodingHandlerPtr
+	xmlFindCharEncodingHandler	(const char *name);
+
+
+/*
+ * Interfaces for encoding names and aliases
+ */
+int	xmlAddEncodingAlias		(const char *name,
+					 const char *alias);
+int	xmlDelEncodingAlias		(const char *alias);
+const char *
+	xmlGetEncodingAlias		(const char *alias);
+void	xmlCleanupEncodingAliases	(void);
+xmlCharEncoding
+	xmlParseCharEncoding		(const char* name);
+const char*
+	xmlGetCharEncodingName		(xmlCharEncoding enc);
+
+/*
+ * Interfaces directly used by the parsers.
+ */
+xmlCharEncoding
+	xmlDetectCharEncoding		(const unsigned char* in,
+					 int len);
+
+int	xmlCheckUTF8			(const unsigned char *utf);
+
+int	xmlCharEncOutFunc		(xmlCharEncodingHandler *handler,
+					 xmlBufferPtr out,
+					 xmlBufferPtr in);
+
+int	xmlCharEncInFunc		(xmlCharEncodingHandler *handler,
+					 xmlBufferPtr out,
+					 xmlBufferPtr in);
+int	xmlCharEncFirstLine		(xmlCharEncodingHandler *handler,
+					 xmlBufferPtr out,
+					 xmlBufferPtr in);
+int	xmlCharEncCloseFunc		(xmlCharEncodingHandler *handler);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_CHAR_ENCODING_H__ */
diff --git a/entities.c b/entities.c
new file mode 100644
index 0000000..0fc4e8e
--- /dev/null
+++ b/entities.c
@@ -0,0 +1,1034 @@
+/*
+ * entities.c : implementation for the XML entities handking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#include <libxml/xmlmemory.h>
+#include <libxml/hash.h>
+#include <libxml/entities.h>
+#include <libxml/parser.h>
+#include <libxml/xmlerror.h>
+
+#define DEBUG_ENT_REF /* debugging of cross entities dependancies */
+#define ENTITY_HASH_SIZE 256 /* modify xmlEntityComputeHash accordingly */
+
+/*
+ * xmlEntityComputeHash:
+ *
+ * Computes the hash value for this given entity
+ */
+int
+xmlEntityComputeHash(const xmlChar *name) {
+    register const unsigned char *cur = (const unsigned char *) name;
+    register unsigned char val = 0;
+
+    if (name == NULL)
+	return(val);
+    while (*cur) val += *cur++;
+    return(val);
+}
+
+/*
+ * The XML predefined entities.
+ */
+
+struct xmlPredefinedEntityValue {
+    const char *name;
+    const char *value;
+};
+struct xmlPredefinedEntityValue xmlPredefinedEntityValues[] = {
+    { "lt", "<" },
+    { "gt", ">" },
+    { "apos", "'" },
+    { "quot", "\"" },
+    { "amp", "&" }
+};
+
+/*
+ * TODO: !!!!!!! This is GROSS, allocation of a 256 entry hash for
+ *               a fixed number of 4 elements !
+ */
+xmlHashTablePtr xmlPredefinedEntities = NULL;
+
+/*
+ * xmlFreeEntity : clean-up an entity record.
+ */
+void xmlFreeEntity(xmlEntityPtr entity) {
+    if (entity == NULL) return;
+
+    if (entity->children)
+	xmlFreeNodeList(entity->children);
+    if (entity->name != NULL)
+	xmlFree((char *) entity->name);
+    if (entity->ExternalID != NULL)
+        xmlFree((char *) entity->ExternalID);
+    if (entity->SystemID != NULL)
+        xmlFree((char *) entity->SystemID);
+    if (entity->URI != NULL)
+        xmlFree((char *) entity->URI);
+    if (entity->content != NULL)
+        xmlFree((char *) entity->content);
+    if (entity->orig != NULL)
+        xmlFree((char *) entity->orig);
+    memset(entity, -1, sizeof(xmlEntity));
+    xmlFree(entity);
+}
+
+/*
+ * xmlAddEntity : register a new entity for an entities table.
+ */
+static xmlEntityPtr
+xmlAddEntity(xmlDtdPtr dtd, const xmlChar *name, int type,
+	  const xmlChar *ExternalID, const xmlChar *SystemID,
+	  const xmlChar *content) {
+    xmlEntitiesTablePtr table = NULL;
+    xmlEntityPtr ret;
+
+    if (name == NULL)
+	return(NULL);
+    switch (type) {
+        case XML_INTERNAL_GENERAL_ENTITY:
+        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+	    if (dtd->entities == NULL)
+		dtd->entities = xmlHashCreate(0);
+	    table = dtd->entities;
+	    break;
+        case XML_INTERNAL_PARAMETER_ENTITY:
+        case XML_EXTERNAL_PARAMETER_ENTITY:
+	    if (dtd->pentities == NULL)
+		dtd->pentities = xmlHashCreate(0);
+	    table = dtd->pentities;
+	    break;
+        case XML_INTERNAL_PREDEFINED_ENTITY:
+	    if (xmlPredefinedEntities == NULL)
+		xmlPredefinedEntities = xmlHashCreate(8);
+	    table = xmlPredefinedEntities;
+    }
+    if (table == NULL)
+	return(NULL);
+    ret = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddEntity: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlEntity));
+    ret->type = XML_ENTITY_DECL;
+
+    /*
+     * fill the structure.
+     */
+    ret->name = xmlStrdup(name);
+    ret->etype = (xmlEntityType) type;
+    if (ExternalID != NULL)
+	ret->ExternalID = xmlStrdup(ExternalID);
+    if (SystemID != NULL)
+	ret->SystemID = xmlStrdup(SystemID);
+    if (content != NULL) {
+        ret->length = xmlStrlen(content);
+	ret->content = xmlStrndup(content, ret->length);
+     } else {
+        ret->length = 0;
+        ret->content = NULL;
+    }
+    ret->URI = NULL; /* to be computed by the layer knowing
+			the defining entity */
+    ret->orig = NULL;
+
+    if (xmlHashAddEntry(table, name, ret)) {
+	/*
+	 * entity was already defined at another level.
+	 */
+        xmlFreeEntity(ret);
+	return(NULL);
+    }
+    return(ret);
+}
+
+/**
+ * xmlInitializePredefinedEntities:
+ *
+ * Set up the predefined entities.
+ */
+void xmlInitializePredefinedEntities(void) {
+    int i;
+    xmlChar name[50];
+    xmlChar value[50];
+    const char *in;
+    xmlChar *out;
+
+    if (xmlPredefinedEntities != NULL) return;
+
+    xmlPredefinedEntities = xmlCreateEntitiesTable();
+    for (i = 0;i < sizeof(xmlPredefinedEntityValues) / 
+                   sizeof(xmlPredefinedEntityValues[0]);i++) {
+        in = xmlPredefinedEntityValues[i].name;
+	out = &name[0];
+	for (;(*out++ = (xmlChar) *in);)in++;
+        in = xmlPredefinedEntityValues[i].value;
+	out = &value[0];
+	for (;(*out++ = (xmlChar) *in);)in++;
+
+        xmlAddEntity(NULL, (const xmlChar *) &name[0],
+	             XML_INTERNAL_PREDEFINED_ENTITY, NULL, NULL,
+		     &value[0]);
+    }
+}
+
+/**
+ * xmlCleanupPredefinedEntities:
+ *
+ * Cleanup up the predefined entities table.
+ */
+void xmlCleanupPredefinedEntities(void) {
+    if (xmlPredefinedEntities == NULL) return;
+
+    xmlFreeEntitiesTable(xmlPredefinedEntities);
+    xmlPredefinedEntities = NULL;
+}
+
+/**
+ * xmlGetPredefinedEntity:
+ * @name:  the entity name
+ *
+ * Check whether this name is an predefined entity.
+ *
+ * Returns NULL if not, othervise the entity
+ */
+xmlEntityPtr
+xmlGetPredefinedEntity(const xmlChar *name) {
+    if (xmlPredefinedEntities == NULL)
+        xmlInitializePredefinedEntities();
+    return((xmlEntityPtr) xmlHashLookup(xmlPredefinedEntities, name));
+}
+
+/**
+ * xmlAddDtdEntity:
+ * @doc:  the document
+ * @name:  the entity name
+ * @type:  the entity type XML_xxx_yyy_ENTITY
+ * @ExternalID:  the entity external ID if available
+ * @SystemID:  the entity system ID if available
+ * @content:  the entity content
+ *
+ * Register a new entity for this document DTD external subset.
+ *
+ * Returns a pointer to the entity or NULL in case of error
+ */
+xmlEntityPtr
+xmlAddDtdEntity(xmlDocPtr doc, const xmlChar *name, int type,
+	        const xmlChar *ExternalID, const xmlChar *SystemID,
+		const xmlChar *content) {
+    xmlEntityPtr ret;
+    xmlDtdPtr dtd;
+
+    if (doc == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+	        "xmlAddDtdEntity: doc == NULL !\n");
+	return(NULL);
+    }
+    if (doc->extSubset == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+	        "xmlAddDtdEntity: document without external subset !\n");
+	return(NULL);
+    }
+    dtd = doc->extSubset;
+    ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
+    if (ret == NULL) return(NULL);
+
+    /*
+     * Link it to the Dtd
+     */
+    ret->parent = dtd;
+    ret->doc = dtd->doc;
+    if (dtd->last == NULL) {
+	dtd->children = dtd->last = (xmlNodePtr) ret;
+    } else {
+        dtd->last->next = (xmlNodePtr) ret;
+	ret->prev = dtd->last;
+	dtd->last = (xmlNodePtr) ret;
+    }
+    return(ret);
+}
+
+/**
+ * xmlAddDocEntity:
+ * @doc:  the document
+ * @name:  the entity name
+ * @type:  the entity type XML_xxx_yyy_ENTITY
+ * @ExternalID:  the entity external ID if available
+ * @SystemID:  the entity system ID if available
+ * @content:  the entity content
+ *
+ * Register a new entity for this document.
+ *
+ * Returns a pointer to the entity or NULL in case of error
+ */
+xmlEntityPtr
+xmlAddDocEntity(xmlDocPtr doc, const xmlChar *name, int type,
+	        const xmlChar *ExternalID, const xmlChar *SystemID,
+	        const xmlChar *content) {
+    xmlEntityPtr ret;
+    xmlDtdPtr dtd;
+
+    if (doc == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+	        "xmlAddDocEntity: document is NULL !\n");
+	return(NULL);
+    }
+    if (doc->intSubset == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+	        "xmlAddDtdEntity: document without internal subset !\n");
+	return(NULL);
+    }
+    dtd = doc->intSubset;
+    ret = xmlAddEntity(dtd, name, type, ExternalID, SystemID, content);
+    if (ret == NULL) return(NULL);
+
+    /*
+     * Link it to the Dtd
+     */
+    ret->parent = dtd;
+    ret->doc = dtd->doc;
+    if (dtd->last == NULL) {
+	dtd->children = dtd->last = (xmlNodePtr) ret;
+    } else {
+	dtd->last->next = (xmlNodePtr) ret;
+	ret->prev = dtd->last;
+	dtd->last = (xmlNodePtr) ret;
+    }
+    return(ret);
+}
+
+/**
+ * xmlGetEntityFromTable:
+ * @table:  an entity table
+ * @name:  the entity name
+ * @parameter:  look for parameter entities
+ *
+ * Do an entity lookup in the table.
+ * returns the corresponding parameter entity, if found.
+ * 
+ * Returns A pointer to the entity structure or NULL if not found.
+ */
+xmlEntityPtr
+xmlGetEntityFromTable(xmlEntitiesTablePtr table, const xmlChar *name) {
+    return((xmlEntityPtr) xmlHashLookup(table, name));
+}
+
+/**
+ * xmlGetParameterEntity:
+ * @doc:  the document referencing the entity
+ * @name:  the entity name
+ *
+ * Do an entity lookup in the internal and external subsets and
+ * returns the corresponding parameter entity, if found.
+ * 
+ * Returns A pointer to the entity structure or NULL if not found.
+ */
+xmlEntityPtr
+xmlGetParameterEntity(xmlDocPtr doc, const xmlChar *name) {
+    xmlEntitiesTablePtr table;
+    xmlEntityPtr ret;
+
+    if ((doc->intSubset != NULL) && (doc->intSubset->pentities != NULL)) {
+	table = (xmlEntitiesTablePtr) doc->intSubset->pentities;
+	ret = xmlGetEntityFromTable(table, name);
+	if (ret != NULL)
+	    return(ret);
+    }
+    if ((doc->extSubset != NULL) && (doc->extSubset->pentities != NULL)) {
+	table = (xmlEntitiesTablePtr) doc->extSubset->pentities;
+	return(xmlGetEntityFromTable(table, name));
+    }
+    return(NULL);
+}
+
+/**
+ * xmlGetDtdEntity:
+ * @doc:  the document referencing the entity
+ * @name:  the entity name
+ *
+ * Do an entity lookup in the Dtd entity hash table and
+ * returns the corresponding entity, if found.
+ * 
+ * Returns A pointer to the entity structure or NULL if not found.
+ */
+xmlEntityPtr
+xmlGetDtdEntity(xmlDocPtr doc, const xmlChar *name) {
+    xmlEntitiesTablePtr table;
+
+    if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
+	table = (xmlEntitiesTablePtr) doc->extSubset->entities;
+	return(xmlGetEntityFromTable(table, name));
+    }
+    return(NULL);
+}
+
+/**
+ * xmlGetDocEntity:
+ * @doc:  the document referencing the entity
+ * @name:  the entity name
+ *
+ * Do an entity lookup in the document entity hash table and
+ * returns the corrsponding entity, otherwise a lookup is done
+ * in the predefined entities too.
+ * 
+ * Returns A pointer to the entity structure or NULL if not found.
+ */
+xmlEntityPtr
+xmlGetDocEntity(xmlDocPtr doc, const xmlChar *name) {
+    xmlEntityPtr cur;
+    xmlEntitiesTablePtr table;
+
+    if (doc != NULL) {
+	if ((doc->intSubset != NULL) && (doc->intSubset->entities != NULL)) {
+	    table = (xmlEntitiesTablePtr) doc->intSubset->entities;
+	    cur = xmlGetEntityFromTable(table, name);
+	    if (cur != NULL)
+		return(cur);
+	}
+	if ((doc->extSubset != NULL) && (doc->extSubset->entities != NULL)) {
+	    table = (xmlEntitiesTablePtr) doc->extSubset->entities;
+	    cur = xmlGetEntityFromTable(table, name);
+	    if (cur != NULL)
+		return(cur);
+	}
+    }
+    if (xmlPredefinedEntities == NULL)
+        xmlInitializePredefinedEntities();
+    table = xmlPredefinedEntities;
+    return(xmlGetEntityFromTable(table, name));
+}
+
+/*
+ * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
+ *                  | [#x10000-#x10FFFF]
+ * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
+ */
+#define IS_CHAR(c)							\
+    (((c) == 0x09) || ((c) == 0x0a) || ((c) == 0x0d) ||			\
+     (((c) >= 0x20) && ((c) != 0xFFFE) && ((c) != 0xFFFF)))
+
+/*
+ * A buffer used for converting entities to their equivalent and back.
+ */
+static int buffer_size = 0;
+static xmlChar *buffer = NULL;
+
+int growBuffer(void) {
+    buffer_size *= 2;
+    buffer = (xmlChar *) xmlRealloc(buffer, buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+        perror("realloc failed");
+	return(-1);
+    }
+    return(0);
+}
+
+
+/**
+ * xmlEncodeEntities:
+ * @doc:  the document containing the string
+ * @input:  A string to convert to XML.
+ *
+ * Do a global encoding of a string, replacing the predefined entities
+ * and non ASCII values with their entities and CharRef counterparts.
+ *
+ * TODO: remove xmlEncodeEntities, once we are not afraid of breaking binary
+ *       compatibility
+ *
+ * People must migrate their code to xmlEncodeEntitiesReentrant !
+ * This routine will issue a warning when encountered.
+ * 
+ * Returns A newly allocated string with the substitution done.
+ */
+const xmlChar *
+xmlEncodeEntities(xmlDocPtr doc, const xmlChar *input) {
+    const xmlChar *cur = input;
+    xmlChar *out = buffer;
+    static int warning = 1;
+    int html = 0;
+
+
+    if (warning) {
+    xmlGenericError(xmlGenericErrorContext,
+	    "Deprecated API xmlEncodeEntities() used\n");
+    xmlGenericError(xmlGenericErrorContext,
+	    "   change code to use xmlEncodeEntitiesReentrant()\n");
+    warning = 0;
+    }
+
+    if (input == NULL) return(NULL);
+    if (doc != NULL)
+        html = (doc->type == XML_HTML_DOCUMENT_NODE);
+
+    if (buffer == NULL) {
+        buffer_size = 1000;
+        buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+	if (buffer == NULL) {
+	    perror("malloc failed");
+            return(NULL);
+	}
+	out = buffer;
+    }
+    while (*cur != '\0') {
+        if (out - buffer > buffer_size - 100) {
+	    int index = out - buffer;
+
+	    growBuffer();
+	    out = &buffer[index];
+	}
+
+	/*
+	 * By default one have to encode at least '<', '>', '"' and '&' !
+	 */
+	if (*cur == '<') {
+	    *out++ = '&';
+	    *out++ = 'l';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '>') {
+	    *out++ = '&';
+	    *out++ = 'g';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '&') {
+	    *out++ = '&';
+	    *out++ = 'a';
+	    *out++ = 'm';
+	    *out++ = 'p';
+	    *out++ = ';';
+	} else if (*cur == '"') {
+	    *out++ = '&';
+	    *out++ = 'q';
+	    *out++ = 'u';
+	    *out++ = 'o';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if ((*cur == '\'') && (!html)) {
+	    *out++ = '&';
+	    *out++ = 'a';
+	    *out++ = 'p';
+	    *out++ = 'o';
+	    *out++ = 's';
+	    *out++ = ';';
+	} else if (((*cur >= 0x20) && (*cur < 0x80)) ||
+	    (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
+	    /*
+	     * default case, just copy !
+	     */
+	    *out++ = *cur;
+#ifndef USE_UTF_8
+	} else if ((sizeof(xmlChar) == 1) && (*cur >= 0x80)) {
+	    char buf[10], *ptr;
+
+#ifdef HAVE_SNPRINTF
+	    snprintf(buf, sizeof(buf), "&#%d;", *cur);
+#else
+	    sprintf(buf, "&#%d;", *cur);
+#endif
+            buf[sizeof(buf) - 1] = 0;
+            ptr = buf;
+	    while (*ptr != 0) *out++ = *ptr++;
+#endif
+	} else if (IS_CHAR(*cur)) {
+	    char buf[10], *ptr;
+
+#ifdef HAVE_SNPRINTF
+	    snprintf(buf, sizeof(buf), "&#%d;", *cur);
+#else
+	    sprintf(buf, "&#%d;", *cur);
+#endif
+            buf[sizeof(buf) - 1] = 0;
+            ptr = buf;
+	    while (*ptr != 0) *out++ = *ptr++;
+	}
+#if 0
+	else {
+	    /*
+	     * default case, this is not a valid char !
+	     * Skip it...
+	     */
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlEncodeEntities: invalid char %d\n", (int) *cur);
+	}
+#endif
+	cur++;
+    }
+    *out++ = 0;
+    return(buffer);
+}
+
+/*
+ * Macro used to grow the current buffer.
+ */
+#define growBufferReentrant() {						\
+    buffer_size *= 2;							\
+    buffer = (xmlChar *)						\
+    		xmlRealloc(buffer, buffer_size * sizeof(xmlChar));	\
+    if (buffer == NULL) {						\
+	perror("realloc failed");					\
+	return(NULL);							\
+    }									\
+}
+
+
+/**
+ * xmlEncodeEntitiesReentrant:
+ * @doc:  the document containing the string
+ * @input:  A string to convert to XML.
+ *
+ * Do a global encoding of a string, replacing the predefined entities
+ * and non ASCII values with their entities and CharRef counterparts.
+ * Contrary to xmlEncodeEntities, this routine is reentrant, and result
+ * must be deallocated.
+ *
+ * Returns A newly allocated string with the substitution done.
+ */
+xmlChar *
+xmlEncodeEntitiesReentrant(xmlDocPtr doc, const xmlChar *input) {
+    const xmlChar *cur = input;
+    xmlChar *buffer = NULL;
+    xmlChar *out = NULL;
+    int buffer_size = 0;
+    int html = 0;
+
+    if (input == NULL) return(NULL);
+    if (doc != NULL)
+        html = (doc->type == XML_HTML_DOCUMENT_NODE);
+
+    /*
+     * allocate an translation buffer.
+     */
+    buffer_size = 1000;
+    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+	perror("malloc failed");
+	return(NULL);
+    }
+    out = buffer;
+
+    while (*cur != '\0') {
+        if (out - buffer > buffer_size - 100) {
+	    int index = out - buffer;
+
+	    growBufferReentrant();
+	    out = &buffer[index];
+	}
+
+	/*
+	 * By default one have to encode at least '<', '>', '"' and '&' !
+	 */
+	if (*cur == '<') {
+	    *out++ = '&';
+	    *out++ = 'l';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '>') {
+	    *out++ = '&';
+	    *out++ = 'g';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '&') {
+	    *out++ = '&';
+	    *out++ = 'a';
+	    *out++ = 'm';
+	    *out++ = 'p';
+	    *out++ = ';';
+	} else if (*cur == '"') {
+	    *out++ = '&';
+	    *out++ = 'q';
+	    *out++ = 'u';
+	    *out++ = 'o';
+	    *out++ = 't';
+	    *out++ = ';';
+#if 0
+	} else if ((*cur == '\'') && (!html)) {
+	    *out++ = '&';
+	    *out++ = 'a';
+	    *out++ = 'p';
+	    *out++ = 'o';
+	    *out++ = 's';
+	    *out++ = ';';
+#endif
+	} else if (((*cur >= 0x20) && (*cur < 0x80)) ||
+	    (*cur == '\n') || (*cur == '\r') || (*cur == '\t')) {
+	    /*
+	     * default case, just copy !
+	     */
+	    *out++ = *cur;
+	} else if (*cur >= 0x80) {
+	    if ((doc->encoding != NULL) || (html)) {
+		/*
+		 * Bjørn Reese <br@sseusa.com> provided the patch
+	        xmlChar xc;
+	        xc = (*cur & 0x3F) << 6;
+	        if (cur[1] != 0) {
+		    xc += *(++cur) & 0x3F;
+		    *out++ = xc;
+	        } else
+		 */
+		    *out++ = *cur;
+	    } else {
+		/*
+		 * We assume we have UTF-8 input.
+		 */
+		char buf[10], *ptr;
+		int val = 0, l = 1;
+
+		if (*cur < 0xC0) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlEncodeEntitiesReentrant : input not UTF-8\n");
+		    doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
+#ifdef HAVE_SNPRINTF
+		    snprintf(buf, sizeof(buf), "&#%d;", *cur);
+#else
+		    sprintf(buf, "&#%d;", *cur);
+#endif
+		    buf[sizeof(buf) - 1] = 0;
+		    ptr = buf;
+		    while (*ptr != 0) *out++ = *ptr++;
+		    continue;
+		} else if (*cur < 0xE0) {
+                    val = (cur[0]) & 0x1F;
+		    val <<= 6;
+		    val |= (cur[1]) & 0x3F;
+		    l = 2;
+		} else if (*cur < 0xF0) {
+                    val = (cur[0]) & 0x0F;
+		    val <<= 6;
+		    val |= (cur[1]) & 0x3F;
+		    val <<= 6;
+		    val |= (cur[2]) & 0x3F;
+		    l = 3;
+		} else if (*cur < 0xF8) {
+                    val = (cur[0]) & 0x07;
+		    val <<= 6;
+		    val |= (cur[1]) & 0x3F;
+		    val <<= 6;
+		    val |= (cur[2]) & 0x3F;
+		    val <<= 6;
+		    val |= (cur[3]) & 0x3F;
+		    l = 4;
+		}
+		if ((l == 1) || (!IS_CHAR(val))) {
+		    xmlGenericError(xmlGenericErrorContext,
+			"xmlEncodeEntitiesReentrant : char out of range\n");
+		    doc->encoding = xmlStrdup(BAD_CAST "ISO-8859-1");
+#ifdef HAVE_SNPRINTF
+		    snprintf(buf, sizeof(buf), "&#%d;", *cur);
+#else
+		    sprintf(buf, "&#%d;", *cur);
+#endif
+		    buf[sizeof(buf) - 1] = 0;
+		    ptr = buf;
+		    while (*ptr != 0) *out++ = *ptr++;
+		    cur++;
+		    continue;
+		}
+		/*
+		 * We could do multiple things here. Just save as a char ref
+		 */
+#ifdef HAVE_SNPRINTF
+		snprintf(buf, sizeof(buf), "&#x%X;", val);
+#else
+		sprintf(buf, "&#x%X;", val);
+#endif
+		buf[sizeof(buf) - 1] = 0;
+		ptr = buf;
+		while (*ptr != 0) *out++ = *ptr++;
+		cur += l;
+		continue;
+	    }
+	} else if (IS_CHAR(*cur)) {
+	    char buf[10], *ptr;
+
+#ifdef HAVE_SNPRINTF
+	    snprintf(buf, sizeof(buf), "&#%d;", *cur);
+#else
+	    sprintf(buf, "&#%d;", *cur);
+#endif
+	    buf[sizeof(buf) - 1] = 0;
+            ptr = buf;
+	    while (*ptr != 0) *out++ = *ptr++;
+	}
+#if 0
+	else {
+	    /*
+	     * default case, this is not a valid char !
+	     * Skip it...
+	     */
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlEncodeEntities: invalid char %d\n", (int) *cur);
+	}
+#endif
+	cur++;
+    }
+    *out++ = 0;
+    return(buffer);
+}
+
+/**
+ * xmlEncodeSpecialChars:
+ * @doc:  the document containing the string
+ * @input:  A string to convert to XML.
+ *
+ * Do a global encoding of a string, replacing the predefined entities
+ * this routine is reentrant, and result must be deallocated.
+ *
+ * Returns A newly allocated string with the substitution done.
+ */
+xmlChar *
+xmlEncodeSpecialChars(xmlDocPtr doc, const xmlChar *input) {
+    const xmlChar *cur = input;
+    xmlChar *buffer = NULL;
+    xmlChar *out = NULL;
+    int buffer_size = 0;
+    int html = 0;
+
+    if (input == NULL) return(NULL);
+    if (doc != NULL)
+        html = (doc->type == XML_HTML_DOCUMENT_NODE);
+
+    /*
+     * allocate an translation buffer.
+     */
+    buffer_size = 1000;
+    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+	perror("malloc failed");
+	return(NULL);
+    }
+    out = buffer;
+
+    while (*cur != '\0') {
+        if (out - buffer > buffer_size - 10) {
+	    int index = out - buffer;
+
+	    growBufferReentrant();
+	    out = &buffer[index];
+	}
+
+	/*
+	 * By default one have to encode at least '<', '>', '"' and '&' !
+	 */
+	if (*cur == '<') {
+	    *out++ = '&';
+	    *out++ = 'l';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '>') {
+	    *out++ = '&';
+	    *out++ = 'g';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else if (*cur == '&') {
+	    *out++ = '&';
+	    *out++ = 'a';
+	    *out++ = 'm';
+	    *out++ = 'p';
+	    *out++ = ';';
+	} else if (*cur == '"') {
+	    *out++ = '&';
+	    *out++ = 'q';
+	    *out++ = 'u';
+	    *out++ = 'o';
+	    *out++ = 't';
+	    *out++ = ';';
+	} else {
+	    /*
+	     * Works because on UTF-8, all extended sequences cannot
+	     * result in bytes in the ASCII range.
+	     */
+	    *out++ = *cur;
+	}
+	cur++;
+    }
+    *out++ = 0;
+    return(buffer);
+}
+
+/**
+ * xmlCreateEntitiesTable:
+ *
+ * create and initialize an empty entities hash table.
+ *
+ * Returns the xmlEntitiesTablePtr just created or NULL in case of error.
+ */
+xmlEntitiesTablePtr
+xmlCreateEntitiesTable(void) {
+    return((xmlEntitiesTablePtr) xmlHashCreate(0));
+}
+
+/**
+ * xmlFreeEntitiesTable:
+ * @table:  An entity table
+ *
+ * Deallocate the memory used by an entities hash table.
+ */
+void
+xmlFreeEntitiesTable(xmlEntitiesTablePtr table) {
+    xmlHashFree(table, (xmlHashDeallocator) xmlFreeEntity);
+}
+
+/**
+ * xmlCopyEntity:
+ * @ent:  An entity
+ *
+ * Build a copy of an entity
+ * 
+ * Returns the new xmlEntitiesPtr or NULL in case of error.
+ */
+xmlEntityPtr
+xmlCopyEntity(xmlEntityPtr ent) {
+    xmlEntityPtr cur;
+
+    cur = (xmlEntityPtr) xmlMalloc(sizeof(xmlEntity));
+    if (cur == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlCopyEntity: out of memory !\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlEntity));
+    cur->type = XML_ELEMENT_DECL;
+
+    cur->etype = ent->etype;
+    if (ent->name != NULL)
+	cur->name = xmlStrdup(ent->name);
+    if (ent->ExternalID != NULL)
+	cur->ExternalID = xmlStrdup(ent->ExternalID);
+    if (ent->SystemID != NULL)
+	cur->SystemID = xmlStrdup(ent->SystemID);
+    if (ent->content != NULL)
+	cur->content = xmlStrdup(ent->content);
+    if (ent->orig != NULL)
+	cur->orig = xmlStrdup(ent->orig);
+    return(cur);
+}
+
+/**
+ * xmlCopyEntitiesTable:
+ * @table:  An entity table
+ *
+ * Build a copy of an entity table.
+ * 
+ * Returns the new xmlEntitiesTablePtr or NULL in case of error.
+ */
+xmlEntitiesTablePtr
+xmlCopyEntitiesTable(xmlEntitiesTablePtr table) {
+    return(xmlHashCopy(table, (xmlHashCopier) xmlCopyEntity));
+}
+
+/**
+ * xmlDumpEntityDecl:
+ * @buf:  An XML buffer.
+ * @ent:  An entity table
+ *
+ * This will dump the content of the entity table as an XML DTD definition
+ */
+void
+xmlDumpEntityDecl(xmlBufferPtr buf, xmlEntityPtr ent) {
+    switch (ent->etype) {
+	case XML_INTERNAL_GENERAL_ENTITY:
+	    xmlBufferWriteChar(buf, "<!ENTITY ");
+	    xmlBufferWriteCHAR(buf, ent->name);
+	    xmlBufferWriteChar(buf, " ");
+	    if (ent->orig != NULL)
+		xmlBufferWriteQuotedString(buf, ent->orig);
+	    else
+		xmlBufferWriteQuotedString(buf, ent->content);
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+	    xmlBufferWriteChar(buf, "<!ENTITY ");
+	    xmlBufferWriteCHAR(buf, ent->name);
+	    if (ent->ExternalID != NULL) {
+		 xmlBufferWriteChar(buf, " PUBLIC ");
+		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
+		 xmlBufferWriteChar(buf, " ");
+		 xmlBufferWriteQuotedString(buf, ent->SystemID);
+	    } else {
+		 xmlBufferWriteChar(buf, " SYSTEM ");
+		 xmlBufferWriteQuotedString(buf, ent->SystemID);
+	    }
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+	    xmlBufferWriteChar(buf, "<!ENTITY ");
+	    xmlBufferWriteCHAR(buf, ent->name);
+	    if (ent->ExternalID != NULL) {
+		 xmlBufferWriteChar(buf, " PUBLIC ");
+		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
+		 xmlBufferWriteChar(buf, " ");
+		 xmlBufferWriteQuotedString(buf, ent->SystemID);
+	    } else {
+		 xmlBufferWriteChar(buf, " SYSTEM ");
+		 xmlBufferWriteQuotedString(buf, ent->SystemID);
+	    }
+	    if (ent->content != NULL) { /* Should be true ! */
+		xmlBufferWriteChar(buf, " NDATA ");
+		if (ent->orig != NULL)
+		    xmlBufferWriteCHAR(buf, ent->orig);
+		else
+		    xmlBufferWriteCHAR(buf, ent->content);
+	    }
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	case XML_INTERNAL_PARAMETER_ENTITY:
+	    xmlBufferWriteChar(buf, "<!ENTITY % ");
+	    xmlBufferWriteCHAR(buf, ent->name);
+	    xmlBufferWriteChar(buf, " ");
+	    if (ent->orig == NULL)
+		xmlBufferWriteQuotedString(buf, ent->content);
+	    else
+		xmlBufferWriteQuotedString(buf, ent->orig);
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	case XML_EXTERNAL_PARAMETER_ENTITY:
+	    xmlBufferWriteChar(buf, "<!ENTITY % ");
+	    xmlBufferWriteCHAR(buf, ent->name);
+	    if (ent->ExternalID != NULL) {
+		 xmlBufferWriteChar(buf, " PUBLIC ");
+		 xmlBufferWriteQuotedString(buf, ent->ExternalID);
+		 xmlBufferWriteChar(buf, " ");
+		 xmlBufferWriteQuotedString(buf, ent->SystemID);
+	    } else {
+		 xmlBufferWriteChar(buf, " SYSTEM ");
+		 xmlBufferWriteQuotedString(buf, ent->SystemID);
+	    }
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		"xmlDumpEntitiesTable: internal: unknown type %d\n",
+		    ent->etype);
+    }
+}
+
+/**
+ * xmlDumpEntitiesTable:
+ * @buf:  An XML buffer.
+ * @table:  An entity table
+ *
+ * This will dump the content of the entity table as an XML DTD definition
+ */
+void
+xmlDumpEntitiesTable(xmlBufferPtr buf, xmlEntitiesTablePtr table) {
+    xmlHashScan(table, (xmlHashScanner)xmlDumpEntityDecl, buf);
+}
diff --git a/entities.h b/entities.h
new file mode 100644
index 0000000..305d043
--- /dev/null
+++ b/entities.h
@@ -0,0 +1,114 @@
+/*
+ * entities.h : interface for the XML entities handking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_ENTITIES_H__
+#define __XML_ENTITIES_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The different valid entity types
+ */
+typedef enum {
+    XML_INTERNAL_GENERAL_ENTITY = 1,
+    XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2,
+    XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3,
+    XML_INTERNAL_PARAMETER_ENTITY = 4,
+    XML_EXTERNAL_PARAMETER_ENTITY = 5,
+    XML_INTERNAL_PREDEFINED_ENTITY = 6
+} xmlEntityType;
+
+/*
+ * An unit of storage for an entity, contains the string, the value
+ * and the linkind data needed for the linking in the hash table.
+ */
+
+typedef struct _xmlEntity xmlEntity;
+typedef xmlEntity *xmlEntityPtr;
+struct _xmlEntity {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	        /* for Corba, must be first ! */
+#endif
+    xmlElementType          type;       /* XML_ENTITY_DECL, must be second ! */
+    const xmlChar          *name;	/* Attribute name */
+    struct _xmlNode    *children;	/* NULL */
+    struct _xmlNode        *last;	/* NULL */
+    struct _xmlDtd       *parent;	/* -> DTD */
+    struct _xmlNode        *next;	/* next sibling link  */
+    struct _xmlNode        *prev;	/* previous sibling link  */
+    struct _xmlDoc          *doc;       /* the containing document */
+
+    xmlChar                *orig;	/* content without ref substitution */
+    xmlChar             *content;	/* content or ndata if unparsed */
+    int                   length;	/* the content length */
+    xmlEntityType          etype;	/* The entity type */
+    const xmlChar    *ExternalID;	/* External identifier for PUBLIC */
+    const xmlChar      *SystemID;	/* URI for a SYSTEM or PUBLIC Entity */
+
+    struct _xmlEntity     *nexte;	/* unused */
+    const xmlChar           *URI;	/* the full URI as computed */
+};
+
+/*
+ * ALl entities are stored in an hash table
+ * there is 2 separate hash tables for global and parmeter entities
+ */
+
+typedef struct _xmlHashTable xmlEntitiesTable;
+typedef xmlEntitiesTable *xmlEntitiesTablePtr;
+
+/*
+ * External functions :
+ */
+
+void		xmlInitializePredefinedEntities	(void);
+xmlEntityPtr		xmlAddDocEntity		(xmlDocPtr doc,
+						 const xmlChar *name,
+						 int type,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID,
+						 const xmlChar *content);
+xmlEntityPtr		xmlAddDtdEntity		(xmlDocPtr doc,
+						 const xmlChar *name,
+						 int type,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID,
+						 const xmlChar *content);
+xmlEntityPtr		xmlGetPredefinedEntity	(const xmlChar *name);
+xmlEntityPtr		xmlGetDocEntity		(xmlDocPtr doc,
+						 const xmlChar *name);
+xmlEntityPtr		xmlGetDtdEntity		(xmlDocPtr doc,
+						 const xmlChar *name);
+xmlEntityPtr		xmlGetParameterEntity	(xmlDocPtr doc,
+						 const xmlChar *name);
+const xmlChar *		xmlEncodeEntities	(xmlDocPtr doc,
+						 const xmlChar *input);
+xmlChar *		xmlEncodeEntitiesReentrant(xmlDocPtr doc,
+						 const xmlChar *input);
+xmlChar *		xmlEncodeSpecialChars	(xmlDocPtr doc,
+						 const xmlChar *input);
+xmlEntitiesTablePtr	xmlCreateEntitiesTable	(void);
+xmlEntitiesTablePtr	xmlCopyEntitiesTable	(xmlEntitiesTablePtr table);
+void			xmlFreeEntitiesTable	(xmlEntitiesTablePtr table);
+void			xmlDumpEntitiesTable	(xmlBufferPtr buf,
+						 xmlEntitiesTablePtr table);
+void			xmlDumpEntityDecl	(xmlBufferPtr buf,
+						 xmlEntityPtr ent);
+xmlEntitiesTablePtr	xmlCopyEntitiesTable	(xmlEntitiesTablePtr table);
+void			xmlCleanupPredefinedEntities(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+# endif /* __XML_ENTITIES_H__ */
diff --git a/error.c b/error.c
new file mode 100644
index 0000000..cf76016
--- /dev/null
+++ b/error.c
@@ -0,0 +1,298 @@
+/*
+ * error.c: module displaying/handling XML parser errors
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <libxml/parser.h>
+#include <libxml/xmlerror.h>
+
+/************************************************************************
+ * 									*
+ * 			Handling of out of context errors		*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xmlGenericErrorDefaultFunc:
+ * @ctx:  an error context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Default handler for out of context error messages.
+ */
+void
+xmlGenericErrorDefaultFunc(void *ctx, const char *msg, ...) {
+    va_list args;
+
+    if (xmlGenericErrorContext == NULL)
+	xmlGenericErrorContext = (void *) stderr;
+
+    va_start(args, msg);
+    vfprintf((FILE *)xmlGenericErrorContext, msg, args);
+    va_end(args);
+}
+
+xmlGenericErrorFunc xmlGenericError = xmlGenericErrorDefaultFunc;
+void *xmlGenericErrorContext = NULL;
+
+
+/**
+ * xmlSetGenericErrorFunc:
+ * @ctx:  the new error handling context
+ * @handler:  the new handler function
+ *
+ * Function to reset the handler and the error context for out of
+ * context error messages.
+ * This simply means that @handler will be called for subsequent
+ * error messages while not parsing nor validating. And @ctx will
+ * be passed as first argument to @handler
+ * One can simply force messages to be emitted to another FILE * than
+ * stderr by setting @ctx to this file handle and @handler to NULL.
+ */
+void
+xmlSetGenericErrorFunc(void *ctx, xmlGenericErrorFunc handler) {
+    xmlGenericErrorContext = ctx;
+    if (handler != NULL)
+	xmlGenericError = handler;
+    else
+	xmlGenericError = xmlGenericErrorDefaultFunc;
+}
+
+/************************************************************************
+ * 									*
+ * 			Handling of parsing errors			*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xmlParserPrintFileInfo:
+ * @input:  an xmlParserInputPtr input
+ * 
+ * Displays the associated file and line informations for the current input
+ */
+
+void
+xmlParserPrintFileInfo(xmlParserInputPtr input) {
+    if (input != NULL) {
+	if (input->filename)
+	    xmlGenericError(xmlGenericErrorContext,
+		    "%s:%d: ", input->filename,
+		    input->line);
+	else
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Entity: line %d: ", input->line);
+    }
+}
+
+/**
+ * xmlParserPrintFileContext:
+ * @input:  an xmlParserInputPtr input
+ * 
+ * Displays current context within the input content for error tracking
+ */
+
+void
+xmlParserPrintFileContext(xmlParserInputPtr input) {
+    const xmlChar *cur, *base;
+    int n;
+
+    if (input == NULL) return;
+    cur = input->cur;
+    base = input->base;
+    while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
+	cur--;
+    }
+    n = 0;
+    while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
+        cur--;
+    if ((*cur == '\n') || (*cur == '\r')) cur++;
+    base = cur;
+    n = 0;
+    while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
+        xmlGenericError(xmlGenericErrorContext,
+		"%c", (unsigned char) *cur++);
+	n++;
+    }
+    xmlGenericError(xmlGenericErrorContext, "\n");
+    cur = input->cur;
+    while ((*cur == '\n') || (*cur == '\r'))
+	cur--;
+    n = 0;
+    while ((cur != base) && (n++ < 80)) {
+        xmlGenericError(xmlGenericErrorContext, " ");
+        base++;
+    }
+    xmlGenericError(xmlGenericErrorContext,"^\n");
+}
+
+/**
+ * xmlParserError:
+ * @ctx:  an XML parser context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Display and format an error messages, gives file, line, position and
+ * extra parameters.
+ */
+void
+xmlParserError(void *ctx, const char *msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlParserInputPtr input = NULL;
+    xmlParserInputPtr cur = NULL;
+    va_list args;
+
+    if (ctxt != NULL) {
+	input = ctxt->input;
+	if ((input != NULL) && (input->filename == NULL) &&
+	    (ctxt->inputNr > 1)) {
+	    cur = input;
+	    input = ctxt->inputTab[ctxt->inputNr - 2];
+	}
+	xmlParserPrintFileInfo(input);
+    }
+
+    xmlGenericError(xmlGenericErrorContext, "error: ");
+    va_start(args, msg);
+    vfprintf(xmlGenericErrorContext, msg, args);
+    va_end(args);
+
+    if (ctxt != NULL) {
+	xmlParserPrintFileContext(input);
+	if (cur != NULL) {
+	    xmlParserPrintFileInfo(cur);
+	    xmlGenericError(xmlGenericErrorContext, "\n");
+	    xmlParserPrintFileContext(cur);
+	}
+    }
+}
+
+/**
+ * xmlParserWarning:
+ * @ctx:  an XML parser context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Display and format a warning messages, gives file, line, position and
+ * extra parameters.
+ */
+void
+xmlParserWarning(void *ctx, const char *msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlParserInputPtr input = NULL;
+    xmlParserInputPtr cur = NULL;
+    va_list args;
+
+    if (ctxt != NULL) {
+	input = ctxt->input;
+	if ((input != NULL) && (input->filename == NULL) &&
+	    (ctxt->inputNr > 1)) {
+	    cur = input;
+	    input = ctxt->inputTab[ctxt->inputNr - 2];
+	}
+	xmlParserPrintFileInfo(input);
+    }
+        
+    xmlGenericError(xmlGenericErrorContext, "warning: ");
+    va_start(args, msg);
+    vfprintf(xmlGenericErrorContext, msg, args);
+    va_end(args);
+
+
+    if (ctxt != NULL) {
+	xmlParserPrintFileContext(input);
+	if (cur != NULL) {
+	    xmlParserPrintFileInfo(cur);
+	    xmlGenericError(xmlGenericErrorContext, "\n");
+	    xmlParserPrintFileContext(cur);
+	}
+    }
+}
+
+/************************************************************************
+ * 									*
+ * 			Handling of validation errors			*
+ * 									*
+ ************************************************************************/
+
+/**
+ * xmlParserValidityError:
+ * @ctx:  an XML parser context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Display and format an validity error messages, gives file,
+ * line, position and extra parameters.
+ */
+void
+xmlParserValidityError(void *ctx, const char *msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlParserInputPtr input = NULL;
+    va_list args;
+
+    if (ctxt != NULL) {
+	input = ctxt->input;
+	if ((input->filename == NULL) && (ctxt->inputNr > 1))
+	    input = ctxt->inputTab[ctxt->inputNr - 2];
+	    
+	xmlParserPrintFileInfo(input);
+    }
+
+    xmlGenericError(xmlGenericErrorContext, "validity error: ");
+    va_start(args, msg);
+    vfprintf(xmlGenericErrorContext, msg, args);
+    va_end(args);
+
+    if (ctxt != NULL) {
+	xmlParserPrintFileContext(input);
+    }
+}
+
+/**
+ * xmlParserValidityWarning:
+ * @ctx:  an XML parser context
+ * @msg:  the message to display/transmit
+ * @...:  extra parameters for the message display
+ * 
+ * Display and format a validity warning messages, gives file, line,
+ * position and extra parameters.
+ */
+void
+xmlParserValidityWarning(void *ctx, const char *msg, ...)
+{
+    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
+    xmlParserInputPtr input = NULL;
+    va_list args;
+
+    if (ctxt != NULL) {
+	input = ctxt->input;
+	if ((input->filename == NULL) && (ctxt->inputNr > 1))
+	    input = ctxt->inputTab[ctxt->inputNr - 2];
+
+	xmlParserPrintFileInfo(input);
+    }
+        
+    xmlGenericError(xmlGenericErrorContext, "validity warning: ");
+    va_start(args, msg);
+    vfprintf(xmlGenericErrorContext, msg, args);
+    va_end(args);
+
+    if (ctxt != NULL) {
+	xmlParserPrintFileContext(input);
+    }
+}
+
+
diff --git a/example/Makefile.am b/example/Makefile.am
index 00a53e9..67d2a28 100644
--- a/example/Makefile.am
+++ b/example/Makefile.am
@@ -1,8 +1,8 @@
 noinst_PROGRAMS	= gjobread
 
-DEFS =
-INCLUDES = -I$(top_builddir)
+INCLUDES =					\
+	-I$(top_builddir) -I$(top_srcdir)	\
+	-I@srcdir@
 
-DEPS = $(top_builddir)/libxml/libxml2.la
-LDADD = $(top_builddir)/libxml/libxml2.la
+LDADD = $(top_builddir)/libxml2.la @Z_LIBS@
 
diff --git a/hash.c b/hash.c
new file mode 100644
index 0000000..7881fc6
--- /dev/null
+++ b/hash.c
@@ -0,0 +1,620 @@
+/*
+ * hash.c: chained hash tables
+ *
+ * Reference: Your favorite introductory book on algorithms
+ *
+ * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: bjorn.reese@systematic.dk
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <string.h>
+#include <libxml/hash.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+
+/*
+ * A single entry in the hash table
+ */
+typedef struct _xmlHashEntry xmlHashEntry;
+typedef xmlHashEntry *xmlHashEntryPtr;
+struct _xmlHashEntry {
+    struct _xmlHashEntry *next;
+    xmlChar *name;
+    xmlChar *name2;
+    xmlChar *name3;
+    void *payload;
+};
+
+/*
+ * The entire hash table
+ */
+struct _xmlHashTable {
+    struct _xmlHashEntry **table;
+    int size;
+    int nbElems;
+};
+
+/*
+ * xmlHashComputeKey:
+ * Calculate the hash key
+ */
+static unsigned long
+xmlHashComputeKey(xmlHashTablePtr table, const xmlChar *string) {
+    unsigned long value = 0L;
+    char ch;
+    
+    while ((ch = *string++) != 0) {
+        /* value *= 31; */
+        value += (unsigned long)ch;
+    }
+    return (value % table->size);
+}
+
+/**
+ * xmlHashCreate:
+ * @size: the size of the hash table
+ *
+ * Create a new xmlHashTablePtr.
+ *
+ * Returns the newly created object, or NULL if an error occured.
+ */
+xmlHashTablePtr
+xmlHashCreate(int size) {
+    xmlHashTablePtr table;
+  
+    if (size <= 0)
+        size = 256;
+  
+    table = xmlMalloc(sizeof(xmlHashTable));
+    if (table) {
+        table->size = size;
+	table->nbElems = 0;
+        table->table = xmlMalloc(size * sizeof(xmlHashEntry));
+        if (table->table) {
+  	    memset(table->table, 0, size * sizeof(xmlHashEntry));
+  	    return(table);
+        }
+        xmlFree(table);
+    }
+    return(NULL);
+}
+
+/**
+ * xmlHashFree:
+ * @table: the hash table
+ * @f:  the deallocator function for items in the hash
+ *
+ * Free the hash table and its contents. The userdata is
+ * deallocated with f if provided.
+ */
+void
+xmlHashFree(xmlHashTablePtr table, xmlHashDeallocator f) {
+    int i;
+    xmlHashEntryPtr iter;
+    xmlHashEntryPtr next;
+
+    if (table == NULL)
+	return;
+    if (table->table) {
+	for(i = 0; i < table->size; i++) {
+	    iter = table->table[i];
+	    while (iter) {
+		next = iter->next;
+		if (iter->name)
+		    xmlFree(iter->name);
+		if (iter->name2)
+		    xmlFree(iter->name2);
+		if (iter->name3)
+		    xmlFree(iter->name3);
+		if (f)
+		    f(iter->payload, iter->name);
+		iter->payload = NULL;
+		xmlFree(iter);
+		iter = next;
+	    }
+	    table->table[i] = NULL;
+	}
+	xmlFree(table->table);
+    }
+    xmlFree(table);
+}
+
+/**
+ * xmlHashAddEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @userdata: a pointer to the userdata
+ *
+ * Add the userdata to the hash table. This can later be retrieved
+ * by using the name. Duplicate names generate errors.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+xmlHashAddEntry(xmlHashTablePtr table, const xmlChar *name, void *userdata) {
+    return(xmlHashAddEntry3(table, name, NULL, NULL, userdata));
+}
+
+/**
+ * xmlHashAddEntry2:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @userdata: a pointer to the userdata
+ *
+ * Add the userdata to the hash table. This can later be retrieved
+ * by using the (name, name2) tuple. Duplicate tuples generate errors.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+xmlHashAddEntry2(xmlHashTablePtr table, const xmlChar *name,
+	        const xmlChar *name2, void *userdata) {
+    return(xmlHashAddEntry3(table, name, name2, NULL, userdata));
+}
+
+/**
+ * xmlHashUpdateEntry:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @userdata: a pointer to the userdata
+ * @f: the deallocator function for replaced item (if any)
+ *
+ * Add the userdata to the hash table. This can later be retrieved
+ * by using the name. Existing entry for this name will be removed
+ * and freed with @f if found.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+xmlHashUpdateEntry(xmlHashTablePtr table, const xmlChar *name,
+	           void *userdata, xmlHashDeallocator f) {
+    return(xmlHashUpdateEntry3(table, name, NULL, NULL, userdata, f));
+}
+
+/**
+ * xmlHashUpdateEntry2:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @userdata: a pointer to the userdata
+ * @f: the deallocator function for replaced item (if any)
+ *
+ * Add the userdata to the hash table. This can later be retrieved
+ * by using the (name, name2) tuple. Existing entry for this tuple will
+ * be removed and freed with @f if found.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+xmlHashUpdateEntry2(xmlHashTablePtr table, const xmlChar *name,
+	           const xmlChar *name2, void *userdata,
+		   xmlHashDeallocator f) {
+    return(xmlHashUpdateEntry3(table, name, name2, NULL, userdata, f));
+}
+
+/**
+ * xmlHashLookup:
+ * @table: the hash table
+ * @name: the name of the userdata
+ *
+ * Find the userdata specified by the name.
+ *
+ * Returns the a pointer to the userdata
+ */
+void *
+xmlHashLookup(xmlHashTablePtr table, const xmlChar *name) {
+    return(xmlHashLookup3(table, name, NULL, NULL));
+}
+
+/**
+ * xmlHashLookup2:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ *
+ * Find the userdata specified by the (name, name2) tuple.
+ *
+ * Returns the a pointer to the userdata
+ */
+void *
+xmlHashLookup2(xmlHashTablePtr table, const xmlChar *name,
+	      const xmlChar *name2) {
+    return(xmlHashLookup3(table, name, name2, NULL));
+}
+
+/**
+ * xmlHashAddEntry3:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @name3: a third name of the userdata
+ * @userdata: a pointer to the userdata
+ *
+ * Add the userdata to the hash table. This can later be retrieved
+ * by using the tuple (name, name2, name3). Duplicate entries generate
+ * errors.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+xmlHashAddEntry3(xmlHashTablePtr table, const xmlChar *name,
+	         const xmlChar *name2, const xmlChar *name3,
+		 void *userdata) {
+    unsigned long key;
+    xmlHashEntryPtr entry;
+    xmlHashEntryPtr insert;
+
+    if ((table == NULL) || name == NULL)
+	return(-1);
+
+    /*
+     * Check for duplicate and insertion location.
+     */
+    key = xmlHashComputeKey(table, name);
+    if (table->table[key] == NULL) {
+	insert = NULL;
+    } else {
+	for (insert = table->table[key]; insert->next != NULL;
+	     insert = insert->next) {
+	    if ((xmlStrEqual(insert->name, name)) &&
+		(xmlStrEqual(insert->name2, name2)) &&
+		(xmlStrEqual(insert->name3, name3)))
+		return(-1);
+	}
+	if ((xmlStrEqual(insert->name, name)) &&
+	    (xmlStrEqual(insert->name2, name2)) &&
+	    (xmlStrEqual(insert->name3, name3)))
+	    return(-1);
+    }
+
+    entry = xmlMalloc(sizeof(xmlHashEntry));
+    if (entry == NULL)
+	return(-1);
+    entry->name = xmlStrdup(name);
+    entry->name2 = xmlStrdup(name2);
+    entry->name3 = xmlStrdup(name3);
+    entry->payload = userdata;
+    entry->next = NULL;
+
+
+    if (insert == NULL) {
+	table->table[key] = entry;
+    } else {
+	insert->next = entry;
+    }
+    table->nbElems++;
+    return(0);
+}
+
+/**
+ * xmlHashUpdateEntry3:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @name3: a third name of the userdata
+ * @userdata: a pointer to the userdata
+ * @f: the deallocator function for replaced item (if any)
+ *
+ * Add the userdata to the hash table. This can later be retrieved
+ * by using the tuple (name, name2, name3). Existing entry for this tuple
+ * will be removed and freed with @f if found.
+ *
+ * Returns 0 the addition succeeded and -1 in case of error.
+ */
+int
+xmlHashUpdateEntry3(xmlHashTablePtr table, const xmlChar *name,
+	           const xmlChar *name2, const xmlChar *name3,
+		   void *userdata, xmlHashDeallocator f) {
+    unsigned long key;
+    xmlHashEntryPtr entry;
+    xmlHashEntryPtr insert;
+
+    if ((table == NULL) || name == NULL)
+	return(-1);
+
+    /*
+     * Check for duplicate and insertion location.
+     */
+    key = xmlHashComputeKey(table, name);
+    if (table->table[key] == NULL) {
+	insert = NULL;
+    } else {
+	for (insert = table->table[key]; insert->next != NULL;
+	     insert = insert->next) {
+	    if ((xmlStrEqual(insert->name, name)) &&
+		(xmlStrEqual(insert->name2, name2)) &&
+		(xmlStrEqual(insert->name3, name3))) {
+		if (f)
+		    f(insert->payload, insert->name);
+		insert->payload = userdata;
+		return(0);
+	    }
+	}
+	if ((xmlStrEqual(insert->name, name)) &&
+	    (xmlStrEqual(insert->name2, name2)) &&
+	    (xmlStrEqual(insert->name3, name3))) {
+	    if (f)
+		f(insert->payload, insert->name);
+	    insert->payload = userdata;
+	    return(0);
+	}
+    }
+
+    entry = xmlMalloc(sizeof(xmlHashEntry));
+    if (entry == NULL)
+	return(-1);
+    entry->name = xmlStrdup(name);
+    entry->name2 = xmlStrdup(name2);
+    entry->name3 = xmlStrdup(name3);
+    entry->payload = userdata;
+    entry->next = NULL;
+    table->nbElems++;
+
+
+    if (insert == NULL) {
+	table->table[key] = entry;
+    } else {
+	insert->next = entry;
+    }
+    return(0);
+}
+
+/**
+ * xmlHashLookup:
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @name3: a third name of the userdata
+ *
+ * Find the userdata specified by the (name, name2, name3) tuple.
+ *
+ * Returns the a pointer to the userdata
+ */
+void *
+xmlHashLookup3(xmlHashTablePtr table, const xmlChar *name, 
+	       const xmlChar *name2, const xmlChar *name3) {
+    unsigned long key;
+    xmlHashEntryPtr entry;
+
+    if (table == NULL)
+	return(NULL);
+    if (name == NULL)
+	return(NULL);
+    key = xmlHashComputeKey(table, name);
+    for (entry = table->table[key]; entry != NULL; entry = entry->next) {
+	if ((xmlStrEqual(entry->name, name)) &&
+	    (xmlStrEqual(entry->name2, name2)) &&
+	    (xmlStrEqual(entry->name3, name3)))
+	    return(entry->payload);
+    }
+    return(NULL);
+}
+
+/**
+ * xmlHashScan:
+ * @table: the hash table
+ * @f:  the scanner function for items in the hash
+ * @data:  extra data passed to f
+ *
+ * Scan the hash table and applied f to each value.
+ */
+void
+xmlHashScan(xmlHashTablePtr table, xmlHashScanner f, void *data) {
+    int i;
+    xmlHashEntryPtr iter;
+    xmlHashEntryPtr next;
+
+    if (table == NULL)
+	return;
+    if (f == NULL)
+	return;
+
+    if (table->table) {
+	for(i = 0; i < table->size; i++) {
+	    iter = table->table[i];
+	    while (iter) {
+		next = iter->next;
+		if (f)
+		    f(iter->payload, data, iter->name);
+		iter = next;
+	    }
+	}
+    }
+}
+
+/**
+ * xmlHashScan3:
+ * @table: the hash table
+ * @name: the name of the userdata or NULL
+ * @name2: a second name of the userdata or NULL
+ * @name3: a third name of the userdata or NULL
+ * @f:  the scanner function for items in the hash
+ * @data:  extra data passed to f
+ *
+ * Scan the hash table and applied f to each value matching
+ * (name, name2, name3) tuple. If one of the names is null,
+ * the comparison is considered to match.
+ */
+void
+xmlHashScan3(xmlHashTablePtr table, const xmlChar *name, 
+	     const xmlChar *name2, const xmlChar *name3,
+	     xmlHashScanner f, void *data) {
+    int i;
+    xmlHashEntryPtr iter;
+    xmlHashEntryPtr next;
+
+    if (table == NULL)
+	return;
+    if (f == NULL)
+	return;
+
+    if (table->table) {
+	for(i = 0; i < table->size; i++) {
+	    iter = table->table[i];
+	    while (iter) {
+		next = iter->next;
+		if (((name == NULL) || (xmlStrEqual(name, iter->name))) &&
+		    ((name2 == NULL) || (xmlStrEqual(name2, iter->name2))) &&
+		    ((name3 == NULL) || (xmlStrEqual(name3, iter->name3)))) {
+		    f(iter->payload, data, iter->name);
+		}
+		iter = next;
+	    }
+	}
+    }
+}
+
+/**
+ * xmlHashCopy:
+ * @table: the hash table
+ * @f:  the copier function for items in the hash
+ *
+ * Scan the hash table and applied f to each value.
+ *
+ * Returns the new table or NULL in case of error.
+ */
+xmlHashTablePtr
+xmlHashCopy(xmlHashTablePtr table, xmlHashCopier f) {
+    int i;
+    xmlHashEntryPtr iter;
+    xmlHashEntryPtr next;
+    xmlHashTablePtr ret;
+
+    if (table == NULL)
+	return(NULL);
+    if (f == NULL)
+	return(NULL);
+
+    ret = xmlHashCreate(table->size);
+    if (table->table) {
+	for(i = 0; i < table->size; i++) {
+	    iter = table->table[i];
+	    while (iter) {
+		next = iter->next;
+		xmlHashAddEntry3(ret, iter->name, iter->name2,
+			         iter->name3, f(iter->payload, iter->name));
+		iter = next;
+	    }
+	}
+    }
+    ret->nbElems = table->nbElems;
+    return(ret);
+}
+
+/**
+ * xmlHashSize:
+ * @table: the hash table
+ *
+ * Returns the number of elements in the hash table or
+ * -1 in case of error
+ */
+int
+xmlHashSize(xmlHashTablePtr table) {
+    if (table == NULL)
+	return(-1);
+    return(table->nbElems);
+}
+
+/**
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @f: the deallocator function for removed item (if any)
+ *
+ * Find the userdata specified by the (name, name2, name3) tuple and remove
+ * it from the hash table. Existing userdata for this tuple will be removed
+ * and freed with @f.
+ *
+ * Returns 0 if the removal succeeded and -1 in case of error or not found.
+ */
+int xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
+											 xmlHashDeallocator f) {
+	return(xmlHashRemoveEntry3(table, name, NULL, NULL, f));
+}
+
+/**
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @f: the deallocator function for removed item (if any)
+ *
+ * Find the userdata specified by the (name, name2, name3) tuple and remove
+ * it from the hash table. Existing userdata for this tuple will be removed
+ * and freed with @f.
+ *
+ * Returns 0 if the removal succeeded and -1 in case of error or not found.
+ */
+int xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
+												const xmlChar *name2, xmlHashDeallocator f) {
+	return(xmlHashRemoveEntry3(table, name, name2, NULL, f));
+}
+
+/**
+ * @table: the hash table
+ * @name: the name of the userdata
+ * @name2: a second name of the userdata
+ * @name3: a third name of the userdata
+ * @f: the deallocator function for removed item (if any)
+ *
+ * Find the userdata specified by the (name, name2, name3) tuple and remove
+ * it from the hash table. Existing userdata for this tuple will be removed
+ * and freed with @f.
+ *
+ * Returns 0 if the removal succeeded and -1 in case of error or not found.
+ */
+int xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
+												const xmlChar *name2, const xmlChar *name3,
+												xmlHashDeallocator f) {
+	unsigned long key;
+	xmlHashEntryPtr entry;
+	xmlHashEntryPtr prev = NULL;
+
+	if (table == NULL || name == NULL)
+		return(-1);
+
+	key = xmlHashComputeKey(table, name);
+	if (table->table[key] == NULL) {
+		return(-1);
+	} else {
+		for (entry = table->table[key]; entry != NULL; entry = entry->next) {
+			if (xmlStrEqual(entry->name, name) &&
+					xmlStrEqual(entry->name2, name2) &&
+					xmlStrEqual(entry->name3, name3)) {
+				if(f)
+					f(entry->payload, entry->name);
+				entry->payload = NULL;
+				if(entry->name)
+					xmlFree(entry->name);
+				if(entry->name2)
+					xmlFree(entry->name2);
+				if(entry->name3)
+					xmlFree(entry->name3);
+				if(prev)
+					prev->next = entry->next;
+				else
+					table->table[key] = entry->next;
+				xmlFree(entry);
+				table->nbElems--;
+				return(0);
+			}
+			prev = entry;
+		}
+		return(-1);
+	}
+}
\ No newline at end of file
diff --git a/hash.h b/hash.h
new file mode 100644
index 0000000..c88fffd
--- /dev/null
+++ b/hash.h
@@ -0,0 +1,129 @@
+/*
+ * hash.c: chained hash tables
+ *
+ * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: bjorn.reese@systematic.dk
+ */
+
+#ifndef __XML_HASH_H__
+#define __XML_HASH_H__
+
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The hash table
+ */
+typedef struct _xmlHashTable xmlHashTable;
+typedef xmlHashTable *xmlHashTablePtr;
+
+/*
+ * function types:
+ */
+typedef void (*xmlHashDeallocator)(void *payload, xmlChar *name);
+typedef void *(*xmlHashCopier)(void *payload, xmlChar *name);
+typedef void *(*xmlHashScanner)(void *payload, void *data, xmlChar *name);
+
+/*
+ * Constructor and destructor
+ */
+xmlHashTablePtr		xmlHashCreate	(int size);
+void			xmlHashFree	(xmlHashTablePtr table,
+					 xmlHashDeallocator f);
+
+/*
+ * Add a new entry to the hash table
+ */
+int			xmlHashAddEntry	(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         void *userdata);
+int			xmlHashUpdateEntry(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         void *userdata,
+					 xmlHashDeallocator f);
+int			xmlHashAddEntry2(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         void *userdata);
+int			xmlHashUpdateEntry2(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         void *userdata,
+					 xmlHashDeallocator f);
+int			xmlHashAddEntry3(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         const xmlChar *name3,
+		                         void *userdata);
+int			xmlHashUpdateEntry3(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         const xmlChar *name3,
+		                         void *userdata,
+					 xmlHashDeallocator f);
+
+/*
+ * Remove an entry from the hash table
+ */
+int     xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
+                           xmlHashDeallocator f);
+int     xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
+                            const xmlChar *name2, xmlHashDeallocator f);
+int     xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
+                            const xmlChar *name2, const xmlChar *name3,
+                            xmlHashDeallocator f);
+
+/*
+ * Retrieve the userdata
+ */
+void *			xmlHashLookup	(xmlHashTablePtr table,
+					 const xmlChar *name);
+void *			xmlHashLookup2	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2);
+void *			xmlHashLookup3	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2,
+					 const xmlChar *name3);
+
+/*
+ * Helpers
+ */
+xmlHashTablePtr		xmlHashCopy	(xmlHashTablePtr table,
+					 xmlHashCopier f);
+int			xmlHashSize	(xmlHashTablePtr);
+void			xmlHashScan	(xmlHashTablePtr table,
+					 xmlHashScanner f,
+					 void *data);
+void			xmlHashScan1	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 xmlHashScanner f,
+					 void *data);
+void			xmlHashScan2	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2,
+					 xmlHashScanner f,
+					 void *data);
+void			xmlHashScan3	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2,
+					 const xmlChar *name3,
+					 xmlHashScanner f,
+					 void *data);
+#ifdef __cplusplus
+}
+#endif
+#endif /* ! __XML_HASH_H__ */
diff --git a/include/.cvsignore b/include/.cvsignore
new file mode 100644
index 0000000..70845e0
--- /dev/null
+++ b/include/.cvsignore
@@ -0,0 +1 @@
+Makefile.in
diff --git a/include/Makefile.am b/include/Makefile.am
new file mode 100644
index 0000000..f4878be
--- /dev/null
+++ b/include/Makefile.am
@@ -0,0 +1,33 @@
+## Process this file with automake to produce Makefile.in
+
+xmlincdir = $(includedir)
+
+xmlinc_HEADERS = \
+		libxml/SAX.h \
+		libxml/entities.h \
+		libxml/encoding.h \
+		libxml/parser.h \
+		libxml/parserInternals.h \
+		libxml/xmlerror.h \
+		libxml/HTMLparser.h \
+		libxml/HTMLtree.h \
+		libxml/debugXML.h \
+		libxml/tree.h \
+		libxml/hash.h \
+		libxml/xpath.h \
+		libxml/xpathInternals.h \
+		libxml/xpointer.h \
+		libxml/xinclude.h \
+		libxml/xmlIO.h \
+		libxml/xmlmemory.h \
+		libxml/nanohttp.h \
+		libxml/nanoftp.h \
+		libxml/uri.h \
+		libxml/valid.h \
+		libxml/xlink.h \
+		libxml/xmlversion.h
+
+install-exec-hook:
+	$(mkinstalldirs) $(DESTDIR)$(xmlincdir) $(DESTDIR)$(xmlincdir)/libxml
+
+EXTRA_DIST = win32config.h libxml/xmlversion.h.in
diff --git a/include/libxml/HTMLparser.h b/include/libxml/HTMLparser.h
new file mode 100644
index 0000000..c79ad09
--- /dev/null
+++ b/include/libxml/HTMLparser.h
@@ -0,0 +1,115 @@
+/*
+ * HTMLparser.h : inf=terface for an HTML 4.0 non-verifying parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __HTML_PARSER_H__
+#define __HTML_PARSER_H__
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Most of the back-end structures from XML and HTML are shared
+ */
+typedef xmlParserCtxt htmlParserCtxt;
+typedef xmlParserCtxtPtr htmlParserCtxtPtr;
+typedef xmlParserNodeInfo htmlParserNodeInfo;
+typedef xmlSAXHandler htmlSAXHandler;
+typedef xmlSAXHandlerPtr htmlSAXHandlerPtr;
+typedef xmlParserInput htmlParserInput;
+typedef xmlParserInputPtr htmlParserInputPtr;
+typedef xmlDocPtr htmlDocPtr;
+typedef xmlNodePtr htmlNodePtr;
+
+/*
+ * Internal description of an HTML element
+ */
+typedef struct _htmlElemDesc htmlElemDesc;
+typedef htmlElemDesc *htmlElemDescPtr;
+struct _htmlElemDesc {
+    const char *name;	/* The tag name */
+    char startTag;       /* Whether the start tag can be implied */
+    char endTag;         /* Whether the end tag can be implied */
+    char saveEndTag;     /* Whether the end tag should be saved */
+    char empty;          /* Is this an empty element ? */
+    char depr;           /* Is this a deprecated element ? */
+    char dtd;            /* 1: only in Loose DTD, 2: only Frameset one */
+    const char *desc;   /* the description */
+};
+
+/*
+ * Internal description of an HTML entity
+ */
+typedef struct _htmlEntityDesc htmlEntityDesc;
+typedef htmlEntityDesc *htmlEntityDescPtr;
+struct _htmlEntityDesc {
+    int value;		/* the UNICODE value for the character */
+    const char *name;	/* The entity name */
+    const char *desc;   /* the description */
+};
+
+/*
+ * There is only few public functions.
+ */
+htmlElemDescPtr		htmlTagLookup	(const xmlChar *tag);
+htmlEntityDescPtr	htmlEntityLookup(const xmlChar *name);
+htmlEntityDescPtr	htmlEntityValueLookup(int value);
+
+int			htmlIsAutoClosed(htmlDocPtr doc,
+					 htmlNodePtr elem);
+int			htmlAutoCloseTag(htmlDocPtr doc,
+					 const xmlChar *name,
+					 htmlNodePtr elem);
+htmlEntityDescPtr	htmlParseEntityRef(htmlParserCtxtPtr ctxt,
+					 xmlChar **str);
+int			htmlParseCharRef(htmlParserCtxtPtr ctxt);
+void			htmlParseElement(htmlParserCtxtPtr ctxt);
+
+htmlDocPtr		htmlSAXParseDoc	(xmlChar *cur,
+					 const char *encoding,
+					 htmlSAXHandlerPtr sax,
+					 void *userData);
+htmlDocPtr		htmlParseDoc	(xmlChar *cur,
+					 const char *encoding);
+htmlDocPtr		htmlSAXParseFile(const char *filename,
+					 const char *encoding,
+					 htmlSAXHandlerPtr sax,
+					 void *userData);
+htmlDocPtr		htmlParseFile	(const char *filename,
+					 const char *encoding);
+int			UTF8ToHtml	(unsigned char* out,
+					 int *outlen,
+					 const unsigned char* in,
+					 int *inlen);
+int			htmlEncodeEntities(unsigned char* out,
+					 int *outlen,
+					 const unsigned char* in,
+					 int *inlen, int quoteChar);
+int			htmlIsScriptAttribute(const xmlChar *name);
+int			htmlHandleOmittedElem(int val);
+
+/**
+ * Interfaces for the Push mode
+ */
+void			htmlFreeParserCtxt	(htmlParserCtxtPtr ctxt);
+htmlParserCtxtPtr	htmlCreatePushParserCtxt(htmlSAXHandlerPtr sax,
+						 void *user_data,
+						 const char *chunk,
+						 int size,
+						 const char *filename,
+						 xmlCharEncoding enc);
+int			htmlParseChunk		(htmlParserCtxtPtr ctxt,
+						 const char *chunk,
+						 int size,
+						 int terminate);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HTML_PARSER_H__ */
diff --git a/include/libxml/HTMLtree.h b/include/libxml/HTMLtree.h
new file mode 100644
index 0000000..543d693
--- /dev/null
+++ b/include/libxml/HTMLtree.h
@@ -0,0 +1,61 @@
+/*
+ * tree.h : describes the structures found in an tree resulting
+ *          from an XML parsing.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __HTML_TREE_H__
+#define __HTML_TREE_H__
+
+#include <stdio.h>
+#include <libxml/tree.h>
+#include <libxml/HTMLparser.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HTML_TEXT_NODE		XML_TEXT_NODE
+#define HTML_ENTITY_REF_NODE	XML_ENTITY_REF_NODE
+#define HTML_COMMENT_NODE	XML_COMMENT_NODE
+#define HTML_PRESERVE_NODE	XML_CDATA_SECTION_NODE
+
+htmlDocPtr	htmlNewDoc		(const xmlChar *URI,
+					 const xmlChar *ExternalID);
+htmlDocPtr	htmlNewDocNoDtD		(const xmlChar *URI,
+					 const xmlChar *ExternalID);
+const xmlChar *	htmlGetMetaEncoding	(htmlDocPtr doc);
+int		htmlSetMetaEncoding	(htmlDocPtr doc,
+					 const xmlChar *encoding);
+void		htmlDocDumpMemory	(xmlDocPtr cur,
+					 xmlChar**mem,
+					 int *size);
+int		htmlDocDump		(FILE *f,
+					 xmlDocPtr cur);
+int		htmlSaveFile		(const char *filename,
+					 xmlDocPtr cur);
+void		htmlNodeDump		(xmlBufferPtr buf,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur);
+void		htmlNodeDumpFile	(FILE *out,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur);
+int		htmlSaveFileEnc		(const char *filename,
+					 xmlDocPtr cur,
+					 const char *encoding);
+
+/* This one is imported from xmlIO.h
+void		htmlDocContentDumpOutput(xmlOutputBufferPtr buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+ */
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HTML_TREE_H__ */
+
diff --git a/include/libxml/SAX.h b/include/libxml/SAX.h
new file mode 100644
index 0000000..4fabbdf
--- /dev/null
+++ b/include/libxml/SAX.h
@@ -0,0 +1,120 @@
+/*
+ * SAX.h : Default SAX handler interfaces.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+
+#ifndef __XML_SAX_H__
+#define __XML_SAX_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libxml/parser.h>
+#include <libxml/xlink.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+const xmlChar *	getPublicId			(void *ctx);
+const xmlChar *	getSystemId			(void *ctx);
+void	setDocumentLocator			(void *ctx,
+						 xmlSAXLocatorPtr loc);
+    
+int		getLineNumber			(void *ctx);
+int		getColumnNumber			(void *ctx);
+
+int		isStandalone			(void *ctx);
+int		hasInternalSubset		(void *ctx);
+int		hasExternalSubset		(void *ctx);
+
+void		internalSubset			(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID);
+void		externalSubset			(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID);
+xmlEntityPtr	getEntity			(void *ctx,
+						 const xmlChar *name);
+xmlEntityPtr	getParameterEntity		(void *ctx,
+						 const xmlChar *name);
+xmlParserInputPtr resolveEntity			(void *ctx,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId);
+
+void		entityDecl			(void *ctx,
+						 const xmlChar *name,
+						 int type,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId,
+						 xmlChar *content);
+void		attributeDecl			(void *ctx,
+						 const xmlChar *elem,
+						 const xmlChar *name,
+						 int type,
+						 int def,
+						 const xmlChar *defaultValue,
+						 xmlEnumerationPtr tree);
+void		elementDecl			(void *ctx,
+						 const xmlChar *name,
+						 int type,
+						 xmlElementContentPtr content);
+void		notationDecl			(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId);
+void		unparsedEntityDecl		(void *ctx,
+						 const xmlChar *name,
+						 const xmlChar *publicId,
+						 const xmlChar *systemId,
+						 const xmlChar *notationName);
+
+void		startDocument			(void *ctx);
+void		endDocument			(void *ctx);
+void		attribute			(void *ctx,
+						 const xmlChar *fullname,
+						 const xmlChar *value);
+void		startElement			(void *ctx,
+						 const xmlChar *fullname,
+						 const xmlChar **atts);
+void		endElement			(void *ctx,
+						 const xmlChar *name);
+void		reference			(void *ctx,
+						 const xmlChar *name);
+void		characters			(void *ctx,
+						 const xmlChar *ch,
+						 int len);
+void		ignorableWhitespace		(void *ctx,
+						 const xmlChar *ch,
+						 int len);
+void		processingInstruction		(void *ctx,
+						 const xmlChar *target,
+						 const xmlChar *data);
+void		globalNamespace			(void *ctx,
+						 const xmlChar *href,
+						 const xmlChar *prefix);
+void		setNamespace			(void *ctx,
+						 const xmlChar *name);
+xmlNsPtr	getNamespace			(void *ctx);
+int		checkNamespace			(void *ctx,
+						 xmlChar *nameSpace);
+void		namespaceDecl			(void *ctx,
+						 const xmlChar *href,
+						 const xmlChar *prefix);
+void		comment				(void *ctx,
+						 const xmlChar *value);
+void		cdataBlock			(void *ctx,
+						 const xmlChar *value,
+						 int len);
+
+void		xmlDefaultSAXHandlerInit	(void);
+void		htmlDefaultSAXHandlerInit	(void);
+void		sgmlDefaultSAXHandlerInit	(void);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_SAX_H__ */
diff --git a/include/libxml/debugXML.h b/include/libxml/debugXML.h
new file mode 100644
index 0000000..4a55fa8
--- /dev/null
+++ b/include/libxml/debugXML.h
@@ -0,0 +1,113 @@
+/*
+ * debugXML.h : Interfaces to a set of routines used for debugging the tree
+ *              produced by the XML parser.
+ *
+ * Daniel Veillard <Daniel.Veillard@w3.org>
+ */
+
+#ifndef __DEBUG_XML__
+#define __DEBUG_XML__
+#include <stdio.h>
+#include <libxml/tree.h>
+
+#ifdef LIBXML_DEBUG_ENABLED
+
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The standard Dump routines
+ */
+void	xmlDebugDumpString	(FILE *output,
+				 const xmlChar *str);
+void	xmlDebugDumpAttr	(FILE *output,
+				 xmlAttrPtr attr,
+				 int depth);
+void	xmlDebugDumpAttrList	(FILE *output,
+				 xmlAttrPtr attr,
+				 int depth);
+void	xmlDebugDumpOneNode	(FILE *output,
+				 xmlNodePtr node,
+				 int depth);
+void	xmlDebugDumpNode	(FILE *output,
+				 xmlNodePtr node,
+				 int depth);
+void	xmlDebugDumpNodeList	(FILE *output,
+				 xmlNodePtr node,
+				 int depth);
+void	xmlDebugDumpDocumentHead(FILE *output,
+				 xmlDocPtr doc);
+void	xmlDebugDumpDocument	(FILE *output,
+				 xmlDocPtr doc);
+void	xmlDebugDumpDTD		(FILE *output,
+				 xmlDtdPtr doc);
+void	xmlDebugDumpEntities	(FILE *output,
+				 xmlDocPtr doc);
+void	xmlLsOneNode		(FILE *output,
+				 xmlNodePtr node);
+
+/****************************************************************
+ *								*
+ *	 The XML shell related structures and functions		*
+ *								*
+ ****************************************************************/
+
+/**
+ * xmlShellReadlineFunc:
+ * @prompt:  a string prompt
+ *
+ * This is a generic signature for the XML shell input function
+ *
+ * Returns a string which will be freed by the Shell
+ */
+typedef char * (* xmlShellReadlineFunc)(char *prompt);
+
+/*
+ * The shell context itself
+ * TODO: add the defined function tables.
+ */
+typedef struct _xmlShellCtxt xmlShellCtxt;
+typedef xmlShellCtxt *xmlShellCtxtPtr;
+struct _xmlShellCtxt {
+    char *filename;
+    xmlDocPtr doc;
+    xmlNodePtr node;
+    xmlXPathContextPtr pctxt;
+    int loaded;
+    FILE *output;
+    xmlShellReadlineFunc input;
+};
+
+/**
+ * xmlShellCmd:
+ * @ctxt:  a shell context
+ * @arg:  a string argument
+ * @node:  a first node
+ * @node2:  a second node
+ *
+ * This is a generic signature for the XML shell functions
+ *
+ * Returns an int, negative returns indicating errors
+ */
+typedef int (* xmlShellCmd) (xmlShellCtxtPtr ctxt,
+                             char *arg,
+			     xmlNodePtr node,
+			     xmlNodePtr node2);
+
+/*
+ * The Shell interface.
+ */
+void	xmlShell	(xmlDocPtr doc,
+			 char *filename,
+			 xmlShellReadlineFunc input,
+			 FILE *output);
+			 
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBXML_DEBUG_ENABLED */
+#endif /* __DEBUG_XML__ */
diff --git a/include/libxml/encoding.h b/include/libxml/encoding.h
new file mode 100644
index 0000000..62e81e3
--- /dev/null
+++ b/include/libxml/encoding.h
@@ -0,0 +1,187 @@
+/*
+ * encoding.h : interface for the encoding conversion functions needed for
+ *              XML
+ *
+ * Related specs: 
+ * rfc2044        (UTF-8 and UTF-16) F. Yergeau Alis Technologies
+ * [ISO-10646]    UTF-8 and UTF-16 in Annexes
+ * [ISO-8859-1]   ISO Latin-1 characters codes.
+ * [UNICODE]      The Unicode Consortium, "The Unicode Standard --
+ *                Worldwide Character Encoding -- Version 1.0", Addison-
+ *                Wesley, Volume 1, 1991, Volume 2, 1992.  UTF-8 is
+ *                described in Unicode Technical Report #4.
+ * [US-ASCII]     Coded Character Set--7-bit American Standard Code for
+ *                Information Interchange, ANSI X3.4-1986.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_CHAR_ENCODING_H__
+#define __XML_CHAR_ENCODING_H__
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_ICONV_ENABLED
+#include <iconv.h>
+#endif
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Predefined values for some standard encodings
+ * Libxml don't do beforehand translation on UTF8, ISOLatinX
+ * It also support UTF16 (LE and BE) by default.
+ *
+ * Anything else would have to be translated to UTF8 before being
+ * given to the parser itself. The BOM for UTF16 and the encoding
+ * declaration are looked at and a converter is looked for at that
+ * point. If not found the parser stops here as asked by the XML REC
+ * Converter can be registered by the user using xmlRegisterCharEncodingHandler
+ * but the currentl form doesn't allow stateful transcoding (a serious
+ * problem agreed !). If iconv has been found it will be used
+ * automatically and allow stateful transcoding, the simplest is then
+ * to be sure to enable icon and to provide iconv libs for the encoding
+ * support needed.
+ */
+typedef enum {
+    XML_CHAR_ENCODING_ERROR=   -1, /* No char encoding detected */
+    XML_CHAR_ENCODING_NONE=	0, /* No char encoding detected */
+    XML_CHAR_ENCODING_UTF8=	1, /* UTF-8 */
+    XML_CHAR_ENCODING_UTF16LE=	2, /* UTF-16 little endian */
+    XML_CHAR_ENCODING_UTF16BE=	3, /* UTF-16 big endian */
+    XML_CHAR_ENCODING_UCS4LE=	4, /* UCS-4 little endian */
+    XML_CHAR_ENCODING_UCS4BE=	5, /* UCS-4 big endian */
+    XML_CHAR_ENCODING_EBCDIC=	6, /* EBCDIC uh! */
+    XML_CHAR_ENCODING_UCS4_2143=7, /* UCS-4 unusual ordering */
+    XML_CHAR_ENCODING_UCS4_3412=8, /* UCS-4 unusual ordering */
+    XML_CHAR_ENCODING_UCS2=	9, /* UCS-2 */
+    XML_CHAR_ENCODING_8859_1=	10,/* ISO-8859-1 ISO Latin 1 */
+    XML_CHAR_ENCODING_8859_2=	11,/* ISO-8859-2 ISO Latin 2 */
+    XML_CHAR_ENCODING_8859_3=	12,/* ISO-8859-3 */
+    XML_CHAR_ENCODING_8859_4=	13,/* ISO-8859-4 */
+    XML_CHAR_ENCODING_8859_5=	14,/* ISO-8859-5 */
+    XML_CHAR_ENCODING_8859_6=	15,/* ISO-8859-6 */
+    XML_CHAR_ENCODING_8859_7=	16,/* ISO-8859-7 */
+    XML_CHAR_ENCODING_8859_8=	17,/* ISO-8859-8 */
+    XML_CHAR_ENCODING_8859_9=	18,/* ISO-8859-9 */
+    XML_CHAR_ENCODING_2022_JP=  19,/* ISO-2022-JP */
+    XML_CHAR_ENCODING_SHIFT_JIS=20,/* Shift_JIS */
+    XML_CHAR_ENCODING_EUC_JP=   21,/* EUC-JP */
+    XML_CHAR_ENCODING_ASCII=    22 /* pure ASCII */
+} xmlCharEncoding;
+
+/**
+ * xmlCharEncodingInputFunc:
+ * @out:  a pointer ot an array of bytes to store the UTF-8 result
+ * @outlen:  the lenght of @out
+ * @in:  a pointer ot an array of chars in the original encoding
+ * @inlen:  the lenght of @in
+ *
+ * Take a block of chars in the original encoding and try to convert
+ * it to an UTF-8 block of chars out.
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding failed.
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+typedef int (* xmlCharEncodingInputFunc)(unsigned char* out, int *outlen,
+                                         const unsigned char* in, int *inlen);
+
+
+/**
+ * xmlCharEncodingOutputFunc:
+ * @out:  a pointer ot an array of bytes to store the result
+ * @outlen:  the lenght of @out
+ * @in:  a pointer ot an array of UTF-8 chars
+ * @inlen:  the lenght of @in
+ *
+ * Take a block of UTF-8 chars in and try to convert it to an other
+ * encoding.
+ * Note: a first call designed to produce heading info is called with
+ * in = NULL. If stateful this should also initialize the encoder state
+ *
+ * Returns the number of byte written, or -1 by lack of space, or -2
+ *     if the transcoding failed.
+ * The value of @inlen after return is the number of octets consumed
+ *     as the return value is positive, else unpredictiable.
+ * The value of @outlen after return is the number of ocetes consumed.
+ */
+typedef int (* xmlCharEncodingOutputFunc)(unsigned char* out, int *outlen,
+                                          const unsigned char* in, int *inlen);
+
+
+/*
+ * Block defining the handlers for non UTF-8 encodings.
+ * If iconv is supported, there is two extra fields 
+ */
+
+typedef struct _xmlCharEncodingHandler xmlCharEncodingHandler;
+typedef xmlCharEncodingHandler *xmlCharEncodingHandlerPtr;
+struct _xmlCharEncodingHandler {
+    char                       *name;
+    xmlCharEncodingInputFunc   input;
+    xmlCharEncodingOutputFunc  output;
+#ifdef LIBXML_ICONV_ENABLED
+    iconv_t                    iconv_in;
+    iconv_t                    iconv_out;
+#endif /* LIBXML_ICONV_ENABLED */
+};
+
+/*
+ * Interfaces for encoding handlers
+ */
+void	xmlInitCharEncodingHandlers	(void);
+void	xmlCleanupCharEncodingHandlers	(void);
+void	xmlRegisterCharEncodingHandler	(xmlCharEncodingHandlerPtr handler);
+xmlCharEncodingHandlerPtr
+	xmlGetCharEncodingHandler	(xmlCharEncoding enc);
+xmlCharEncodingHandlerPtr
+	xmlFindCharEncodingHandler	(const char *name);
+
+
+/*
+ * Interfaces for encoding names and aliases
+ */
+int	xmlAddEncodingAlias		(const char *name,
+					 const char *alias);
+int	xmlDelEncodingAlias		(const char *alias);
+const char *
+	xmlGetEncodingAlias		(const char *alias);
+void	xmlCleanupEncodingAliases	(void);
+xmlCharEncoding
+	xmlParseCharEncoding		(const char* name);
+const char*
+	xmlGetCharEncodingName		(xmlCharEncoding enc);
+
+/*
+ * Interfaces directly used by the parsers.
+ */
+xmlCharEncoding
+	xmlDetectCharEncoding		(const unsigned char* in,
+					 int len);
+
+int	xmlCheckUTF8			(const unsigned char *utf);
+
+int	xmlCharEncOutFunc		(xmlCharEncodingHandler *handler,
+					 xmlBufferPtr out,
+					 xmlBufferPtr in);
+
+int	xmlCharEncInFunc		(xmlCharEncodingHandler *handler,
+					 xmlBufferPtr out,
+					 xmlBufferPtr in);
+int	xmlCharEncFirstLine		(xmlCharEncodingHandler *handler,
+					 xmlBufferPtr out,
+					 xmlBufferPtr in);
+int	xmlCharEncCloseFunc		(xmlCharEncodingHandler *handler);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_CHAR_ENCODING_H__ */
diff --git a/include/libxml/entities.h b/include/libxml/entities.h
new file mode 100644
index 0000000..305d043
--- /dev/null
+++ b/include/libxml/entities.h
@@ -0,0 +1,114 @@
+/*
+ * entities.h : interface for the XML entities handking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_ENTITIES_H__
+#define __XML_ENTITIES_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The different valid entity types
+ */
+typedef enum {
+    XML_INTERNAL_GENERAL_ENTITY = 1,
+    XML_EXTERNAL_GENERAL_PARSED_ENTITY = 2,
+    XML_EXTERNAL_GENERAL_UNPARSED_ENTITY = 3,
+    XML_INTERNAL_PARAMETER_ENTITY = 4,
+    XML_EXTERNAL_PARAMETER_ENTITY = 5,
+    XML_INTERNAL_PREDEFINED_ENTITY = 6
+} xmlEntityType;
+
+/*
+ * An unit of storage for an entity, contains the string, the value
+ * and the linkind data needed for the linking in the hash table.
+ */
+
+typedef struct _xmlEntity xmlEntity;
+typedef xmlEntity *xmlEntityPtr;
+struct _xmlEntity {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	        /* for Corba, must be first ! */
+#endif
+    xmlElementType          type;       /* XML_ENTITY_DECL, must be second ! */
+    const xmlChar          *name;	/* Attribute name */
+    struct _xmlNode    *children;	/* NULL */
+    struct _xmlNode        *last;	/* NULL */
+    struct _xmlDtd       *parent;	/* -> DTD */
+    struct _xmlNode        *next;	/* next sibling link  */
+    struct _xmlNode        *prev;	/* previous sibling link  */
+    struct _xmlDoc          *doc;       /* the containing document */
+
+    xmlChar                *orig;	/* content without ref substitution */
+    xmlChar             *content;	/* content or ndata if unparsed */
+    int                   length;	/* the content length */
+    xmlEntityType          etype;	/* The entity type */
+    const xmlChar    *ExternalID;	/* External identifier for PUBLIC */
+    const xmlChar      *SystemID;	/* URI for a SYSTEM or PUBLIC Entity */
+
+    struct _xmlEntity     *nexte;	/* unused */
+    const xmlChar           *URI;	/* the full URI as computed */
+};
+
+/*
+ * ALl entities are stored in an hash table
+ * there is 2 separate hash tables for global and parmeter entities
+ */
+
+typedef struct _xmlHashTable xmlEntitiesTable;
+typedef xmlEntitiesTable *xmlEntitiesTablePtr;
+
+/*
+ * External functions :
+ */
+
+void		xmlInitializePredefinedEntities	(void);
+xmlEntityPtr		xmlAddDocEntity		(xmlDocPtr doc,
+						 const xmlChar *name,
+						 int type,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID,
+						 const xmlChar *content);
+xmlEntityPtr		xmlAddDtdEntity		(xmlDocPtr doc,
+						 const xmlChar *name,
+						 int type,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID,
+						 const xmlChar *content);
+xmlEntityPtr		xmlGetPredefinedEntity	(const xmlChar *name);
+xmlEntityPtr		xmlGetDocEntity		(xmlDocPtr doc,
+						 const xmlChar *name);
+xmlEntityPtr		xmlGetDtdEntity		(xmlDocPtr doc,
+						 const xmlChar *name);
+xmlEntityPtr		xmlGetParameterEntity	(xmlDocPtr doc,
+						 const xmlChar *name);
+const xmlChar *		xmlEncodeEntities	(xmlDocPtr doc,
+						 const xmlChar *input);
+xmlChar *		xmlEncodeEntitiesReentrant(xmlDocPtr doc,
+						 const xmlChar *input);
+xmlChar *		xmlEncodeSpecialChars	(xmlDocPtr doc,
+						 const xmlChar *input);
+xmlEntitiesTablePtr	xmlCreateEntitiesTable	(void);
+xmlEntitiesTablePtr	xmlCopyEntitiesTable	(xmlEntitiesTablePtr table);
+void			xmlFreeEntitiesTable	(xmlEntitiesTablePtr table);
+void			xmlDumpEntitiesTable	(xmlBufferPtr buf,
+						 xmlEntitiesTablePtr table);
+void			xmlDumpEntityDecl	(xmlBufferPtr buf,
+						 xmlEntityPtr ent);
+xmlEntitiesTablePtr	xmlCopyEntitiesTable	(xmlEntitiesTablePtr table);
+void			xmlCleanupPredefinedEntities(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+# endif /* __XML_ENTITIES_H__ */
diff --git a/include/libxml/hash.h b/include/libxml/hash.h
new file mode 100644
index 0000000..c88fffd
--- /dev/null
+++ b/include/libxml/hash.h
@@ -0,0 +1,129 @@
+/*
+ * hash.c: chained hash tables
+ *
+ * Copyright (C) 2000 Bjorn Reese and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: bjorn.reese@systematic.dk
+ */
+
+#ifndef __XML_HASH_H__
+#define __XML_HASH_H__
+
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The hash table
+ */
+typedef struct _xmlHashTable xmlHashTable;
+typedef xmlHashTable *xmlHashTablePtr;
+
+/*
+ * function types:
+ */
+typedef void (*xmlHashDeallocator)(void *payload, xmlChar *name);
+typedef void *(*xmlHashCopier)(void *payload, xmlChar *name);
+typedef void *(*xmlHashScanner)(void *payload, void *data, xmlChar *name);
+
+/*
+ * Constructor and destructor
+ */
+xmlHashTablePtr		xmlHashCreate	(int size);
+void			xmlHashFree	(xmlHashTablePtr table,
+					 xmlHashDeallocator f);
+
+/*
+ * Add a new entry to the hash table
+ */
+int			xmlHashAddEntry	(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         void *userdata);
+int			xmlHashUpdateEntry(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         void *userdata,
+					 xmlHashDeallocator f);
+int			xmlHashAddEntry2(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         void *userdata);
+int			xmlHashUpdateEntry2(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         void *userdata,
+					 xmlHashDeallocator f);
+int			xmlHashAddEntry3(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         const xmlChar *name3,
+		                         void *userdata);
+int			xmlHashUpdateEntry3(xmlHashTablePtr table,
+		                         const xmlChar *name,
+		                         const xmlChar *name2,
+		                         const xmlChar *name3,
+		                         void *userdata,
+					 xmlHashDeallocator f);
+
+/*
+ * Remove an entry from the hash table
+ */
+int     xmlHashRemoveEntry(xmlHashTablePtr table, const xmlChar *name,
+                           xmlHashDeallocator f);
+int     xmlHashRemoveEntry2(xmlHashTablePtr table, const xmlChar *name,
+                            const xmlChar *name2, xmlHashDeallocator f);
+int     xmlHashRemoveEntry3(xmlHashTablePtr table, const xmlChar *name,
+                            const xmlChar *name2, const xmlChar *name3,
+                            xmlHashDeallocator f);
+
+/*
+ * Retrieve the userdata
+ */
+void *			xmlHashLookup	(xmlHashTablePtr table,
+					 const xmlChar *name);
+void *			xmlHashLookup2	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2);
+void *			xmlHashLookup3	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2,
+					 const xmlChar *name3);
+
+/*
+ * Helpers
+ */
+xmlHashTablePtr		xmlHashCopy	(xmlHashTablePtr table,
+					 xmlHashCopier f);
+int			xmlHashSize	(xmlHashTablePtr);
+void			xmlHashScan	(xmlHashTablePtr table,
+					 xmlHashScanner f,
+					 void *data);
+void			xmlHashScan1	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 xmlHashScanner f,
+					 void *data);
+void			xmlHashScan2	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2,
+					 xmlHashScanner f,
+					 void *data);
+void			xmlHashScan3	(xmlHashTablePtr table,
+					 const xmlChar *name,
+					 const xmlChar *name2,
+					 const xmlChar *name3,
+					 xmlHashScanner f,
+					 void *data);
+#ifdef __cplusplus
+}
+#endif
+#endif /* ! __XML_HASH_H__ */
diff --git a/include/libxml/list.h b/include/libxml/list.h
new file mode 100644
index 0000000..a708ef2
--- /dev/null
+++ b/include/libxml/list.h
@@ -0,0 +1,81 @@
+/*
+ * list.h: lists interfaces
+ *
+ * Copyright (C) 2000 Gary Pennington and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: Gary.Pennington@uk.sun.com
+ */
+
+typedef struct _xmlLink xmlLink;
+typedef xmlLink *xmlLinkPtr;
+
+typedef struct _xmlList xmlList;
+typedef xmlList *xmlListPtr;
+
+typedef void (*xmlListDeallocator) (xmlLinkPtr lk);
+typedef int  (*xmlListDataCompare) (const void *data0, const void *data1);
+typedef int (*xmlListWalker) (const void *data, const void *user);
+
+/* Creation/Deletion */
+xmlListPtr	xmlListCreate		(xmlListDeallocator deallocator,
+	                                 xmlListDataCompare compare);
+void		xmlListDelete		(xmlListPtr l);
+
+/* Basic Operators */
+void *		xmlListSearch		(xmlListPtr l,
+					 void *data);
+void *		xmlListReverseSearch	(xmlListPtr l,
+					 void *data);
+int		xmlListInsert		(xmlListPtr l,
+					 void *data) ;
+int		xmlListAppend		(xmlListPtr l,
+					 void *data) ;
+int		xmlListRemoveFirst	(xmlListPtr l,
+					 void *data);
+int		xmlListRemoveLast	(xmlListPtr l,
+					 void *data);
+int		xmlListRemoveAll	(xmlListPtr l,
+					 void *data);
+void		xmlListClear		(xmlListPtr l);
+int		xmlListEmpty		(xmlListPtr l);
+xmlLinkPtr	xmlListFront		(xmlListPtr l);
+xmlLinkPtr	xmlListEnd		(xmlListPtr l);
+int		xmlListSize		(xmlListPtr l);
+
+void		xmlListPopFront		(xmlListPtr l);
+void		xmlListPopBack		(xmlListPtr l);
+int		xmlListPushFront	(xmlListPtr l,
+					 void *data);
+int		xmlListPushBack		(xmlListPtr l,
+					 void *data);
+
+/* Advanced Operators */
+void		xmlListReverse		(xmlListPtr l);
+void		xmlListSort		(xmlListPtr l);
+void		xmlListWalk		(xmlListPtr l,
+					 xmlListWalker walker,
+					 const void *user);
+void		xmlListReverseWalk	(xmlListPtr l,
+					 xmlListWalker walker,
+					 const void *user);
+void		xmlListMerge		(xmlListPtr l1,
+					 xmlListPtr l2);
+xmlListPtr	xmlListDup		(const xmlListPtr old);
+int		xmlListCopy		(xmlListPtr cur,
+					 const xmlListPtr old);
+/* Link operators */
+void *          xmlLinkGetData          (xmlLinkPtr lk);
+
+/* xmlListUnique() */
+/* xmlListSwap */
+
+
diff --git a/include/libxml/nanoftp.h b/include/libxml/nanoftp.h
new file mode 100644
index 0000000..5346528
--- /dev/null
+++ b/include/libxml/nanoftp.h
@@ -0,0 +1,110 @@
+/*
+ * nanohttp.c: minimalist FTP implementation to fetch external subsets.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+ 
+#ifndef __NANO_FTP_H__
+#define __NANO_FTP_H__
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_FTP_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * ftpListCallback: 
+ * @userData:  user provided data for the callback
+ * @filename:  the file name (including "->" when links are shown)
+ * @attrib:  the attribute string
+ * @owner:  the owner string
+ * @group:  the group string
+ * @size:  the file size
+ * @links:  the link count
+ * @year:  the year
+ * @month:  the month
+ * @day:  the day
+ * @hour:  the hour
+ * @minute:  the minute
+ *
+ * A callback for the xmlNanoFTPList command
+ * Note that only one of year and day:minute are specified
+ */
+typedef void (*ftpListCallback) (void *userData,
+	                         const char *filename, const char* attrib,
+	                         const char *owner, const char *group,
+				 unsigned long size, int links, int year,
+				 const char *month, int day, int hour,
+				 int minute);
+/**
+ * ftpDataCallback: 
+ * A callback for the xmlNanoFTPGet command
+ */
+typedef void (*ftpDataCallback) (void *userData, const char *data, int len);
+
+/*
+ * Init
+ */
+void	xmlNanoFTPInit		(void);
+void	xmlNanoFTPCleanup	(void);
+
+/*
+ * Creating/freeing contexts
+ */
+void *	xmlNanoFTPNewCtxt	(const char *URL);
+void	xmlNanoFTPFreeCtxt	(void * ctx);
+void * 	xmlNanoFTPConnectTo	(const char *server,
+				 int port);
+/*
+ * Opening/closing session connections
+ */
+void * 	xmlNanoFTPOpen		(const char *URL);
+int	xmlNanoFTPConnect	(void *ctx);
+int	xmlNanoFTPClose		(void *ctx);
+int	xmlNanoFTPQuit		(void *ctx);
+void	xmlNanoFTPScanProxy	(const char *URL);
+void	xmlNanoFTPProxy		(const char *host,
+				 int port,
+				 const char *user,
+				 const char *passwd,
+				 int type);
+int	xmlNanoFTPUpdateURL	(void *ctx,
+				 const char *URL);
+
+/*
+ * Rathern internal commands
+ */
+int	xmlNanoFTPGetResponse	(void *ctx);
+int	xmlNanoFTPCheckResponse	(void *ctx);
+
+/*
+ * CD/DIR/GET handlers
+ */
+int	xmlNanoFTPCwd		(void *ctx,
+				 char *directory);
+
+int	xmlNanoFTPGetConnection	(void *ctx);
+int	xmlNanoFTPCloseConnection(void *ctx);
+int	xmlNanoFTPList		(void *ctx,
+				 ftpListCallback callback,
+				 void *userData,
+				 char *filename);
+int	xmlNanoFTPGetSocket	(void *ctx,
+				 const char *filename);
+int	xmlNanoFTPGet		(void *ctx,
+				 ftpDataCallback callback,
+				 void *userData,
+				 const char *filename);
+int	xmlNanoFTPRead		(void *ctx,
+				 void *dest,
+				 int len);
+
+#ifdef __cplusplus
+}
+#endif /* LIBXML_FTP_ENABLED */
+#endif
+#endif /* __NANO_FTP_H__ */
diff --git a/include/libxml/nanohttp.h b/include/libxml/nanohttp.h
new file mode 100644
index 0000000..78d1c44
--- /dev/null
+++ b/include/libxml/nanohttp.h
@@ -0,0 +1,44 @@
+/*
+ * nanohttp.c: minimalist HTTP implementation to fetch external subsets.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+ 
+#ifndef __NANO_HTTP_H__
+#define __NANO_HTTP_H__
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_HTTP_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void	xmlNanoHTTPInit		(void);
+void	xmlNanoHTTPCleanup	(void);
+void	xmlNanoHTTPScanProxy	(const char *URL);
+int	xmlNanoHTTPFetch	(const char *URL,
+				 const char *filename,
+				 char **contentType);
+void *	xmlNanoHTTPMethod	(const char *URL,
+				 const char *method,
+				 const char *input,
+				 char **contentType,
+				 const char *headers);
+void *	xmlNanoHTTPOpen		(const char *URL,
+				 char **contentType);
+int	xmlNanoHTTPReturnCode	(void *ctx);
+const char * xmlNanoHTTPAuthHeader(void *ctx);
+int	xmlNanoHTTPRead		(void *ctx,
+				 void *dest,
+				 int len);
+int	xmlNanoHTTPSave		(void *ctxt,
+				 const char *filename);
+void	xmlNanoHTTPClose	(void *ctx);
+#ifdef __cplusplus
+}
+
+#endif /* LIBXML_HTTP_ENABLED */
+#endif
+#endif /* __NANO_HTTP_H__ */
diff --git a/include/libxml/parser.h b/include/libxml/parser.h
new file mode 100644
index 0000000..b98f2a3
--- /dev/null
+++ b/include/libxml/parser.h
@@ -0,0 +1,527 @@
+/*
+ * parser.h : Interfaces, constants and types related to the XML parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_PARSER_H__
+#define __XML_PARSER_H__
+
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/xmlIO.h>
+#include <libxml/entities.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Constants.
+ */
+#define XML_DEFAULT_VERSION	"1.0"
+
+/**
+ * an xmlParserInput is an input flow for the XML processor.
+ * Each entity parsed is associated an xmlParserInput (except the
+ * few predefined ones). This is the case both for internal entities
+ * - in which case the flow is already completely in memory - or
+ * external entities - in which case we use the buf structure for
+ * progressive reading and I18N conversions to the internal UTF-8 format.
+ */
+
+typedef void (* xmlParserInputDeallocate)(xmlChar *);
+typedef struct _xmlParserInput xmlParserInput;
+typedef xmlParserInput *xmlParserInputPtr;
+struct _xmlParserInput {
+    /* Input buffer */
+    xmlParserInputBufferPtr buf;      /* UTF-8 encoded buffer */
+
+    const char *filename;             /* The file analyzed, if any */
+    const char *directory;            /* the directory/base of teh file */
+    const xmlChar *base;              /* Base of the array to parse */
+    const xmlChar *cur;               /* Current char being parsed */
+    int length;                       /* length if known */
+    int line;                         /* Current line */
+    int col;                          /* Current column */
+    int consumed;                     /* How many xmlChars already consumed */
+    xmlParserInputDeallocate free;    /* function to deallocate the base */
+    const xmlChar *encoding;          /* the encoding string for entity */
+    const xmlChar *version;           /* the version string for entity */
+    int standalone;                   /* Was that entity marked standalone */
+};
+
+/**
+ * the parser can be asked to collect Node informations, i.e. at what
+ * place in the file they were detected. 
+ * NOTE: This is off by default and not very well tested.
+ */
+typedef struct _xmlParserNodeInfo xmlParserNodeInfo;
+typedef xmlParserNodeInfo *xmlParserNodeInfoPtr;
+
+struct _xmlParserNodeInfo {
+  const struct _xmlNode* node;
+  /* Position & line # that text that created the node begins & ends on */
+  unsigned long begin_pos;
+  unsigned long begin_line;
+  unsigned long end_pos;
+  unsigned long end_line;
+};
+
+typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq;
+typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr;
+struct _xmlParserNodeInfoSeq {
+  unsigned long maximum;
+  unsigned long length;
+  xmlParserNodeInfo* buffer;
+};
+
+/**
+ * The parser is now working also as a state based parser
+ * The recursive one use the stagte info for entities processing
+ */
+typedef enum {
+    XML_PARSER_EOF = -1,	/* nothing is to be parsed */
+    XML_PARSER_START = 0,	/* nothing has been parsed */
+    XML_PARSER_MISC,		/* Misc* before int subset */
+    XML_PARSER_PI,		/* Whithin a processing instruction */
+    XML_PARSER_DTD,		/* within some DTD content */
+    XML_PARSER_PROLOG,		/* Misc* after internal subset */
+    XML_PARSER_COMMENT,		/* within a comment */
+    XML_PARSER_START_TAG,	/* within a start tag */
+    XML_PARSER_CONTENT,		/* within the content */
+    XML_PARSER_CDATA_SECTION,	/* within a CDATA section */
+    XML_PARSER_END_TAG,		/* within a closing tag */
+    XML_PARSER_ENTITY_DECL,	/* within an entity declaration */
+    XML_PARSER_ENTITY_VALUE,	/* within an entity value in a decl */
+    XML_PARSER_ATTRIBUTE_VALUE,	/* within an attribute value */
+    XML_PARSER_SYSTEM_LITERAL,	/* within a SYSTEM value */
+    XML_PARSER_EPILOG, 		/* the Misc* after the last end tag */
+    XML_PARSER_IGNORE		/* within an IGNORED section */
+} xmlParserInputState;
+
+/**
+ * The parser context.
+ * NOTE This doesn't completely defines the parser state, the (current ?)
+ *      design of the parser uses recursive function calls since this allow
+ *      and easy mapping from the production rules of the specification
+ *      to the actual code. The drawback is that the actual function call
+ *      also reflect the parser state. However most of the parsing routines
+ *      takes as the only argument the parser context pointer, so migrating
+ *      to a state based parser for progressive parsing shouldn't be too hard.
+ */
+typedef struct _xmlParserCtxt xmlParserCtxt;
+typedef xmlParserCtxt *xmlParserCtxtPtr;
+struct _xmlParserCtxt {
+    struct _xmlSAXHandler *sax;       /* The SAX handler */
+    void            *userData;        /* For SAX interface only, used by DOM build */
+    xmlDocPtr           myDoc;        /* the document being built */
+    int            wellFormed;        /* is the document well formed */
+    int       replaceEntities;        /* shall we replace entities ? */
+    const xmlChar    *version;        /* the XML version string */
+    const xmlChar   *encoding;        /* the declared encoding, if any */
+    int            standalone;        /* standalone document */
+    int                  html;        /* an HTML(1)/Docbook(2) document */
+
+    /* Input stream stack */
+    xmlParserInputPtr  input;         /* Current input stream */
+    int                inputNr;       /* Number of current input streams */
+    int                inputMax;      /* Max number of input streams */
+    xmlParserInputPtr *inputTab;      /* stack of inputs */
+
+    /* Node analysis stack only used for DOM building */
+    xmlNodePtr         node;          /* Current parsed Node */
+    int                nodeNr;        /* Depth of the parsing stack */
+    int                nodeMax;       /* Max depth of the parsing stack */
+    xmlNodePtr        *nodeTab;       /* array of nodes */
+
+    int record_info;                  /* Whether node info should be kept */
+    xmlParserNodeInfoSeq node_seq;    /* info about each node parsed */
+
+    int errNo;                        /* error code */
+
+    int     hasExternalSubset;        /* reference and external subset */
+    int             hasPErefs;        /* the internal subset has PE refs */
+    int              external;        /* are we parsing an external entity */
+
+    int                 valid;        /* is the document valid */
+    int              validate;        /* shall we try to validate ? */
+    xmlValidCtxt        vctxt;        /* The validity context */
+
+    xmlParserInputState instate;      /* current type of input */
+    int                 token;        /* next char look-ahead */    
+
+    char           *directory;        /* the data directory */
+
+    /* Node name stack */
+    xmlChar           *name;          /* Current parsed Node */
+    int                nameNr;        /* Depth of the parsing stack */
+    int                nameMax;       /* Max depth of the parsing stack */
+    xmlChar *         *nameTab;       /* array of nodes */
+
+    long               nbChars;       /* number of xmlChar processed */
+    long            checkIndex;       /* used by progressive parsing lookup */
+    int             keepBlanks;       /* ugly but ... */
+    int             disableSAX;       /* SAX callbacks are disabled */
+    int               inSubset;       /* Parsing is in int 1/ext 2 subset */
+    xmlChar *          intSubName;    /* name of subset */
+    xmlChar *          extSubURI;     /* URI of external subset */
+    xmlChar *          extSubSystem;  /* SYSTEM ID of external subset */
+
+    /* xml:space values */
+    int *              space;         /* Should the parser preserve spaces */
+    int                spaceNr;       /* Depth of the parsing stack */
+    int                spaceMax;      /* Max depth of the parsing stack */
+    int *              spaceTab;      /* array of space infos */
+
+    int                depth;         /* to prevent entity substitution loops */
+    xmlParserInputPtr  entity;        /* used to check entities boundaries */
+    int                charset;       /* encoding of the in-memory content
+				         actually an xmlCharEncoding */
+    int                nodelen;       /* Those two fields are there to */
+    int                nodemem;       /* Speed up large node parsing */
+    int                pedantic;      /* signal pedantic warnings */
+    void              *_private;      /* For user data, libxml won't touch it */
+
+    int                loadsubset;    /* should the external subset be loaded */
+};
+
+/**
+ * a SAX Locator.
+ */
+typedef struct _xmlSAXLocator xmlSAXLocator;
+typedef xmlSAXLocator *xmlSAXLocatorPtr;
+struct _xmlSAXLocator {
+    const xmlChar *(*getPublicId)(void *ctx);
+    const xmlChar *(*getSystemId)(void *ctx);
+    int (*getLineNumber)(void *ctx);
+    int (*getColumnNumber)(void *ctx);
+};
+
+/**
+ * a SAX handler is bunch of callbacks called by the parser when processing
+ * of the input generate data or structure informations.
+ */
+
+typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx,
+			    const xmlChar *publicId, const xmlChar *systemId);
+typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name,
+                            const xmlChar *ExternalID, const xmlChar *SystemID);
+typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name,
+                            const xmlChar *ExternalID, const xmlChar *SystemID);
+typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx,
+                            const xmlChar *name);
+typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx,
+                            const xmlChar *name);
+typedef void (*entityDeclSAXFunc) (void *ctx,
+                            const xmlChar *name, int type, const xmlChar *publicId,
+			    const xmlChar *systemId, xmlChar *content);
+typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name,
+			    const xmlChar *publicId, const xmlChar *systemId);
+typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem,
+                            const xmlChar *name, int type, int def,
+			    const xmlChar *defaultValue, xmlEnumerationPtr tree);
+typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name,
+			    int type, xmlElementContentPtr content);
+typedef void (*unparsedEntityDeclSAXFunc)(void *ctx,
+                            const xmlChar *name, const xmlChar *publicId,
+			    const xmlChar *systemId, const xmlChar *notationName);
+typedef void (*setDocumentLocatorSAXFunc) (void *ctx,
+                            xmlSAXLocatorPtr loc);
+typedef void (*startDocumentSAXFunc) (void *ctx);
+typedef void (*endDocumentSAXFunc) (void *ctx);
+typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name,
+                            const xmlChar **atts);
+typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name);
+typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name,
+                                  const xmlChar *value);
+typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name);
+typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch,
+		            int len);
+typedef void (*ignorableWhitespaceSAXFunc) (void *ctx,
+			    const xmlChar *ch, int len);
+typedef void (*processingInstructionSAXFunc) (void *ctx,
+                            const xmlChar *target, const xmlChar *data);
+typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value);
+typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len);
+typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...);
+typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...);
+typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...);
+typedef int (*isStandaloneSAXFunc) (void *ctx);
+typedef int (*hasInternalSubsetSAXFunc) (void *ctx);
+typedef int (*hasExternalSubsetSAXFunc) (void *ctx);
+
+typedef struct _xmlSAXHandler xmlSAXHandler;
+typedef xmlSAXHandler *xmlSAXHandlerPtr;
+struct _xmlSAXHandler {
+    internalSubsetSAXFunc internalSubset;
+    isStandaloneSAXFunc isStandalone;
+    hasInternalSubsetSAXFunc hasInternalSubset;
+    hasExternalSubsetSAXFunc hasExternalSubset;
+    resolveEntitySAXFunc resolveEntity;
+    getEntitySAXFunc getEntity;
+    entityDeclSAXFunc entityDecl;
+    notationDeclSAXFunc notationDecl;
+    attributeDeclSAXFunc attributeDecl;
+    elementDeclSAXFunc elementDecl;
+    unparsedEntityDeclSAXFunc unparsedEntityDecl;
+    setDocumentLocatorSAXFunc setDocumentLocator;
+    startDocumentSAXFunc startDocument;
+    endDocumentSAXFunc endDocument;
+    startElementSAXFunc startElement;
+    endElementSAXFunc endElement;
+    referenceSAXFunc reference;
+    charactersSAXFunc characters;
+    ignorableWhitespaceSAXFunc ignorableWhitespace;
+    processingInstructionSAXFunc processingInstruction;
+    commentSAXFunc comment;
+    warningSAXFunc warning;
+    errorSAXFunc error;
+    fatalErrorSAXFunc fatalError;
+    getParameterEntitySAXFunc getParameterEntity;
+    cdataBlockSAXFunc cdataBlock;
+    externalSubsetSAXFunc externalSubset;
+};
+
+/**
+ * External entity loaders types
+ */
+typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL,
+						     const char *ID,
+						     xmlParserCtxtPtr context);
+
+/**
+ * Global variables: just the default SAX interface tables and XML
+ * version infos.
+ */
+LIBXML_DLL_IMPORT extern const char *xmlParserVersion;
+
+LIBXML_DLL_IMPORT extern xmlSAXLocator xmlDefaultSAXLocator;
+LIBXML_DLL_IMPORT extern xmlSAXHandler xmlDefaultSAXHandler;
+LIBXML_DLL_IMPORT extern xmlSAXHandler htmlDefaultSAXHandler;
+LIBXML_DLL_IMPORT extern xmlSAXHandler sgmlDefaultSAXHandler;
+
+/**
+ * entity substitution default behaviour.
+ */
+
+#ifdef VMS
+LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultVal;
+#define xmlSubstituteEntitiesDefaultValue xmlSubstituteEntitiesDefaultVal
+#else
+LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultValue;
+#endif
+LIBXML_DLL_IMPORT extern int xmlGetWarningsDefaultValue;
+
+
+/**
+ * Init/Cleanup
+ */
+void		xmlInitParser		(void);
+void		xmlCleanupParser	(void);
+
+/**
+ * Input functions
+ */
+int		xmlParserInputRead	(xmlParserInputPtr in,
+					 int len);
+int		xmlParserInputGrow	(xmlParserInputPtr in,
+					 int len);
+
+/**
+ * xmlChar handling
+ */
+xmlChar *	xmlStrdup		(const xmlChar *cur);
+xmlChar *	xmlStrndup		(const xmlChar *cur,
+					 int len);
+xmlChar *	xmlStrsub		(const xmlChar *str,
+					 int start,
+					 int len);
+const xmlChar *	xmlStrchr		(const xmlChar *str,
+					 xmlChar val);
+const xmlChar *	xmlStrstr		(const xmlChar *str,
+					 xmlChar *val);
+const xmlChar *	xmlStrcasestr		(const xmlChar *str,
+					 xmlChar *val);
+int		xmlStrcmp		(const xmlChar *str1,
+					 const xmlChar *str2);
+int		xmlStrncmp		(const xmlChar *str1,
+					 const xmlChar *str2,
+					 int len);
+int		xmlStrcasecmp		(const xmlChar *str1,
+					 const xmlChar *str2);
+int		xmlStrncasecmp		(const xmlChar *str1,
+					 const xmlChar *str2,
+					 int len);
+int		xmlStrEqual		(const xmlChar *str1,
+					 const xmlChar *str2);
+int		xmlStrlen		(const xmlChar *str);
+xmlChar *	xmlStrcat		(xmlChar *cur,
+					 const xmlChar *add);
+xmlChar *	xmlStrncat		(xmlChar *cur,
+					 const xmlChar *add,
+					 int len);
+
+/**
+ * Basic parsing Interfaces
+ */
+xmlDocPtr	xmlParseDoc		(xmlChar *cur);
+xmlDocPtr	xmlParseMemory		(char *buffer,
+					 int size);
+xmlDocPtr	xmlParseFile		(const char *filename);
+int		xmlSubstituteEntitiesDefault(int val);
+int		xmlKeepBlanksDefault	(int val);
+void		xmlStopParser		(xmlParserCtxtPtr ctxt);
+int		xmlPedanticParserDefault(int val);
+
+/**
+ * Recovery mode 
+ */
+xmlDocPtr	xmlRecoverDoc		(xmlChar *cur);
+xmlDocPtr	xmlRecoverMemory	(char *buffer,
+					 int size);
+xmlDocPtr	xmlRecoverFile		(const char *filename);
+
+/**
+ * Less common routines and SAX interfaces
+ */
+int		xmlParseDocument	(xmlParserCtxtPtr ctxt);
+int		xmlParseExtParsedEnt	(xmlParserCtxtPtr ctxt);
+xmlDocPtr	xmlSAXParseDoc		(xmlSAXHandlerPtr sax,
+					 xmlChar *cur,
+					 int recovery);
+int		xmlSAXUserParseFile	(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 const char *filename);
+int		xmlSAXUserParseMemory	(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 char *buffer,
+					 int size);
+xmlDocPtr	xmlSAXParseMemory	(xmlSAXHandlerPtr sax,
+					 char *buffer,
+                                   	 int size,
+					 int recovery);
+xmlDocPtr	xmlSAXParseFile		(xmlSAXHandlerPtr sax,
+					 const char *filename,
+					 int recovery);
+xmlDocPtr	xmlSAXParseEntity	(xmlSAXHandlerPtr sax,
+					 const char *filename);
+xmlDocPtr	xmlParseEntity		(const char *filename);
+xmlDtdPtr	xmlParseDTD		(const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlSAXParseDTD		(xmlSAXHandlerPtr sax,
+					 const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlIOParseDTD		(xmlSAXHandlerPtr sax,
+					 xmlParserInputBufferPtr input,
+					 xmlCharEncoding enc);
+int		xmlParseBalancedChunkMemory(xmlDocPtr doc,
+					 xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 int depth,
+					 const xmlChar *string,
+					 xmlNodePtr *list);
+int		xmlParseExternalEntity	(xmlDocPtr doc,
+					 xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 int depth,
+					 const xmlChar *URL,
+					 const xmlChar *ID,
+					 xmlNodePtr *list);
+int		xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx,
+					 const xmlChar *URL,
+					 const xmlChar *ID,
+					 xmlNodePtr *list);
+
+/**
+ * SAX initialization routines
+ */
+void		xmlDefaultSAXHandlerInit(void);
+void		htmlDefaultSAXHandlerInit(void);
+
+/**
+ * Parser contexts handling.
+ */
+void		xmlInitParserCtxt	(xmlParserCtxtPtr ctxt);
+void		xmlClearParserCtxt	(xmlParserCtxtPtr ctxt);
+void		xmlFreeParserCtxt	(xmlParserCtxtPtr ctxt);
+void		xmlSetupParserForBuffer	(xmlParserCtxtPtr ctxt,
+					 const xmlChar* buffer,
+					 const char* filename);
+xmlParserCtxtPtr xmlCreateDocParserCtxt	(xmlChar *cur);
+
+/**
+ * Reading/setting optional parsing features.
+ */
+
+int		xmlGetFeaturesList	(int *len,
+					 const char **result);
+int		xmlGetFeature		(xmlParserCtxtPtr ctxt,
+					 const char *name,
+					 void *result);
+int		xmlSetFeature		(xmlParserCtxtPtr ctxt,
+					 const char *name,
+					 void *value);
+
+/**
+ * Interfaces for the Push mode
+ */
+xmlParserCtxtPtr xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 const char *chunk,
+					 int size,
+					 const char *filename);
+int		 xmlParseChunk		(xmlParserCtxtPtr ctxt,
+					 const char *chunk,
+					 int size,
+					 int terminate);
+
+/**
+ * Special I/O mode
+ */
+
+xmlParserCtxtPtr xmlCreateIOParserCtxt	(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 xmlInputReadCallback   ioread,
+					 xmlInputCloseCallback  ioclose,
+					 void *ioctx,
+					 xmlCharEncoding enc);
+
+xmlParserInputPtr xmlNewIOInputStream	(xmlParserCtxtPtr ctxt,
+					 xmlParserInputBufferPtr input,
+					 xmlCharEncoding enc);
+
+/**
+ * Node infos
+ */
+const xmlParserNodeInfo*
+		xmlParserFindNodeInfo	(const xmlParserCtxt* ctxt,
+                                               const xmlNode* node);
+void		xmlInitNodeInfoSeq	(xmlParserNodeInfoSeqPtr seq);
+void		xmlClearNodeInfoSeq	(xmlParserNodeInfoSeqPtr seq);
+unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
+                                         const xmlNode* node);
+void		xmlParserAddNodeInfo	(xmlParserCtxtPtr ctxt,
+					 const xmlParserNodeInfo* info);
+
+/*
+ * External entities handling actually implemented in xmlIO
+ */
+
+void		xmlSetExternalEntityLoader(xmlExternalEntityLoader f);
+xmlExternalEntityLoader
+		xmlGetExternalEntityLoader(void);
+xmlParserInputPtr
+		xmlLoadExternalEntity	(const char *URL,
+					 const char *ID,
+					 xmlParserCtxtPtr context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_PARSER_H__ */
+
diff --git a/include/libxml/parserInternals.h b/include/libxml/parserInternals.h
new file mode 100644
index 0000000..3fdb8f6
--- /dev/null
+++ b/include/libxml/parserInternals.h
@@ -0,0 +1,314 @@
+/*
+ * parserInternals.h : internals routines exported by the parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - truncated declaration of xmlParseElementChildrenContentDecl 
+ * for VMS
+ *
+ */
+
+#ifndef __XML_PARSER_INTERNALS_H__
+#define __XML_PARSER_INTERNALS_H__
+
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* 
+  * Identifiers can be longer, but this will be more costly
+  * at runtime.
+  */
+#define XML_MAX_NAMELEN 100
+
+/*
+ * The parser tries to always have that amount of input ready
+ * one of the point is providing context when reporting errors
+ */
+#define INPUT_CHUNK	250
+
+/************************************************************************
+ *									*
+ * UNICODE version of the macros.      					*
+ *									*
+ ************************************************************************/
+/*
+ * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
+ *                  | [#x10000-#x10FFFF]
+ * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
+ */
+#define IS_CHAR(c)							\
+    ((((c) >= 0x20) && ((c) <= 0xD7FF)) ||				\
+     ((c) == 0x09) || ((c) == 0x0A) || ((c) == 0x0D) ||			\
+     (((c) >= 0xE000) && ((c) <= 0xFFFD)) ||				\
+     (((c) >= 0x10000) && ((c) <= 0x10FFFF)))
+
+/*
+ * [3] S ::= (#x20 | #x9 | #xD | #xA)+
+ */
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
+                     ((c) == 0x0D))
+
+/*
+ * [85] BaseChar ::= ... long list see REC ...
+ */
+#define IS_BASECHAR(c) xmlIsBaseChar(c)
+
+/*
+ * [88] Digit ::= ... long list see REC ...
+ */
+#define IS_DIGIT(c) xmlIsDigit(c)
+
+/*
+ * [87] CombiningChar ::= ... long list see REC ...
+ */
+#define IS_COMBINING(c) xmlIsCombining(c)
+
+/*
+ * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 |
+ *                   #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] |
+ *                   [#x309D-#x309E] | [#x30FC-#x30FE]
+ */
+#define IS_EXTENDER(c) xmlIsExtender(c)
+
+/*
+ * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]
+ */
+#define IS_IDEOGRAPHIC(c) xmlIsIdeographic(c)
+
+/*
+ * [84] Letter ::= BaseChar | Ideographic 
+ */
+#define IS_LETTER(c) (IS_BASECHAR(c) || IS_IDEOGRAPHIC(c))
+
+
+/*
+ * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
+ */
+#define IS_PUBIDCHAR(c)	xmlIsPubidChar(c)
+
+#define SKIP_EOL(p) 							\
+    if (*(p) == 0x13) { p++ ; if (*(p) == 0x10) p++; }			\
+    if (*(p) == 0x10) { p++ ; if (*(p) == 0x13) p++; }
+
+#define MOVETO_ENDTAG(p)						\
+    while ((*p) && (*(p) != '>')) (p)++
+
+#define MOVETO_STARTTAG(p)						\
+    while ((*p) && (*(p) != '<')) (p)++
+
+/**
+ * Global vaiables affecting the default parser behaviour.
+ */
+
+LIBXML_DLL_IMPORT extern int xmlParserDebugEntities;
+LIBXML_DLL_IMPORT extern int xmlGetWarningsDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlParserDebugEntities;
+LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlDoValidityCheckingDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlLoadExtDtdDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlPedanticParserDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlKeepBlanksDefaultValue;
+LIBXML_DLL_IMPORT extern xmlChar xmlStringText[];
+LIBXML_DLL_IMPORT extern xmlChar xmlStringTextNoenc[];
+LIBXML_DLL_IMPORT extern xmlChar xmlStringComment[];
+
+/*
+ * Function to finish teh work of the macros where needed
+ */
+int			xmlIsBaseChar	(int c);
+int			xmlIsBlank	(int c);
+int			xmlIsPubidChar	(int c);
+int			xmlIsLetter	(int c);
+int			xmlIsDigit	(int c);
+int			xmlIsIdeographic(int c);
+int			xmlIsCombining	(int c);
+int			xmlIsExtender	(int c);
+int			xmlIsCombining	(int c);
+int			xmlIsChar	(int c);
+
+/**
+ * Parser context
+ */
+xmlParserCtxtPtr	xmlCreateDocParserCtxt	(xmlChar *cur);
+xmlParserCtxtPtr	xmlCreateFileParserCtxt	(const char *filename);
+xmlParserCtxtPtr	xmlCreateMemoryParserCtxt(char *buffer,
+						 int size);
+xmlParserCtxtPtr	xmlNewParserCtxt	(void);
+xmlParserCtxtPtr	xmlCreateEntityParserCtxt(const xmlChar *URL,
+						 const xmlChar *ID,
+						 const xmlChar *base);
+int			xmlSwitchEncoding	(xmlParserCtxtPtr ctxt,
+						 xmlCharEncoding enc);
+int			xmlSwitchToEncoding	(xmlParserCtxtPtr ctxt,
+					     xmlCharEncodingHandlerPtr handler);
+void			xmlFreeParserCtxt	(xmlParserCtxtPtr ctxt);
+
+/**
+ * Entities
+ */
+void			xmlHandleEntity		(xmlParserCtxtPtr ctxt,
+						 xmlEntityPtr entity);
+
+/**
+ * Input Streams
+ */
+xmlParserInputPtr	xmlNewEntityInputStream	(xmlParserCtxtPtr ctxt,
+						 xmlEntityPtr entity);
+void			xmlPushInput		(xmlParserCtxtPtr ctxt,
+						 xmlParserInputPtr input);
+xmlChar			xmlPopInput		(xmlParserCtxtPtr ctxt);
+void			xmlFreeInputStream	(xmlParserInputPtr input);
+xmlParserInputPtr	xmlNewInputFromFile	(xmlParserCtxtPtr ctxt,
+						 const char *filename);
+xmlParserInputPtr	xmlNewInputStream	(xmlParserCtxtPtr ctxt);
+
+/**
+ * Namespaces.
+ */
+xmlChar *		xmlSplitQName		(xmlParserCtxtPtr ctxt,
+						 const xmlChar *name,
+						 xmlChar **prefix);
+xmlChar *		xmlNamespaceParseNCName	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlNamespaceParseQName	(xmlParserCtxtPtr ctxt,
+						 xmlChar **prefix);
+xmlChar *		xmlNamespaceParseNSDef	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseQuotedString	(xmlParserCtxtPtr ctxt);
+void			xmlParseNamespace	(xmlParserCtxtPtr ctxt);
+
+/**
+ * Generic production rules
+ */
+xmlChar *		xmlScanName		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseName		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseNmtoken		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseEntityValue	(xmlParserCtxtPtr ctxt,
+						 xmlChar **orig);
+xmlChar *		xmlParseAttValue	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseSystemLiteral	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParsePubidLiteral	(xmlParserCtxtPtr ctxt);
+void			xmlParseCharData	(xmlParserCtxtPtr ctxt,
+						 int cdata);
+xmlChar *		xmlParseExternalID	(xmlParserCtxtPtr ctxt,
+						 xmlChar **publicID,
+						 int strict);
+void			xmlParseComment		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParsePITarget	(xmlParserCtxtPtr ctxt);
+void			xmlParsePI		(xmlParserCtxtPtr ctxt);
+void			xmlParseNotationDecl	(xmlParserCtxtPtr ctxt);
+void			xmlParseEntityDecl	(xmlParserCtxtPtr ctxt);
+int			xmlParseDefaultDecl	(xmlParserCtxtPtr ctxt,
+						 xmlChar **value);
+xmlEnumerationPtr	xmlParseNotationType	(xmlParserCtxtPtr ctxt);
+xmlEnumerationPtr	xmlParseEnumerationType	(xmlParserCtxtPtr ctxt);
+int			xmlParseEnumeratedType	(xmlParserCtxtPtr ctxt,
+						 xmlEnumerationPtr *tree);
+int			xmlParseAttributeType	(xmlParserCtxtPtr ctxt,
+						 xmlEnumerationPtr *tree);
+void			xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt);
+xmlElementContentPtr	xmlParseElementMixedContentDecl
+						(xmlParserCtxtPtr ctxt);
+#ifdef VMS
+xmlElementContentPtr	xmlParseElementChildrenContentD
+						(xmlParserCtxtPtr ctxt);
+#define xmlParseElementChildrenContentDecl	xmlParseElementChildrenContentD
+#else
+xmlElementContentPtr	xmlParseElementChildrenContentDecl
+						(xmlParserCtxtPtr ctxt);
+#endif
+int			xmlParseElementContentDecl(xmlParserCtxtPtr ctxt,
+						 xmlChar *name,
+						 xmlElementContentPtr *result);
+int			xmlParseElementDecl	(xmlParserCtxtPtr ctxt);
+void			xmlParseMarkupDecl	(xmlParserCtxtPtr ctxt);
+int			xmlParseCharRef		(xmlParserCtxtPtr ctxt);
+xmlEntityPtr		xmlParseEntityRef	(xmlParserCtxtPtr ctxt);
+void			xmlParseReference	(xmlParserCtxtPtr ctxt);
+void			xmlParsePEReference	(xmlParserCtxtPtr ctxt);
+void			xmlParseDocTypeDecl	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseAttribute	(xmlParserCtxtPtr ctxt,
+						 xmlChar **value);
+xmlChar *		xmlParseStartTag	(xmlParserCtxtPtr ctxt);
+void			xmlParseEndTag		(xmlParserCtxtPtr ctxt);
+void			xmlParseCDSect		(xmlParserCtxtPtr ctxt);
+void			xmlParseContent		(xmlParserCtxtPtr ctxt);
+void			xmlParseElement		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseVersionNum	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseVersionInfo	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseEncName		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseEncodingDecl	(xmlParserCtxtPtr ctxt);
+int			xmlParseSDDecl		(xmlParserCtxtPtr ctxt);
+void			xmlParseXMLDecl		(xmlParserCtxtPtr ctxt);
+void			xmlParseTextDecl	(xmlParserCtxtPtr ctxt);
+void			xmlParseMisc		(xmlParserCtxtPtr ctxt);
+void			xmlParseExternalSubset	(xmlParserCtxtPtr ctxt,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID); 
+/*
+ * Entities substitution
+ */
+#define XML_SUBSTITUTE_NONE	0
+#define XML_SUBSTITUTE_REF	1
+#define XML_SUBSTITUTE_PEREF	2
+#define XML_SUBSTITUTE_BOTH 	3
+
+xmlChar *		xmlDecodeEntities	(xmlParserCtxtPtr ctxt,
+						 int len,
+						 int what,
+						 xmlChar end,
+						 xmlChar  end2,
+						 xmlChar end3);
+xmlChar *		xmlStringDecodeEntities	(xmlParserCtxtPtr ctxt,
+						 const xmlChar *str,
+						 int what,
+						 xmlChar end,
+						 xmlChar  end2,
+						 xmlChar end3);
+
+/*
+ * Generated by MACROS on top of parser.c c.f. PUSH_AND_POP
+ */
+int			nodePush		(xmlParserCtxtPtr ctxt,
+						 xmlNodePtr value);
+xmlNodePtr		nodePop			(xmlParserCtxtPtr ctxt);
+int			inputPush		(xmlParserCtxtPtr ctxt,
+						 xmlParserInputPtr value);
+xmlParserInputPtr	inputPop		(xmlParserCtxtPtr ctxt);
+
+/*
+ * other comodities shared between parser.c and parserInternals
+ */
+int			xmlSkipBlankChars	(xmlParserCtxtPtr ctxt);
+int			xmlStringCurrentChar	(xmlParserCtxtPtr ctxt,
+						 const xmlChar *cur,
+						 int *len);
+void			xmlParserHandlePEReference(xmlParserCtxtPtr ctxt);
+void			xmlParserHandleReference(xmlParserCtxtPtr ctxt);
+xmlChar                *namePop			(xmlParserCtxtPtr ctxt);
+int			xmlCheckLanguageID	(const xmlChar *lang);
+
+/*
+ * Really core function shared with HTML parser
+ */
+int			xmlCurrentChar		(xmlParserCtxtPtr ctxt,
+						 int *len);
+int			xmlCopyChar		(int len,
+						 xmlChar *out,
+						 int val);
+void			xmlNextChar		(xmlParserCtxtPtr ctxt);
+void			xmlParserInputShrink	(xmlParserInputPtr in);
+
+#ifdef LIBXML_HTML_ENABLED
+/*
+ * Actually comes from the HTML parser but launched from the init stuff
+ */
+void			htmlInitAutoClose	(void);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_PARSER_INTERNALS_H__ */
diff --git a/include/libxml/tree.h b/include/libxml/tree.h
new file mode 100644
index 0000000..648817d
--- /dev/null
+++ b/include/libxml/tree.h
@@ -0,0 +1,701 @@
+/*
+ * tree.h : describes the structures found in an tree resulting
+ *          from an XML parsing.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - added redefinition of xmlBufferWriteChar for VMS
+ *
+ */
+
+#ifndef __XML_TREE_H__
+#define __XML_TREE_H__
+
+#include <stdio.h>
+#include <libxml/xmlversion.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XML_XML_NAMESPACE \
+    (const xmlChar *) "http://www.w3.org/XML/1998/namespace"
+
+/*
+ * The different element types carried by an XML tree
+ *
+ * NOTE: This is synchronized with DOM Level1 values
+ *       See http://www.w3.org/TR/REC-DOM-Level-1/
+ *
+ * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should
+ * be deprecated to use an XML_DTD_NODE.
+ */
+typedef enum {
+    XML_ELEMENT_NODE=		1,
+    XML_ATTRIBUTE_NODE=		2,
+    XML_TEXT_NODE=		3,
+    XML_CDATA_SECTION_NODE=	4,
+    XML_ENTITY_REF_NODE=	5,
+    XML_ENTITY_NODE=		6,
+    XML_PI_NODE=		7,
+    XML_COMMENT_NODE=		8,
+    XML_DOCUMENT_NODE=		9,
+    XML_DOCUMENT_TYPE_NODE=	10,
+    XML_DOCUMENT_FRAG_NODE=	11,
+    XML_NOTATION_NODE=		12,
+    XML_HTML_DOCUMENT_NODE=	13,
+    XML_DTD_NODE=		14,
+    XML_ELEMENT_DECL=		15,
+    XML_ATTRIBUTE_DECL=		16,
+    XML_ENTITY_DECL=		17,
+    XML_NAMESPACE_DECL=		18,
+    XML_XINCLUDE_START=		19,
+    XML_XINCLUDE_END=		20
+#ifdef LIBXML_SGML_ENABLED
+   ,XML_SGML_DOCUMENT_NODE=	21
+#endif
+} xmlElementType;
+
+/*
+ * Size of an internal character representation.
+ *
+ * We use 8bit chars internal representation for memory efficiency,
+ * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle
+ * correctly non ISO-Latin input.
+ */
+
+typedef unsigned char xmlChar;
+
+#ifndef WIN32
+#ifndef CHAR
+#define CHAR xmlChar
+#endif
+#endif
+
+#define BAD_CAST (xmlChar *)
+
+/*
+ * a DTD Notation definition
+ */
+
+typedef struct _xmlNotation xmlNotation;
+typedef xmlNotation *xmlNotationPtr;
+struct _xmlNotation {
+    const xmlChar               *name;	/* Notation name */
+    const xmlChar               *PublicID;	/* Public identifier, if any */
+    const xmlChar               *SystemID;	/* System identifier, if any */
+};
+
+/*
+ * a DTD Attribute definition
+ */
+
+typedef enum {
+    XML_ATTRIBUTE_CDATA = 1,
+    XML_ATTRIBUTE_ID,
+    XML_ATTRIBUTE_IDREF	,
+    XML_ATTRIBUTE_IDREFS,
+    XML_ATTRIBUTE_ENTITY,
+    XML_ATTRIBUTE_ENTITIES,
+    XML_ATTRIBUTE_NMTOKEN,
+    XML_ATTRIBUTE_NMTOKENS,
+    XML_ATTRIBUTE_ENUMERATION,
+    XML_ATTRIBUTE_NOTATION
+} xmlAttributeType;
+
+typedef enum {
+    XML_ATTRIBUTE_NONE = 1,
+    XML_ATTRIBUTE_REQUIRED,
+    XML_ATTRIBUTE_IMPLIED,
+    XML_ATTRIBUTE_FIXED
+} xmlAttributeDefault;
+
+typedef struct _xmlEnumeration xmlEnumeration;
+typedef xmlEnumeration *xmlEnumerationPtr;
+struct _xmlEnumeration {
+    struct _xmlEnumeration    *next;	/* next one */
+    const xmlChar            *name;	/* Enumeration name */
+};
+
+typedef struct _xmlAttribute xmlAttribute;
+typedef xmlAttribute *xmlAttributePtr;
+struct _xmlAttribute {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	        /* for Corba, must be first ! */
+#endif
+    xmlElementType          type;       /* XML_ATTRIBUTE_DECL, must be second ! */
+    const xmlChar          *name;	/* Attribute name */
+    struct _xmlNode    *children;	/* NULL */
+    struct _xmlNode        *last;	/* NULL */
+    struct _xmlDtd       *parent;	/* -> DTD */
+    struct _xmlNode        *next;	/* next sibling link  */
+    struct _xmlNode        *prev;	/* previous sibling link  */
+    struct _xmlDoc          *doc;       /* the containing document */
+
+    struct _xmlAttribute  *nexth;	/* next in hash table */
+    xmlAttributeType       atype;	/* The attribute type */
+    xmlAttributeDefault      def;	/* the default */
+    const xmlChar  *defaultValue;	/* or the default value */
+    xmlEnumerationPtr       tree;       /* or the enumeration tree if any */
+    const xmlChar        *prefix;	/* the namespace prefix if any */
+    const xmlChar          *elem;	/* Element holding the attribute */
+};
+
+/*
+ * a DTD Element definition.
+ */
+typedef enum {
+    XML_ELEMENT_CONTENT_PCDATA = 1,
+    XML_ELEMENT_CONTENT_ELEMENT,
+    XML_ELEMENT_CONTENT_SEQ,
+    XML_ELEMENT_CONTENT_OR
+} xmlElementContentType;
+
+typedef enum {
+    XML_ELEMENT_CONTENT_ONCE = 1,
+    XML_ELEMENT_CONTENT_OPT,
+    XML_ELEMENT_CONTENT_MULT,
+    XML_ELEMENT_CONTENT_PLUS
+} xmlElementContentOccur;
+
+typedef struct _xmlElementContent xmlElementContent;
+typedef xmlElementContent *xmlElementContentPtr;
+struct _xmlElementContent {
+    xmlElementContentType     type;	/* PCDATA, ELEMENT, SEQ or OR */
+    xmlElementContentOccur    ocur;	/* ONCE, OPT, MULT or PLUS */
+    const xmlChar            *name;	/* Element name */
+    struct _xmlElementContent *c1;	/* first child */
+    struct _xmlElementContent *c2;	/* second child */
+};
+
+typedef enum {
+    XML_ELEMENT_TYPE_EMPTY = 1,
+    XML_ELEMENT_TYPE_ANY,
+    XML_ELEMENT_TYPE_MIXED,
+    XML_ELEMENT_TYPE_ELEMENT
+} xmlElementTypeVal;
+
+typedef struct _xmlElement xmlElement;
+typedef xmlElement *xmlElementPtr;
+struct _xmlElement {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	        /* for Corba, must be first ! */
+#endif
+    xmlElementType          type;       /* XML_ELEMENT_DECL, must be second ! */
+    const xmlChar          *name;	/* Element name */
+    struct _xmlNode    *children;	/* NULL */
+    struct _xmlNode        *last;	/* NULL */
+    struct _xmlDtd       *parent;	/* -> DTD */
+    struct _xmlNode        *next;	/* next sibling link  */
+    struct _xmlNode        *prev;	/* previous sibling link  */
+    struct _xmlDoc          *doc;       /* the containing document */
+
+    xmlElementTypeVal      etype;	/* The type */
+    xmlElementContentPtr content;	/* the allowed element content */
+    xmlAttributePtr   attributes;	/* List of the declared attributes */
+    const xmlChar        *prefix;	/* the namespace prefix if any */
+};
+
+/*
+ * An XML namespace.
+ * Note that prefix == NULL is valid, it defines the default namespace
+ * within the subtree (until overriden).
+ *
+ * XML_GLOBAL_NAMESPACE is now deprecated for good
+ * xmlNsType is unified with xmlElementType
+ */
+
+#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL
+typedef xmlElementType xmlNsType;
+
+typedef struct _xmlNs xmlNs;
+typedef xmlNs *xmlNsPtr;
+struct _xmlNs {
+    struct _xmlNs  *next;	/* next Ns link for this node  */
+    xmlNsType      type;	/* global or local */
+    const xmlChar *href;	/* URL for the namespace */
+    const xmlChar *prefix;	/* prefix for the namespace */
+};
+
+/*
+ * An XML DtD, as defined by <!DOCTYPE.
+ */
+typedef struct _xmlDtd xmlDtd;
+typedef xmlDtd *xmlDtdPtr;
+struct _xmlDtd {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType  type;       /* XML_DTD_NODE, must be second ! */
+    const xmlChar *name;	/* Name of the DTD */
+    struct _xmlNode *children;	/* the value of the property link */
+    struct _xmlNode *last;	/* last child link */
+    struct _xmlDoc  *parent;	/* child->parent link */
+    struct _xmlNode *next;	/* next sibling link  */
+    struct _xmlNode *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* the containing document */
+
+    /* End of common part */
+    void          *notations;   /* Hash table for notations if any */
+    void          *elements;    /* Hash table for elements if any */
+    void          *attributes;  /* Hash table for attributes if any */
+    void          *entities;    /* Hash table for entities if any */
+    const xmlChar *ExternalID;	/* External identifier for PUBLIC DTD */
+    const xmlChar *SystemID;	/* URI for a SYSTEM or PUBLIC DTD */
+    void          *pentities;   /* Hash table for param entities if any */
+};
+
+/*
+ * A attribute of an XML node.
+ */
+typedef struct _xmlAttr xmlAttr;
+typedef xmlAttr *xmlAttrPtr;
+struct _xmlAttr {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType   type;      /* XML_ATTRIBUTE_NODE, must be second ! */
+    const xmlChar   *name;      /* the name of the property */
+    struct _xmlNode *children;	/* the value of the property */
+    struct _xmlNode *last;	/* NULL */
+    struct _xmlNode *parent;	/* child->parent link */
+    struct _xmlAttr *next;	/* next sibling link  */
+    struct _xmlAttr *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* the containing document */
+    xmlNs           *ns;        /* pointer to the associated namespace */
+    xmlAttributeType atype;     /* the attribute type if validating */
+};
+
+/*
+ * An XML ID instance.
+ */
+
+typedef struct _xmlID xmlID;
+typedef xmlID *xmlIDPtr;
+struct _xmlID {
+    struct _xmlID    *next;	/* next ID */
+    const xmlChar    *value;	/* The ID name */
+    xmlAttrPtr        attr;	/* The attribut holding it */
+};
+
+/*
+ * An XML IDREF instance.
+ */
+
+typedef struct _xmlRef xmlRef;
+typedef xmlRef *xmlRefPtr;
+struct _xmlRef {
+    struct _xmlRef    *next;	/* next Ref */
+    const xmlChar     *value;	/* The Ref name */
+    xmlAttrPtr        attr;	/* The attribut holding it */
+};
+
+/*
+ * A buffer structure
+ */
+
+typedef enum {
+    XML_BUFFER_ALLOC_DOUBLEIT,
+    XML_BUFFER_ALLOC_EXACT
+} xmlBufferAllocationScheme;
+
+typedef struct _xmlBuffer xmlBuffer;
+typedef xmlBuffer *xmlBufferPtr;
+struct _xmlBuffer {
+    xmlChar *content;		/* The buffer content UTF8 */
+    unsigned int use;		/* The buffer size used */
+    unsigned int size;		/* The buffer size */
+    xmlBufferAllocationScheme alloc; /* The realloc method */
+};
+
+/*
+ * A node in an XML tree.
+ */
+typedef struct _xmlNode xmlNode;
+typedef xmlNode *xmlNodePtr;
+struct _xmlNode {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType   type;	/* type number, must be second ! */
+    const xmlChar   *name;      /* the name of the node, or the entity */
+    struct _xmlNode *children;	/* parent->childs link */
+    struct _xmlNode *last;	/* last child link */
+    struct _xmlNode *parent;	/* child->parent link */
+    struct _xmlNode *next;	/* next sibling link  */
+    struct _xmlNode *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* the containing document */
+    xmlNs           *ns;        /* pointer to the associated namespace */
+#ifndef XML_USE_BUFFER_CONTENT    
+    xmlChar         *content;   /* the content */
+#else
+    xmlBufferPtr     content;   /* the content in a buffer */
+#endif
+
+    /* End of common part */
+    struct _xmlAttr *properties;/* properties list */
+    xmlNs           *nsDef;     /* namespace definitions on this node */
+};
+
+/*
+ * An XML document.
+ */
+typedef struct _xmlDoc xmlDoc;
+typedef xmlDoc *xmlDocPtr;
+struct _xmlDoc {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType  type;       /* XML_DOCUMENT_NODE, must be second ! */
+    char           *name;	/* name/filename/URI of the document */
+    struct _xmlNode *children;	/* the document tree */
+    struct _xmlNode *last;	/* last child link */
+    struct _xmlNode *parent;	/* child->parent link */
+    struct _xmlNode *next;	/* next sibling link  */
+    struct _xmlNode *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* autoreference to itself */
+
+    /* End of common part */
+    int             compression;/* level of zlib compression */
+    int             standalone; /* standalone document (no external refs) */
+    struct _xmlDtd  *intSubset;	/* the document internal subset */
+    struct _xmlDtd  *extSubset;	/* the document external subset */
+    struct _xmlNs   *oldNs;	/* Global namespace, the old way */
+    const xmlChar  *version;	/* the XML version string */
+    const xmlChar  *encoding;   /* external initial encoding, if any */
+    void           *ids;        /* Hash table for ID attributes if any */
+    void           *refs;       /* Hash table for IDREFs attributes if any */
+    const xmlChar  *URL;	/* The URI for that document */
+    int             charset;    /* encoding of the in-memory content
+				   actually an xmlCharEncoding */
+};
+
+/*
+ * Compatibility naming layer with libxml1
+ */
+#ifndef xmlChildrenNode
+#define xmlChildrenNode children
+#define xmlRootNode children
+#endif
+
+/*
+ * Variables.
+ */
+LIBXML_DLL_IMPORT extern xmlNsPtr baseDTD;
+LIBXML_DLL_IMPORT extern int oldXMLWDcompatibility;/* maintain compatibility with old WD */
+LIBXML_DLL_IMPORT extern int xmlIndentTreeOutput;  /* try to indent the tree dumps */
+LIBXML_DLL_IMPORT extern xmlBufferAllocationScheme xmlBufferAllocScheme; /* alloc scheme to use */
+LIBXML_DLL_IMPORT extern int xmlSaveNoEmptyTags;   /* save empty tags as <empty></empty> */
+
+/*
+ * Handling Buffers.
+ */
+
+xmlBufferPtr	xmlBufferCreate		(void);
+xmlBufferPtr	xmlBufferCreateSize	(size_t size);
+void		xmlBufferFree		(xmlBufferPtr buf);
+int		xmlBufferDump		(FILE *file,
+					 xmlBufferPtr buf);
+void		xmlBufferAdd		(xmlBufferPtr buf,
+					 const xmlChar *str,
+					 int len);
+void		xmlBufferAddHead	(xmlBufferPtr buf,
+					 const xmlChar *str,
+					 int len);
+void		xmlBufferCat		(xmlBufferPtr buf,
+					 const xmlChar *str);
+void		xmlBufferCCat		(xmlBufferPtr buf,
+					 const char *str);
+int		xmlBufferShrink		(xmlBufferPtr buf,
+					 unsigned int len);
+int		xmlBufferGrow		(xmlBufferPtr buf,
+					 unsigned int len);
+void		xmlBufferEmpty		(xmlBufferPtr buf);
+const xmlChar*	xmlBufferContent	(const xmlBufferPtr buf);
+int		xmlBufferUse		(const xmlBufferPtr buf);
+void		xmlBufferSetAllocationScheme(xmlBufferPtr buf,
+					 xmlBufferAllocationScheme scheme);
+int		xmlBufferLength		(const xmlBufferPtr buf);
+
+/*
+ * Creating/freeing new structures
+ */
+xmlDtdPtr	xmlCreateIntSubset	(xmlDocPtr doc,
+					 const xmlChar *name,
+					 const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlNewDtd		(xmlDocPtr doc,
+					 const xmlChar *name,
+					 const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlGetIntSubset		(xmlDocPtr doc);
+void		xmlFreeDtd		(xmlDtdPtr cur);
+xmlNsPtr	xmlNewGlobalNs		(xmlDocPtr doc,
+					 const xmlChar *href,
+					 const xmlChar *prefix);
+xmlNsPtr	xmlNewNs		(xmlNodePtr node,
+					 const xmlChar *href,
+					 const xmlChar *prefix);
+void		xmlFreeNs		(xmlNsPtr cur);
+xmlDocPtr 	xmlNewDoc		(const xmlChar *version);
+void		xmlFreeDoc		(xmlDocPtr cur);
+xmlAttrPtr	xmlNewDocProp		(xmlDocPtr doc,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlAttrPtr	xmlNewProp		(xmlNodePtr node,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlAttrPtr	xmlNewNsProp		(xmlNodePtr node,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *value);
+void		xmlFreePropList		(xmlAttrPtr cur);
+void		xmlFreeProp		(xmlAttrPtr cur);
+xmlAttrPtr	xmlCopyProp		(xmlNodePtr target,
+					 xmlAttrPtr cur);
+xmlAttrPtr	xmlCopyPropList		(xmlNodePtr target,
+					 xmlAttrPtr cur);
+xmlDtdPtr	xmlCopyDtd		(xmlDtdPtr dtd);
+xmlDocPtr	xmlCopyDoc		(xmlDocPtr doc,
+					 int recursive);
+
+/*
+ * Creating new nodes
+ */
+xmlNodePtr	xmlNewDocNode		(xmlDocPtr doc,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewDocRawNode	(xmlDocPtr doc,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewNode		(xmlNsPtr ns,
+					 const xmlChar *name);
+xmlNodePtr	xmlNewChild		(xmlNodePtr parent,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewTextChild		(xmlNodePtr parent,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewDocText		(xmlDocPtr doc,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewText		(const xmlChar *content);
+xmlNodePtr	xmlNewPI		(const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewDocTextLen	(xmlDocPtr doc,
+					 const xmlChar *content,
+					 int len);
+xmlNodePtr	xmlNewTextLen		(const xmlChar *content,
+					 int len);
+xmlNodePtr	xmlNewDocComment	(xmlDocPtr doc,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewComment		(const xmlChar *content);
+xmlNodePtr	xmlNewCDataBlock	(xmlDocPtr doc,
+					 const xmlChar *content,
+					 int len);
+xmlNodePtr	xmlNewCharRef		(xmlDocPtr doc,
+					 const xmlChar *name);
+xmlNodePtr	xmlNewReference		(xmlDocPtr doc,
+					 const xmlChar *name);
+xmlNodePtr	xmlCopyNode		(xmlNodePtr node,
+					 int recursive);
+xmlNodePtr	xmlCopyNodeList		(xmlNodePtr node);
+xmlNodePtr	xmlNewDocFragment	(xmlDocPtr doc);
+
+/*
+ * Navigating
+ */
+xmlNodePtr	xmlDocGetRootElement	(xmlDocPtr doc);
+xmlNodePtr	xmlGetLastChild		(xmlNodePtr parent);
+int		xmlNodeIsText		(xmlNodePtr node);
+int		xmlIsBlankNode		(xmlNodePtr node);
+
+/*
+ * Changing the structure
+ */
+xmlNodePtr	xmlDocSetRootElement	(xmlDocPtr doc,
+					 xmlNodePtr root);
+void		xmlNodeSetName		(xmlNodePtr cur,
+					 const xmlChar *name);
+xmlNodePtr	xmlAddChild		(xmlNodePtr parent,
+					 xmlNodePtr cur);
+xmlNodePtr	xmlAddChildList		(xmlNodePtr parent,
+					 xmlNodePtr cur);
+xmlNodePtr	xmlReplaceNode		(xmlNodePtr old,
+					 xmlNodePtr cur);
+xmlNodePtr	xmlAddSibling		(xmlNodePtr cur,
+					 xmlNodePtr elem);
+xmlNodePtr	xmlAddPrevSibling	(xmlNodePtr cur,
+					 xmlNodePtr elem);
+xmlNodePtr	xmlAddNextSibling	(xmlNodePtr cur,
+					 xmlNodePtr elem);
+void		xmlUnlinkNode		(xmlNodePtr cur);
+xmlNodePtr	xmlTextMerge		(xmlNodePtr first,
+					 xmlNodePtr second);
+void		xmlTextConcat		(xmlNodePtr node,
+					 const xmlChar *content,
+					 int len);
+void		xmlFreeNodeList		(xmlNodePtr cur);
+void		xmlFreeNode		(xmlNodePtr cur);
+void		xmlSetTreeDoc		(xmlNodePtr tree,
+					 xmlDocPtr doc);
+void		xmlSetListDoc		(xmlNodePtr list,
+					 xmlDocPtr doc);
+
+/*
+ * Namespaces
+ */
+xmlNsPtr	xmlSearchNs		(xmlDocPtr doc,
+					 xmlNodePtr node,
+					 const xmlChar *nameSpace);
+xmlNsPtr	xmlSearchNsByHref	(xmlDocPtr doc,
+					 xmlNodePtr node,
+					 const xmlChar *href);
+xmlNsPtr *	xmlGetNsList		(xmlDocPtr doc,
+					 xmlNodePtr node);
+void		xmlSetNs		(xmlNodePtr node,
+					 xmlNsPtr ns);
+xmlNsPtr	xmlCopyNamespace	(xmlNsPtr cur);
+xmlNsPtr	xmlCopyNamespaceList	(xmlNsPtr cur);
+
+/*
+ * Changing the content.
+ */
+xmlAttrPtr	xmlSetProp		(xmlNodePtr node,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlChar *	xmlGetProp		(xmlNodePtr node,
+					 const xmlChar *name);
+xmlAttrPtr	xmlHasProp		(xmlNodePtr node,
+					 const xmlChar *name);
+xmlAttrPtr	xmlSetNsProp		(xmlNodePtr node,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlChar *	xmlGetNsProp		(xmlNodePtr node,
+					 const xmlChar *name,
+					 const xmlChar *nameSpace);
+xmlNodePtr	xmlStringGetNodeList	(xmlDocPtr doc,
+					 const xmlChar *value);
+xmlNodePtr	xmlStringLenGetNodeList	(xmlDocPtr doc,
+					 const xmlChar *value,
+					 int len);
+xmlChar *	xmlNodeListGetString	(xmlDocPtr doc,
+					 xmlNodePtr list,
+					 int inLine);
+xmlChar *	xmlNodeListGetRawString	(xmlDocPtr doc,
+					 xmlNodePtr list,
+					 int inLine);
+void		xmlNodeSetContent	(xmlNodePtr cur,
+					 const xmlChar *content);
+void		xmlNodeSetContentLen	(xmlNodePtr cur,
+					 const xmlChar *content,
+					 int len);
+void		xmlNodeAddContent	(xmlNodePtr cur,
+					 const xmlChar *content);
+void		xmlNodeAddContentLen	(xmlNodePtr cur,
+					 const xmlChar *content,
+					 int len);
+xmlChar *	xmlNodeGetContent	(xmlNodePtr cur);
+xmlChar *	xmlNodeGetLang		(xmlNodePtr cur);
+void		xmlNodeSetLang		(xmlNodePtr cur,
+					 const xmlChar *lang);
+int		xmlNodeGetSpacePreserve	(xmlNodePtr cur);
+void		xmlNodeSetSpacePreserve (xmlNodePtr cur, int
+					 val);
+xmlChar *	xmlNodeGetBase		(xmlDocPtr doc,
+					 xmlNodePtr cur);
+void		xmlNodeSetBase		(xmlNodePtr cur,
+					 xmlChar *uri);
+
+/*
+ * Removing content.
+ */
+int		xmlRemoveProp		(xmlAttrPtr attr);
+int		xmlRemoveNode		(xmlNodePtr node); /* TODO */
+
+/*
+ * Internal, don't use
+ */
+#ifdef VMS
+void		xmlBufferWriteXmlCHAR	(xmlBufferPtr buf,
+					 const xmlChar *string);
+#define 	xmlBufferWriteCHAR 	xmlBufferWriteXmlCHAR
+#else
+void		xmlBufferWriteCHAR	(xmlBufferPtr buf,
+					 const xmlChar *string);
+#endif
+void		xmlBufferWriteChar	(xmlBufferPtr buf,
+					 const char *string);
+void		xmlBufferWriteQuotedString(xmlBufferPtr buf,
+					 const xmlChar *string);
+
+/*
+ * Namespace handling
+ */
+int		xmlReconciliateNs	(xmlDocPtr doc,
+					 xmlNodePtr tree);
+
+/*
+ * Saving
+ */
+void		xmlDocDumpFormatMemory	(xmlDocPtr cur,
+					 xmlChar**mem,
+					 int *size,
+					 int format);
+void		xmlDocDumpMemory	(xmlDocPtr cur,
+					 xmlChar**mem,
+					 int *size);
+void		xmlDocDumpMemoryEnc	(xmlDocPtr out_doc,
+					 xmlChar **doc_txt_ptr,
+					 int * doc_txt_len,
+					 const char *txt_encoding);
+void		xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc,
+					 xmlChar **doc_txt_ptr,
+					 int * doc_txt_len,
+					 const char *txt_encoding,
+					 int format);
+int		xmlDocDump		(FILE *f,
+					 xmlDocPtr cur);
+void		xmlElemDump		(FILE *f,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur);
+int		xmlSaveFile		(const char *filename,
+					 xmlDocPtr cur);
+void		xmlNodeDump		(xmlBufferPtr buf,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur,
+					 int level,
+					 int format);
+
+/* This one is exported from xmlIO.h
+ 
+int		xmlSaveFileTo		(xmlOutputBuffer *buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+ */ 					 
+
+int		xmlSaveFileEnc		(const char *filename,
+					 xmlDocPtr cur,
+					 const char *encoding);
+
+/*
+ * Compression
+ */
+int		xmlGetDocCompressMode	(xmlDocPtr doc);
+void		xmlSetDocCompressMode	(xmlDocPtr doc,
+					 int mode);
+int		xmlGetCompressMode	(void);
+void		xmlSetCompressMode	(int mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_TREE_H__ */
+
diff --git a/include/libxml/uri.h b/include/libxml/uri.h
new file mode 100644
index 0000000..e7aeda4
--- /dev/null
+++ b/include/libxml/uri.h
@@ -0,0 +1,61 @@
+/**
+ * uri.c: library of generic URI related routines 
+ *
+ * Reference: RFC 2396
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_URI_H__
+#define __XML_URI_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *
+ */
+typedef struct _xmlURI xmlURI;
+typedef xmlURI *xmlURIPtr;
+struct _xmlURI {
+    char *scheme;
+    char *opaque;
+    char *authority;
+    char *server;
+    char *user;
+    int port;
+    char *path;
+    char *query;
+    char *fragment;
+};
+
+/*
+ * This function is in tree.h:
+ * xmlChar *	xmlNodeGetBase	(xmlDocPtr doc,
+ *                               xmlNodePtr cur);
+ */
+xmlURIPtr	xmlCreateURI		(void);
+xmlChar *	xmlBuildURI		(const xmlChar *URI,
+	                        	 const xmlChar *base);
+xmlURIPtr	xmlParseURI		(const char *URI);
+int		xmlParseURIReference	(xmlURIPtr uri,
+					 const char *str);
+xmlChar *	xmlSaveUri		(xmlURIPtr uri);
+void		xmlPrintURI		(FILE *stream,
+					 xmlURIPtr uri);
+char *		xmlURIUnescapeString	(const char *str,
+					 int len,
+					 char *target);
+int		xmlNormalizeURIPath	(char *path);
+xmlChar *	xmlURIEscape		(const xmlChar *str);
+void		xmlFreeURI		(xmlURIPtr uri);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_URI_H__ */
diff --git a/include/libxml/valid.h b/include/libxml/valid.h
new file mode 100644
index 0000000..a7eb675
--- /dev/null
+++ b/include/libxml/valid.h
@@ -0,0 +1,236 @@
+/*
+ * valid.h : interface to the DTD handling and the validity checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifndef __XML_VALID_H__
+#define __XML_VALID_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * an xmlValidCtxt is used for error reporting when validating
+ */
+
+typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...);
+typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...);
+
+typedef struct _xmlValidCtxt xmlValidCtxt;
+typedef xmlValidCtxt *xmlValidCtxtPtr;
+struct _xmlValidCtxt {
+    void *userData;			/* user specific data block */
+    xmlValidityErrorFunc error;		/* the callback in case of errors */
+    xmlValidityWarningFunc warning;	/* the callback in case of warning */
+
+    /* Node analysis stack used when validating within entities */
+    xmlNodePtr         node;          /* Current parsed Node */
+    int                nodeNr;        /* Depth of the parsing stack */
+    int                nodeMax;       /* Max depth of the parsing stack */
+    xmlNodePtr        *nodeTab;       /* array of nodes */
+
+    int              finishDtd;       /* finished validating the Dtd ? */
+    xmlDocPtr              doc;       /* the document */
+    int                  valid;       /* temporary validity check result */
+};
+
+/*
+ * ALl notation declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlNotationTable;
+typedef xmlNotationTable *xmlNotationTablePtr;
+
+/*
+ * ALl element declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlElementTable;
+typedef xmlElementTable *xmlElementTablePtr;
+
+/*
+ * ALl attribute declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlAttributeTable;
+typedef xmlAttributeTable *xmlAttributeTablePtr;
+
+/*
+ * ALl IDs attributes are stored in a table
+ * there is one table per document
+ */
+
+typedef struct _xmlHashTable xmlIDTable;
+typedef xmlIDTable *xmlIDTablePtr;
+
+/*
+ * ALl Refs attributes are stored in a table
+ * there is one table per document
+ */
+
+typedef struct _xmlHashTable xmlRefTable;
+typedef xmlRefTable *xmlRefTablePtr;
+
+/* helper */
+xmlChar *           xmlSplitQName2	(const xmlChar *name,
+					 xmlChar **prefix);
+
+/* Notation */
+xmlNotationPtr	    xmlAddNotationDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDtdPtr dtd,
+					 const xmlChar *name,
+					 const xmlChar *PublicID,
+					 const xmlChar *SystemID);
+xmlNotationTablePtr xmlCopyNotationTable(xmlNotationTablePtr table);
+void		    xmlFreeNotationTable(xmlNotationTablePtr table);
+void		    xmlDumpNotationDecl	(xmlBufferPtr buf,
+					 xmlNotationPtr nota);
+void		    xmlDumpNotationTable(xmlBufferPtr buf,
+					 xmlNotationTablePtr table);
+
+/* Element Content */
+xmlElementContentPtr xmlNewElementContent (xmlChar *name,
+					   xmlElementContentType type);
+xmlElementContentPtr xmlCopyElementContent(xmlElementContentPtr content);
+void		     xmlFreeElementContent(xmlElementContentPtr cur);
+void		     xmlSprintfElementContent(char *buf,
+	                                   xmlElementContentPtr content,
+					   int glob);
+
+/* Element */
+xmlElementPtr	   xmlAddElementDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDtdPtr dtd,
+					 const xmlChar *name,
+					 xmlElementTypeVal type,
+					 xmlElementContentPtr content);
+xmlElementTablePtr xmlCopyElementTable	(xmlElementTablePtr table);
+void		   xmlFreeElementTable	(xmlElementTablePtr table);
+void		   xmlDumpElementTable	(xmlBufferPtr buf,
+					 xmlElementTablePtr table);
+void		   xmlDumpElementDecl	(xmlBufferPtr buf,
+					 xmlElementPtr elem);
+
+/* Enumeration */
+xmlEnumerationPtr  xmlCreateEnumeration	(xmlChar *name);
+void		   xmlFreeEnumeration	(xmlEnumerationPtr cur);
+xmlEnumerationPtr  xmlCopyEnumeration	(xmlEnumerationPtr cur);
+
+/* Attribute */
+xmlAttributePtr	    xmlAddAttributeDecl	    (xmlValidCtxtPtr ctxt,
+					     xmlDtdPtr dtd,
+					     const xmlChar *elem,
+					     const xmlChar *name,
+					     const xmlChar *ns,
+					     xmlAttributeType type,
+					     xmlAttributeDefault def,
+					     const xmlChar *defaultValue,
+					     xmlEnumerationPtr tree);
+xmlAttributeTablePtr xmlCopyAttributeTable  (xmlAttributeTablePtr table);
+void		     xmlFreeAttributeTable  (xmlAttributeTablePtr table);
+void		     xmlDumpAttributeTable  (xmlBufferPtr buf,
+					     xmlAttributeTablePtr table);
+void		     xmlDumpAttributeDecl   (xmlBufferPtr buf,
+					     xmlAttributePtr attr);
+
+/* IDs */
+xmlIDPtr	xmlAddID	(xmlValidCtxtPtr ctxt,
+				 xmlDocPtr doc,
+				 const xmlChar *value,
+				 xmlAttrPtr attr);
+xmlIDTablePtr	xmlCopyIDTable	(xmlIDTablePtr table);
+void		xmlFreeIDTable	(xmlIDTablePtr table);
+xmlAttrPtr	xmlGetID	(xmlDocPtr doc,
+				 const xmlChar *ID);
+int		xmlIsID		(xmlDocPtr doc,
+				 xmlNodePtr elem,
+				 xmlAttrPtr attr);
+int		xmlRemoveID	(xmlDocPtr doc, xmlAttrPtr attr);
+
+/* IDREFs */
+xmlRefPtr	xmlAddRef	(xmlValidCtxtPtr ctxt,
+				 xmlDocPtr doc,
+				 const xmlChar *value,
+				 xmlAttrPtr attr);
+xmlRefTablePtr	xmlCopyRefTable	(xmlRefTablePtr table);
+void		xmlFreeRefTable	(xmlRefTablePtr table);
+int		xmlIsRef	(xmlDocPtr doc,
+				 xmlNodePtr elem,
+				 xmlAttrPtr attr);
+int		xmlRemoveRef	(xmlDocPtr doc, xmlAttrPtr attr);
+
+/**
+ * The public function calls related to validity checking
+ */
+
+int		xmlValidateRoot		(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateElementDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlElementPtr elem);
+xmlChar *	xmlValidNormalizeAttributeValue(xmlDocPtr doc,
+					 xmlNodePtr elem,
+					 const xmlChar *name,
+					 const xmlChar *value);
+int		xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlAttributePtr attr);
+int		xmlValidateAttributeValue(xmlAttributeType type,
+					 const xmlChar *value);
+int		xmlValidateNotationDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlNotationPtr nota);
+int		xmlValidateDtd		(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlDtdPtr dtd);
+int		xmlValidateDtdFinal	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateDocument	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateElement	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlNodePtr elem);
+int		xmlValidateOneElement	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlNodePtr elem);
+int		xmlValidateOneAttribute	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlNodePtr	elem,
+					 xmlAttrPtr attr,
+					 const xmlChar *value);
+int		xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateNotationUse	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 const xmlChar *notationName);
+int		xmlIsMixedElement	(xmlDocPtr doc,
+					 const xmlChar *name);
+xmlAttributePtr	xmlGetDtdAttrDesc	(xmlDtdPtr dtd,
+					 const xmlChar *elem,
+					 const xmlChar *name);
+xmlNotationPtr	xmlGetDtdNotationDesc	(xmlDtdPtr dtd,
+					 const xmlChar *name);
+xmlElementPtr	xmlGetDtdElementDesc	(xmlDtdPtr dtd,
+					 const xmlChar *name);
+
+int		xmlValidGetValidElements(xmlNode *prev,
+					 xmlNode *next,
+					 const xmlChar **list,
+					 int max);
+int		xmlValidGetPotentialChildren(xmlElementContent *ctree,
+					 const xmlChar **list,
+					 int *len,
+					 int max);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_VALID_H__ */
diff --git a/include/libxml/xinclude.h b/include/libxml/xinclude.h
new file mode 100644
index 0000000..eca4588
--- /dev/null
+++ b/include/libxml/xinclude.h
@@ -0,0 +1,26 @@
+/*
+ * xinclude.c : API to handle XInclude processing
+ *
+ * World Wide Web Consortium Working Draft 26 October 2000
+ * http://www.w3.org/TR/2000/WD-xinclude-20001026
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XINCLUDE_H__
+#define __XML_XINCLUDE_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int	xmlXIncludeProcess	(xmlDocPtr doc);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XINCLUDE_H__ */
diff --git a/include/libxml/xlink.h b/include/libxml/xlink.h
new file mode 100644
index 0000000..37a5415
--- /dev/null
+++ b/include/libxml/xlink.h
@@ -0,0 +1,182 @@
+/*
+ * xlink.h : interfaces to the hyperlinks detection module
+ *
+ * See Copyright for the status of this software.
+ *
+ * Related specification: http://www.w3.org/TR/xlink
+ *                        http://www.w3.org/HTML/
+ *     and XBase 
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XLINK_H__
+#define __XML_XLINK_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * Various defines for the various Link properties.
+ *
+ * NOTE: the link detection layer will try to resolve QName expansion
+ *       of namespaces, if "foo" is the prefix for "http://foo.com/"
+ *       then the link detection layer will expand role="foo:myrole"
+ *       to "http://foo.com/:myrole"
+ * NOTE: the link detection layer will expand URI-Refences found on
+ *       href attributes by using the base mechanism if found.
+ */
+typedef xmlChar *xlinkHRef;
+typedef xmlChar *xlinkRole;
+typedef xmlChar *xlinkTitle;
+
+typedef enum {
+    XLINK_TYPE_NONE = 0,
+    XLINK_TYPE_SIMPLE,
+    XLINK_TYPE_EXTENDED,
+    XLINK_TYPE_EXTENDED_SET
+} xlinkType;
+
+typedef enum {
+    XLINK_SHOW_NONE = 0,
+    XLINK_SHOW_NEW,
+    XLINK_SHOW_EMBED,
+    XLINK_SHOW_REPLACE
+} xlinkShow;
+
+typedef enum {
+    XLINK_ACTUATE_NONE = 0,
+    XLINK_ACTUATE_AUTO,
+    XLINK_ACTUATE_ONREQUEST
+} xlinkActuate;
+
+/**
+ * xlinkNodeDetectFunc:
+ * @ctx:  user data pointer
+ * @node:  the node to check
+ * 
+ * This is the prototype for the link detection routine
+ * It calls the default link detection callbacks upon link detection.
+ */
+typedef void
+(*xlinkNodeDetectFunc)	(void *ctx,
+		 	 xmlNodePtr node);
+
+/**
+ * The link detection module interract with the upper layers using
+ * a set of callback registered at parsing time.
+ */
+
+/**
+ * xlinkSimpleLinkFunk:
+ * @ctx:  user data pointer
+ * @node:  the node carrying the link
+ * @href:  the target of the link
+ * @role:  the role string
+ * @title:  the link title
+ *
+ * This is the prototype for a simple link detection callback.
+ */
+typedef void
+(*xlinkSimpleLinkFunk)	(void *ctx,
+			 xmlNodePtr node,
+			 const xlinkHRef href,
+			 const xlinkRole role,
+			 const xlinkTitle title);
+
+/**
+ * xlinkExtendedLinkFunk:
+ * @ctx:  user data pointer
+ * @node:  the node carrying the link
+ * @nbLocators: the number of locators detected on the link
+ * @hrefs:  pointer to the array of locator hrefs
+ * @roles:  pointer to the array of locator roles
+ * @nbArcs: the number of arcs detected on the link
+ * @from:  pointer to the array of source roles found on the arcs
+ * @to:  pointer to the array of target roles found on the arcs
+ * @show:  array of values for the show attributes found on the arcs
+ * @actuate:  array of values for the actuate attributes found on the arcs
+ * @nbTitles: the number of titles detected on the link
+ * @title:  array of titles detected on the link
+ * @langs:  array of xml:lang values for the titles
+ *
+ * This is the prototype for a extended link detection callback.
+ */
+typedef void
+(*xlinkExtendedLinkFunk)(void *ctx,
+			 xmlNodePtr node,
+			 int nbLocators,
+			 const xlinkHRef *hrefs,
+			 const xlinkRole *roles,
+			 int nbArcs,
+			 const xlinkRole *from,
+			 const xlinkRole *to,
+			 xlinkShow *show,
+			 xlinkActuate *actuate,
+			 int nbTitles,
+			 const xlinkTitle *titles,
+			 const xmlChar **langs);
+
+/**
+ * xlinkExtendedLinkSetFunk:
+ * @ctx:  user data pointer
+ * @node:  the node carrying the link
+ * @nbLocators: the number of locators detected on the link
+ * @hrefs:  pointer to the array of locator hrefs
+ * @roles:  pointer to the array of locator roles
+ * @nbTitles: the number of titles detected on the link
+ * @title:  array of titles detected on the link
+ * @langs:  array of xml:lang values for the titles
+ *
+ * This is the prototype for a extended link set detection callback.
+ */
+typedef void
+(*xlinkExtendedLinkSetFunk)	(void *ctx,
+				 xmlNodePtr node,
+				 int nbLocators,
+				 const xlinkHRef *hrefs,
+				 const xlinkRole *roles,
+				 int nbTitles,
+				 const xlinkTitle *titles,
+				 const xmlChar **langs);
+
+/**
+ * This is the structure containing a set of Links detection callbacks
+ *
+ * There is no default xlink callbacks, if one want to get link
+ * recognition activated, those call backs must be provided before parsing.
+ */
+typedef struct _xlinkHandler xlinkHandler;
+typedef xlinkHandler *xlinkHandlerPtr;
+struct _xlinkHandler {
+    xlinkSimpleLinkFunk simple;
+    xlinkExtendedLinkFunk extended;
+    xlinkExtendedLinkSetFunk set;
+};
+
+/**
+ * the default detection routine, can be overriden, they call the default
+ * detection callbacks. 
+ */
+
+xlinkNodeDetectFunc	xlinkGetDefaultDetect	(void);
+void			xlinkSetDefaultDetect	(xlinkNodeDetectFunc func);
+
+/**
+ * Routines to set/get the default handlers.
+ */
+xlinkHandlerPtr	xlinkGetDefaultHandler	(void);
+void		xlinkSetDefaultHandler	(xlinkHandlerPtr handler);
+
+/*
+ * Link detection module itself.
+ */
+xlinkType	 xlinkIsLink		(xmlDocPtr doc,
+					 xmlNodePtr node);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XLINK_H__ */
diff --git a/include/libxml/xmlIO.h b/include/libxml/xmlIO.h
new file mode 100644
index 0000000..ecff73b
--- /dev/null
+++ b/include/libxml/xmlIO.h
@@ -0,0 +1,178 @@
+/*
+ * xmlIO.h : interface for the I/O interfaces used by the parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 15 Nov 2000 ht - modified for VMS
+ */
+
+#ifndef __XML_IO_H__
+#define __XML_IO_H__
+
+#include <stdio.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/encoding.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Those are the functions and datatypes for the parser input
+ * I/O structures.
+ */
+
+typedef int (*xmlInputMatchCallback) (char const *filename);
+typedef void * (*xmlInputOpenCallback) (char const *filename);
+typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len);
+typedef void (*xmlInputCloseCallback) (void * context);
+
+typedef struct _xmlParserInputBuffer xmlParserInputBuffer;
+typedef xmlParserInputBuffer *xmlParserInputBufferPtr;
+struct _xmlParserInputBuffer {
+    void*                  context;
+    xmlInputReadCallback   readcallback;
+    xmlInputCloseCallback  closecallback;
+    
+    xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */
+    
+    xmlBufferPtr buffer;    /* Local buffer encoded in UTF-8 */
+    xmlBufferPtr raw;       /* if encoder != NULL buffer for raw input */
+};
+
+
+/*
+ * Those are the functions and datatypes for the library output
+ * I/O structures.
+ */
+
+typedef int (*xmlOutputMatchCallback) (char const *filename);
+typedef void * (*xmlOutputOpenCallback) (char const *filename);
+typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer,
+                                       int len);
+typedef void (*xmlOutputCloseCallback) (void * context);
+
+typedef struct _xmlOutputBuffer xmlOutputBuffer;
+typedef xmlOutputBuffer *xmlOutputBufferPtr;
+struct _xmlOutputBuffer {
+    void*                   context;
+    xmlOutputWriteCallback  writecallback;
+    xmlOutputCloseCallback  closecallback;
+    
+    xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */
+    
+    xmlBufferPtr buffer;    /* Local buffer encoded in UTF-8 or ISOLatin */
+    xmlBufferPtr conv;      /* if encoder != NULL buffer for output */
+    int written;            /* total number of byte written */
+};
+
+/*
+ * Interfaces for input
+ */
+
+void	xmlRegisterDefaultInputCallbacks	(void);
+xmlParserInputBufferPtr
+	xmlAllocParserInputBuffer		(xmlCharEncoding enc);
+
+#ifdef VMS
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFname		(const char *URI,
+                                                 xmlCharEncoding enc);
+#define xmlParserInputBufferCreateFilename xmlParserInputBufferCreateFname
+#else
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFilename	(const char *URI,
+                                                 xmlCharEncoding enc);
+#endif
+
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFile		(FILE *file,
+                                                 xmlCharEncoding enc);
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFd		(int fd,
+	                                         xmlCharEncoding enc);
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateMem		(const char *mem, int size,
+	                                         xmlCharEncoding enc);
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateIO		(xmlInputReadCallback   ioread,
+						 xmlInputCloseCallback  ioclose,
+						 void *ioctx,
+	                                         xmlCharEncoding enc);
+int	xmlParserInputBufferRead		(xmlParserInputBufferPtr in,
+						 int len);
+int	xmlParserInputBufferGrow		(xmlParserInputBufferPtr in,
+						 int len);
+int	xmlParserInputBufferPush		(xmlParserInputBufferPtr in,
+						 int len,
+						 const char *buf);
+void	xmlFreeParserInputBuffer		(xmlParserInputBufferPtr in);
+char *	xmlParserGetDirectory			(const char *filename);
+
+int     xmlRegisterInputCallbacks		(xmlInputMatchCallback match,
+						 xmlInputOpenCallback open,
+						 xmlInputReadCallback read,
+						 xmlInputCloseCallback close);
+/*
+ * Interfaces for output
+ */
+void	xmlRegisterDefaultOutputCallbacks(void);
+xmlOutputBufferPtr
+	xmlAllocOutputBuffer		(xmlCharEncodingHandlerPtr encoder);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateFilename	(const char *URI,
+					 xmlCharEncodingHandlerPtr encoder,
+					 int compression);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateFile	(FILE *file,
+					 xmlCharEncodingHandlerPtr encoder);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateFd		(int fd,
+					 xmlCharEncodingHandlerPtr encoder);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateIO		(xmlOutputWriteCallback   iowrite,
+					 xmlOutputCloseCallback  ioclose,
+					 void *ioctx,
+					 xmlCharEncodingHandlerPtr encoder);
+
+int	xmlOutputBufferWrite		(xmlOutputBufferPtr out,
+					 int len,
+					 const char *buf);
+int	xmlOutputBufferWriteString	(xmlOutputBufferPtr out,
+					 const char *str);
+
+int	xmlOutputBufferFlush		(xmlOutputBufferPtr out);
+int	xmlOutputBufferClose		(xmlOutputBufferPtr out);
+
+int     xmlRegisterOutputCallbacks	(xmlOutputMatchCallback match,
+					 xmlOutputOpenCallback open,
+					 xmlOutputWriteCallback write,
+					 xmlOutputCloseCallback close);
+
+/*
+ * This save function are part of tree.h and HTMLtree.h actually
+ */
+int		xmlSaveFileTo		(xmlOutputBuffer *buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+void		xmlNodeDumpOutput	(xmlOutputBufferPtr buf,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur,
+					 int level,
+					 int format,
+					 const char *encoding);
+void		htmlDocContentDumpOutput(xmlOutputBufferPtr buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_IO_H__ */
diff --git a/include/libxml/xmlerror.h b/include/libxml/xmlerror.h
new file mode 100644
index 0000000..53c5751
--- /dev/null
+++ b/include/libxml/xmlerror.h
@@ -0,0 +1,180 @@
+#ifndef __XML_ERROR_H__
+#define __XML_ERROR_H__
+
+#include <libxml/parser.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    XML_ERR_OK = 0,
+    XML_ERR_INTERNAL_ERROR,
+    XML_ERR_NO_MEMORY,
+    
+    XML_ERR_DOCUMENT_START, /* 3 */
+    XML_ERR_DOCUMENT_EMPTY,
+    XML_ERR_DOCUMENT_END,
+
+    XML_ERR_INVALID_HEX_CHARREF, /* 6 */
+    XML_ERR_INVALID_DEC_CHARREF,
+    XML_ERR_INVALID_CHARREF,
+    XML_ERR_INVALID_CHAR,
+
+    XML_ERR_CHARREF_AT_EOF, /* 10 */
+    XML_ERR_CHARREF_IN_PROLOG,
+    XML_ERR_CHARREF_IN_EPILOG,
+    XML_ERR_CHARREF_IN_DTD,
+    XML_ERR_ENTITYREF_AT_EOF,
+    XML_ERR_ENTITYREF_IN_PROLOG,
+    XML_ERR_ENTITYREF_IN_EPILOG,
+    XML_ERR_ENTITYREF_IN_DTD,
+    XML_ERR_PEREF_AT_EOF,
+    XML_ERR_PEREF_IN_PROLOG,
+    XML_ERR_PEREF_IN_EPILOG,
+    XML_ERR_PEREF_IN_INT_SUBSET,
+
+    XML_ERR_ENTITYREF_NO_NAME, /* 22 */
+    XML_ERR_ENTITYREF_SEMICOL_MISSING,
+
+    XML_ERR_PEREF_NO_NAME, /* 24 */
+    XML_ERR_PEREF_SEMICOL_MISSING,
+
+    XML_ERR_UNDECLARED_ENTITY, /* 26 */
+    XML_WAR_UNDECLARED_ENTITY,
+    XML_ERR_UNPARSED_ENTITY,
+    XML_ERR_ENTITY_IS_EXTERNAL,
+    XML_ERR_ENTITY_IS_PARAMETER,
+
+    XML_ERR_UNKNOWN_ENCODING, /* 31 */
+    XML_ERR_UNSUPPORTED_ENCODING,
+
+    XML_ERR_STRING_NOT_STARTED, /* 33 */
+    XML_ERR_STRING_NOT_CLOSED,
+    XML_ERR_NS_DECL_ERROR,
+
+    XML_ERR_ENTITY_NOT_STARTED, /* 36 */
+    XML_ERR_ENTITY_NOT_FINISHED,
+    
+    XML_ERR_LT_IN_ATTRIBUTE, /* 38 */
+    XML_ERR_ATTRIBUTE_NOT_STARTED,
+    XML_ERR_ATTRIBUTE_NOT_FINISHED,
+    XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
+    XML_ERR_ATTRIBUTE_REDEFINED,
+
+    XML_ERR_LITERAL_NOT_STARTED, /* 43 */
+    XML_ERR_LITERAL_NOT_FINISHED,
+    
+    XML_ERR_COMMENT_NOT_FINISHED, /* 45 */
+
+    XML_ERR_PI_NOT_STARTED, /* 47 */
+    XML_ERR_PI_NOT_FINISHED,
+
+    XML_ERR_NOTATION_NOT_STARTED, /* 49 */
+    XML_ERR_NOTATION_NOT_FINISHED,
+
+    XML_ERR_ATTLIST_NOT_STARTED, /* 51 */
+    XML_ERR_ATTLIST_NOT_FINISHED,
+
+    XML_ERR_MIXED_NOT_STARTED, /* 53 */
+    XML_ERR_MIXED_NOT_FINISHED,
+
+    XML_ERR_ELEMCONTENT_NOT_STARTED, /* 55 */
+    XML_ERR_ELEMCONTENT_NOT_FINISHED,
+
+    XML_ERR_XMLDECL_NOT_STARTED, /* 57 */
+    XML_ERR_XMLDECL_NOT_FINISHED,
+
+    XML_ERR_CONDSEC_NOT_STARTED, /* 59 */
+    XML_ERR_CONDSEC_NOT_FINISHED,
+
+    XML_ERR_EXT_SUBSET_NOT_FINISHED, /* 61 */
+
+    XML_ERR_DOCTYPE_NOT_FINISHED, /* 62 */
+
+    XML_ERR_MISPLACED_CDATA_END, /* 63 */
+    XML_ERR_CDATA_NOT_FINISHED,
+
+    XML_ERR_RESERVED_XML_NAME, /* 65 */
+
+    XML_ERR_SPACE_REQUIRED, /* 66 */
+    XML_ERR_SEPARATOR_REQUIRED,
+    XML_ERR_NMTOKEN_REQUIRED,
+    XML_ERR_NAME_REQUIRED,
+    XML_ERR_PCDATA_REQUIRED,
+    XML_ERR_URI_REQUIRED,
+    XML_ERR_PUBID_REQUIRED,
+    XML_ERR_LT_REQUIRED,
+    XML_ERR_GT_REQUIRED,
+    XML_ERR_LTSLASH_REQUIRED,
+    XML_ERR_EQUAL_REQUIRED,
+
+    XML_ERR_TAG_NAME_MISMATCH, /* 77 */
+    XML_ERR_TAG_NOT_FINISED,
+
+    XML_ERR_STANDALONE_VALUE, /* 79 */
+
+    XML_ERR_ENCODING_NAME, /* 80 */
+
+    XML_ERR_HYPHEN_IN_COMMENT, /* 81 */
+
+    XML_ERR_INVALID_ENCODING, /* 82 */
+
+    XML_ERR_EXT_ENTITY_STANDALONE, /* 83 */
+
+    XML_ERR_CONDSEC_INVALID, /* 84 */
+
+    XML_ERR_VALUE_REQUIRED, /* 85 */
+
+    XML_ERR_NOT_WELL_BALANCED, /* 86 */
+    XML_ERR_EXTRA_CONTENT, /* 87 */
+    XML_ERR_ENTITY_CHAR_ERROR, /* 88 */
+    XML_ERR_ENTITY_PE_INTERNAL, /* 88 */
+    XML_ERR_ENTITY_LOOP, /* 89 */
+    XML_ERR_ENTITY_BOUNDARY, /* 90 */
+    XML_ERR_INVALID_URI, /* 91 */
+    XML_ERR_URI_FRAGMENT /* 92 */
+}xmlParserErrors;
+
+/*
+ * Signature of the function to use when there is an error and
+ * no parsing or validity context available 
+ */
+typedef void (*xmlGenericErrorFunc) (void *ctx, const char *msg, ...);
+
+/*
+ * Those are the default error function and associated context to use
+ * when when there is an error and no parsing or validity context available
+ */
+
+LIBXML_DLL_IMPORT extern xmlGenericErrorFunc xmlGenericError;
+LIBXML_DLL_IMPORT extern void *xmlGenericErrorContext;
+
+/*
+ * Use the following function to reset the two previous global variables.
+ */
+void	xmlSetGenericErrorFunc	(void *ctx,
+				 xmlGenericErrorFunc handler);
+
+/*
+ * Default message routines used by SAX and Valid context for error
+ * and warning reporting
+ */
+void	xmlParserError		(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserWarning	(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserValidityError	(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserValidityWarning(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserPrintFileInfo	(xmlParserInputPtr input);
+void	xmlParserPrintFileContext(xmlParserInputPtr input);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_ERROR_H__ */
diff --git a/include/libxml/xmlmemory.h b/include/libxml/xmlmemory.h
new file mode 100644
index 0000000..1e533d1
--- /dev/null
+++ b/include/libxml/xmlmemory.h
@@ -0,0 +1,91 @@
+/*
+ * xmlmemory.h: interface for the memory allocation debug.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifndef _DEBUG_MEMORY_ALLOC_
+#define _DEBUG_MEMORY_ALLOC_
+
+#include <stdio.h>
+#include <libxml/xmlversion.h>
+
+/*
+ * DEBUG_MEMORY_LOCATION should be activated only done when debugging 
+ * libxml.
+ */
+/* #define DEBUG_MEMORY_LOCATION */
+
+#ifdef DEBUG
+#ifndef DEBUG_MEMORY
+#define DEBUG_MEMORY
+#endif
+#endif
+
+#ifdef DEBUG_MEMORY_LOCATION
+#define MEM_LIST /* keep a list of all the allocated memory blocks */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The XML memory wrapper support 4 basic overloadable functions
+ */
+typedef void (*xmlFreeFunc)(void *);
+typedef void *(*xmlMallocFunc)(int);
+typedef void *(*xmlReallocFunc)(void *, int);
+typedef char *(*xmlStrdupFunc)(const char *);
+
+/*
+ * The 4 interfaces used for all memory handling within libxml
+ */
+LIBXML_DLL_IMPORT extern xmlFreeFunc xmlFree;
+LIBXML_DLL_IMPORT extern xmlMallocFunc xmlMalloc;
+LIBXML_DLL_IMPORT extern xmlReallocFunc xmlRealloc;
+LIBXML_DLL_IMPORT extern xmlStrdupFunc xmlMemStrdup;
+
+/*
+ * The way to overload the existing functions
+ */
+int     xmlMemSetup	(xmlFreeFunc freeFunc,
+			 xmlMallocFunc mallocFunc,
+			 xmlReallocFunc reallocFunc,
+			 xmlStrdupFunc strdupFunc);
+int     xmlMemGet	(xmlFreeFunc *freeFunc,
+			 xmlMallocFunc *mallocFunc,
+			 xmlReallocFunc *reallocFunc,
+			 xmlStrdupFunc *strdupFunc);
+
+/*
+ * Initialization of the memory layer
+ */
+int	xmlInitMemory	(void);
+
+/*
+ * Those are specific to the XML debug memory wrapper
+ */
+int	xmlMemUsed	(void);
+void	xmlMemDisplay	(FILE *fp);
+void	xmlMemShow	(FILE *fp, int nr);
+void	xmlMemoryDump	(void);
+int	xmlInitMemory	(void);
+
+#ifdef DEBUG_MEMORY_LOCATION
+#define xmlMalloc(x) xmlMallocLoc((x), __FILE__, __LINE__)
+#define xmlRealloc(p, x) xmlReallocLoc((p), (x), __FILE__, __LINE__)
+#define xmlMemStrdup(x) xmlMemStrdupLoc((x), __FILE__, __LINE__)
+
+void *	xmlMallocLoc(int size, const char *file, int line);
+void *	xmlReallocLoc(void *ptr,int size, const char *file, int line);
+char *	xmlMemStrdupLoc(const char *str, const char *file, int line);
+#endif /* DEBUG_MEMORY_LOCATION */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* _DEBUG_MEMORY_ALLOC_ */
+
diff --git a/include/libxml/xmlversion.h.in b/include/libxml/xmlversion.h.in
new file mode 100644
index 0000000..71ab184
--- /dev/null
+++ b/include/libxml/xmlversion.h.in
@@ -0,0 +1,129 @@
+/*
+ * xmlversion.h : compile-time version informations for the XML parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_VERSION_H__
+#define __XML_VERSION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * use those to be sure nothing nasty will happen if
+ * your library and includes mismatch
+ */
+extern void xmlCheckVersion(int version);
+#define LIBXML_DOTTED_VERSION "@VERSION@"
+#define LIBXML_VERSION @LIBXML_VERSION_NUMBER@
+#define LIBXML_VERSION_STRING "@LIBXML_VERSION_NUMBER@"
+#define LIBXML_TEST_VERSION xmlCheckVersion(@LIBXML_VERSION_NUMBER@);
+
+/*
+ * Whether the FTP support is configured in
+ */
+#if @WITH_FTP@
+#define LIBXML_FTP_ENABLED
+#else
+#define LIBXML_FTP_DISABLED
+#endif
+
+/*
+ * Whether the HTTP support is configured in
+ */
+#if @WITH_HTTP@
+#define LIBXML_HTTP_ENABLED
+#else
+#define LIBXML_HTTP_DISABLED
+#endif
+
+/*
+ * Whether the HTML support is configured in
+ */
+#if @WITH_HTML@
+#define LIBXML_HTML_ENABLED
+#else
+#define LIBXML_HTML_DISABLED
+#endif
+
+/*
+ * Whether the Docbook support is configured in
+#if @WITH_SGML@
+#define LIBXML_SGML_ENABLED
+#else
+#define LIBXML_SGML_DISABLED
+#endif
+ */
+
+/*
+ * Whether XPath is configured in
+ */
+#if @WITH_XPATH@
+#define LIBXML_XPATH_ENABLED
+#else
+#define LIBXML_XPATH_DISABLED
+#endif
+
+/*
+ * Whether XPointer is configured in
+ */
+#if @WITH_XPTR@
+#define LIBXML_XPTR_ENABLED
+#else
+#define LIBXML_XPTR_DISABLED
+#endif
+
+/*
+ * Whether XInclude is configured in
+ */
+#if @WITH_XINCLUDE@
+#define LIBXML_XINCLUDE_ENABLED
+#else
+#define LIBXML_XINCLUDE_DISABLED
+#endif
+
+/*
+ * Whether iconv support is available
+ */
+#ifndef WIN32
+#if @WITH_ICONV@
+#define LIBXML_ICONV_ENABLED
+#else
+#define LIBXML_ICONV_DISABLED
+#endif
+#endif
+
+/*
+ * Whether Debugging module is configured in
+ */
+#if @WITH_DEBUG@
+#define LIBXML_DEBUG_ENABLED
+#else
+#define LIBXML_DEBUG_DISABLED
+#endif
+
+/*
+ * Whether the memory debugging is configured in
+ */
+#if @WITH_MEM_DEBUG@
+#define DEBUG_MEMORY_LOCATION
+#endif
+
+#ifndef LIBXML_DLL_IMPORT
+#if defined(WIN32) && !defined(STATIC)
+#define LIBXML_DLL_IMPORT __declspec(dllimport)
+#else
+#define LIBXML_DLL_IMPORT
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
+
diff --git a/include/libxml/xpath.h b/include/libxml/xpath.h
new file mode 100644
index 0000000..f8fd861
--- /dev/null
+++ b/include/libxml/xpath.h
@@ -0,0 +1,278 @@
+/*
+ * xpath.c: interface for XML Path Language implementation
+ *
+ * Reference: W3C Working Draft 5 July 1999
+ *            http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
+ *
+ * See COPYRIGHT for the status of this software
+ *
+ * Author: Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XPATH_H__
+#define __XML_XPATH_H__
+
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _xmlXPathContext xmlXPathContext;
+typedef xmlXPathContext *xmlXPathContextPtr;
+typedef struct _xmlXPathParserContext xmlXPathParserContext;
+typedef xmlXPathParserContext *xmlXPathParserContextPtr;
+
+/**
+ * The set of XPath error codes
+ */
+
+typedef enum {
+    XPATH_EXPRESSION_OK = 0,
+    XPATH_NUMBER_ERROR,
+    XPATH_UNFINISHED_LITERAL_ERROR,
+    XPATH_START_LITERAL_ERROR,
+    XPATH_VARIABLE_REF_ERROR,
+    XPATH_UNDEF_VARIABLE_ERROR,
+    XPATH_INVALID_PREDICATE_ERROR,
+    XPATH_EXPR_ERROR,
+    XPATH_UNCLOSED_ERROR,
+    XPATH_UNKNOWN_FUNC_ERROR,
+    XPATH_INVALID_OPERAND,
+    XPATH_INVALID_TYPE,
+    XPATH_INVALID_ARITY,
+    XPATH_INVALID_CTXT_SIZE,
+    XPATH_INVALID_CTXT_POSITION,
+    XPATH_MEMORY_ERROR,
+    XPTR_SYNTAX_ERROR,
+    XPTR_RESOURCE_ERROR,
+    XPTR_SUB_RESOURCE_ERROR,
+    XPATH_UNDEF_PREFIX_ERROR
+} xmlXPathError;
+
+/*
+ * A node-set (an unordered collection of nodes without duplicates) 
+ */
+typedef struct _xmlNodeSet xmlNodeSet;
+typedef xmlNodeSet *xmlNodeSetPtr;
+struct _xmlNodeSet {
+    int nodeNr;			/* number of nodes in the set */
+    int nodeMax;		/* size of the array as allocated */
+    xmlNodePtr *nodeTab;	/* array of nodes in no particular order */
+};
+
+/*
+ * An expression is evaluated to yield an object, which
+ * has one of the following four basic types:
+ *   - node-set
+ *   - boolean
+ *   - number
+ *   - string
+ *
+ * @@ XPointer will add more types !
+ */
+
+typedef enum {
+    XPATH_UNDEFINED = 0,
+    XPATH_NODESET = 1,
+    XPATH_BOOLEAN = 2,
+    XPATH_NUMBER = 3,
+    XPATH_STRING = 4,
+    XPATH_POINT = 5,
+    XPATH_RANGE = 6,
+    XPATH_LOCATIONSET = 7,
+    XPATH_USERS = 8,
+    XPATH_XSLT_TREE = 9  /* An XSLT value tree, non modifiable */
+} xmlXPathObjectType;
+
+typedef struct _xmlXPathObject xmlXPathObject;
+typedef xmlXPathObject *xmlXPathObjectPtr;
+struct _xmlXPathObject {
+    xmlXPathObjectType type;
+    xmlNodeSetPtr nodesetval;
+    int boolval;
+    double floatval;
+    xmlChar *stringval;
+    void *user;
+    int index;
+    void *user2;
+    int index2;
+};
+
+/*
+ * A conversion function is associated to a type and used to cast
+ * the new type to primitive values.
+ */
+typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type);
+
+/*
+ * Extra type: a name and a conversion function.
+ */
+
+typedef struct _xmlXPathType xmlXPathType;
+typedef xmlXPathType *xmlXPathTypePtr;
+struct _xmlXPathType {
+    const xmlChar         *name;		/* the type name */
+    xmlXPathConvertFunc func;		/* the conversion function */
+};
+
+/*
+ * Extra variable: a name and a value.
+ */
+
+typedef struct _xmlXPathVariable xmlXPathVariable;
+typedef xmlXPathVariable *xmlXPathVariablePtr;
+struct _xmlXPathVariable {
+    const xmlChar       *name;		/* the variable name */
+    xmlXPathObjectPtr value;		/* the value */
+};
+
+/*
+ * an evaluation function, the parameters are on the context stack
+ */
+
+typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, int nargs);
+
+/*
+ * Extra function: a name and a evaluation function.
+ */
+
+typedef struct _xmlXPathFunct xmlXPathFunct;
+typedef xmlXPathFunct *xmlXPathFuncPtr;
+struct _xmlXPathFunct {
+    const xmlChar      *name;		/* the function name */
+    xmlXPathEvalFunc func;		/* the evaluation function */
+};
+
+/*
+ * An axis traversal function. To traverse an axis, the engine calls
+ * the first time with cur == NULL and repeat until the function returns
+ * NULL indicating the end of the axis traversal.
+ */
+
+typedef xmlXPathObjectPtr (*xmlXPathAxisFunc)	(xmlXPathParserContextPtr ctxt,
+						 xmlXPathObjectPtr cur);
+
+/*
+ * Extra axis: a name and an axis function.
+ */
+
+typedef struct _xmlXPathAxis xmlXPathAxis;
+typedef xmlXPathAxis *xmlXPathAxisPtr;
+struct _xmlXPathAxis {
+    const xmlChar      *name;		/* the axis name */
+    xmlXPathAxisFunc func;		/* the search function */
+};
+
+/* 
+ * Expression evaluation occurs with respect to a context.
+ * he context consists of:
+ *    - a node (the context node) 
+ *    - a node list (the context node list) 
+ *    - a set of variable bindings 
+ *    - a function library 
+ *    - the set of namespace declarations in scope for the expression 
+ * Following the switch to hash tables, this need to be trimmed up at
+ * the next binary incompatible release.
+ */
+
+struct _xmlXPathContext {
+    xmlDocPtr doc;			/* The current document */
+    xmlNodePtr node;			/* The current node */
+
+    int nb_variables_unused;		/* unused (hash table) */
+    int max_variables_unused;		/* unused (hash table) */
+    xmlHashTablePtr varHash;		/* Hash table of defined variables */
+
+    int nb_types;			/* number of defined types */
+    int max_types;			/* max number of types */
+    xmlXPathTypePtr types;		/* Array of defined types */
+
+    int nb_funcs_unused;		/* unused (hash table) */
+    int max_funcs_unused;		/* unused (hash table) */
+    xmlHashTablePtr funcHash;		/* Hash table of defined funcs */
+
+    int nb_axis;			/* number of defined axis */
+    int max_axis;			/* max number of axis */
+    xmlXPathAxisPtr axis;		/* Array of defined axis */
+
+    /* the namespace nodes of the context node */
+    xmlNsPtr *namespaces;		/* Array of namespaces */
+    int nsNr;				/* number of namespace in scope */
+    void *user;				/* function to free */
+
+    /* extra variables */
+    int contextSize;			/* the context size */
+    int proximityPosition;		/* the proximity position */
+
+    /* extra stuff for XPointer */
+    int xptr;				/* it this an XPointer context */
+    xmlNodePtr here;			/* for here() */
+    xmlNodePtr origin;			/* for origin() */
+
+    /* the set of namespace declarations in scope for the expression */
+    xmlHashTablePtr nsHash;		/* The namespaces hash table */
+    void *varLookupFunc;		/* variable lookup func */
+    void *varLookupData;		/* variable lookup data */
+
+    /* Possibility to link in an extra item */
+    void *extra;                        /* needed for XSLT */
+};
+
+/*
+ * An XPath parser context, it contains pure parsing informations,
+ * an xmlXPathContext, and the stack of objects.
+ */
+struct _xmlXPathParserContext {
+    const xmlChar *cur;			/* the current char being parsed */
+    const xmlChar *base;			/* the full expression */
+
+    int error;				/* error code */
+
+    xmlXPathContextPtr  context;	/* the evaluation context */
+    xmlXPathObjectPtr     value;	/* the current value */
+    int                 valueNr;	/* number of values stacked */
+    int                valueMax;	/* max number of values stacked */
+    xmlXPathObjectPtr *valueTab;	/* stack of values */
+};
+
+/*
+ * An XPath function
+ * The arguments (if any) are popped out of the context stack
+ * and the result is pushed on the stack.
+ */
+
+typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs);
+
+/************************************************************************
+ *									*
+ *			Public API					*
+ *									*
+ ************************************************************************/
+
+/**
+ * Evaluation functions.
+ */
+void		   xmlXPathInit			(void);
+xmlXPathContextPtr xmlXPathNewContext		(xmlDocPtr doc);
+void		   xmlXPathFreeContext		(xmlXPathContextPtr ctxt);
+xmlXPathObjectPtr  xmlXPathEval			(const xmlChar *str,
+						 xmlXPathContextPtr ctxt);
+xmlXPathObjectPtr  xmlXPathEvalXPtrExpr		(const xmlChar *str,
+						 xmlXPathContextPtr ctxt);
+void		   xmlXPathFreeObject		(xmlXPathObjectPtr obj);
+xmlXPathObjectPtr  xmlXPathEvalExpression	(const xmlChar *str,
+						 xmlXPathContextPtr ctxt);
+xmlNodeSetPtr	   xmlXPathNodeSetCreate	(xmlNodePtr val);
+void		   xmlXPathFreeNodeSetList	(xmlXPathObjectPtr obj);
+void		   xmlXPathFreeNodeSet		(xmlNodeSetPtr obj);
+xmlXPathObjectPtr  xmlXPathObjectCopy		(xmlXPathObjectPtr val);
+int		   xmlXPathCmpNodes		(xmlNodePtr node1,
+						 xmlNodePtr node2);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ! __XML_XPATH_H__ */
diff --git a/include/libxml/xpathInternals.h b/include/libxml/xpathInternals.h
new file mode 100644
index 0000000..51f6ad5
--- /dev/null
+++ b/include/libxml/xpathInternals.h
@@ -0,0 +1,236 @@
+/*
+ * xpath.c: internal interfaces for XML Path Language implementation
+ *          used to build new modules on top of XPath
+ *
+ * See COPYRIGHT for the status of this software
+ *
+ * Author: Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XPATH_INTERNALS_H__
+#define __XML_XPATH_INTERNALS_H__
+
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/************************************************************************
+ *									*
+ *			Helpers						*
+ *									*
+ ************************************************************************/
+
+#define CHECK_ERROR							\
+    if (ctxt->error != XPATH_EXPRESSION_OK) return
+
+#define CHECK_ERROR0							\
+    if (ctxt->error != XPATH_EXPRESSION_OK) return(0)
+
+#define XP_ERROR(X)							\
+    { xmlXPatherror(ctxt, __FILE__, __LINE__, X);			\
+      ctxt->error = (X); return; }
+
+#define XP_ERROR0(X)							\
+    { xmlXPatherror(ctxt, __FILE__, __LINE__, X);			\
+      ctxt->error = (X); return(0); }
+
+#define CHECK_TYPE(typeval)						\
+    if ((ctxt->value == NULL) || (ctxt->value->type != typeval))	\
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+#define CHECK_ARITY(x)							\
+    if (nargs != (x))							\
+        XP_ERROR(XPATH_INVALID_ARITY);
+
+#define CAST_TO_STRING							\
+    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING))	\
+        xmlXPathStringFunction(ctxt, 1);
+
+#define CAST_TO_NUMBER							\
+    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER))	\
+        xmlXPathNumberFunction(ctxt, 1);
+
+#define CAST_TO_BOOLEAN							\
+    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN))	\
+        xmlXPathBooleanFunction(ctxt, 1);
+
+/*
+ * Varibale Lookup forwarding
+ */
+typedef xmlXPathObjectPtr
+	(*xmlXPathVariableLookupFunc)	(void *ctxt,
+					 const xmlChar *name,
+					 const xmlChar *ns_uri);
+
+void	xmlXPathRegisterVariableLookup	(xmlXPathContextPtr ctxt,
+					 xmlXPathVariableLookupFunc f,
+					 void *varCtxt);
+
+/*
+ * Error reporting
+ */
+void		xmlXPatherror	(xmlXPathParserContextPtr ctxt,
+				 const char *file,
+				 int line,
+				 int no);
+
+void		xmlXPathDebugDumpObject	(FILE *output,
+					 xmlXPathObjectPtr cur,
+					 int depth);
+
+/**
+ * Extending a context
+ */
+
+int		   xmlXPathRegisterNs		(xmlXPathContextPtr ctxt,
+						 const xmlChar *prefix,
+						 const xmlChar *ns_uri);
+const xmlChar *	   xmlXPathNsLookup		(xmlXPathContextPtr ctxt,
+						 const xmlChar *ns_uri);
+void		   xmlXPathRegisteredNsCleanup	(xmlXPathContextPtr ctxt);
+
+int		   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 xmlXPathFunction f);
+int		   xmlXPathRegisterFuncNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri,
+						 xmlXPathFunction f);
+int		   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 xmlXPathObjectPtr value);
+int		   xmlXPathRegisterVariableNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri,
+						 xmlXPathObjectPtr value);
+xmlXPathFunction   xmlXPathFunctionLookup	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name);
+xmlXPathFunction   xmlXPathFunctionLookupNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
+void		   xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt);
+xmlXPathObjectPtr  xmlXPathVariableLookup	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name);
+xmlXPathObjectPtr  xmlXPathVariableLookupNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
+void		   xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt);
+
+/**
+ * Utilities to extend XPath
+ */
+xmlXPathParserContextPtr
+		  xmlXPathNewParserContext	(const xmlChar *str,
+			  			 xmlXPathContextPtr ctxt);
+void		  xmlXPathFreeParserContext	(xmlXPathParserContextPtr ctxt);
+
+/* TODO: remap to xmlXPathValuePop and Push */
+xmlXPathObjectPtr valuePop			(xmlXPathParserContextPtr ctxt);
+int		  valuePush			(xmlXPathParserContextPtr ctxt,
+					 	xmlXPathObjectPtr value);
+
+xmlXPathObjectPtr xmlXPathNewString		(const xmlChar *val);
+xmlXPathObjectPtr xmlXPathNewCString		(const char *val);
+xmlXPathObjectPtr xmlXPathNewFloat		(double val);
+xmlXPathObjectPtr xmlXPathNewBoolean		(int val);
+xmlXPathObjectPtr xmlXPathNewNodeSet		(xmlNodePtr val);
+xmlXPathObjectPtr xmlXPathNewValueTree		(xmlNodePtr val);
+void		  xmlXPathNodeSetAdd		(xmlNodeSetPtr cur,
+						 xmlNodePtr val);
+
+
+void		  xmlXPathIdFunction		(xmlXPathParserContextPtr ctxt,
+					 	int nargs);
+void		  xmlXPathRoot			(xmlXPathParserContextPtr ctxt);
+void		  xmlXPathEvalExpr		(xmlXPathParserContextPtr ctxt);
+xmlChar *	  xmlXPathParseName		(xmlXPathParserContextPtr ctxt);
+xmlChar *	  xmlXPathParseNCName		(xmlXPathParserContextPtr ctxt);
+
+/*
+ * Debug
+ */
+#ifdef LIBXML_DEBUG_ENABLED
+double xmlXPathStringEvalNumber(const xmlChar *str);
+void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
+#endif
+/*
+ * Existing functions
+ */
+
+int xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
+                                    xmlXPathObjectPtr res);
+void xmlXPathInit(void);
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt);
+xmlNodeSetPtr xmlXPathNodeSetCreate(xmlNodePtr val);
+void xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val);
+xmlNodeSetPtr xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2);
+void xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val);
+void xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val);
+void xmlXPathFreeNodeSet(xmlNodeSetPtr obj);
+xmlXPathObjectPtr xmlXPathNewNodeSet(xmlNodePtr val);
+xmlXPathObjectPtr xmlXPathNewNodeSetList(xmlNodeSetPtr val);
+xmlXPathObjectPtr xmlXPathWrapNodeSet(xmlNodeSetPtr val);
+void xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj);
+
+
+xmlXPathObjectPtr xmlXPathNewFloat(double val);
+xmlXPathObjectPtr xmlXPathNewBoolean(int val);
+xmlXPathObjectPtr xmlXPathNewString(const xmlChar *val);
+xmlXPathObjectPtr xmlXPathNewCString(const char *val);
+void xmlXPathFreeObject(xmlXPathObjectPtr obj);
+xmlXPathContextPtr xmlXPathNewContext(xmlDocPtr doc);
+void xmlXPathFreeContext(xmlXPathContextPtr ctxt);
+
+int xmlXPathEqualValues(xmlXPathParserContextPtr ctxt);
+int xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict);
+void xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt);
+void xmlXPathAddValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathSubValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathMultValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathDivValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathModValues(xmlXPathParserContextPtr ctxt);
+
+
+/*
+ * Some of the axis navigation routines
+ */
+xmlNodePtr xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+xmlNodePtr xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+xmlNodePtr xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+/*
+ * The official core of XPath functions
+ */
+void xmlXPathRoot(xmlXPathParserContextPtr ctxt);
+void xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs);
+#ifdef __cplusplus
+}
+#endif
+#endif /* ! __XML_XPATH_INTERNALS_H__ */
diff --git a/include/libxml/xpointer.h b/include/libxml/xpointer.h
new file mode 100644
index 0000000..786fb5a
--- /dev/null
+++ b/include/libxml/xpointer.h
@@ -0,0 +1,57 @@
+/*
+ * xpointer.h : API to handle XML Pointers
+ *
+ * World Wide Web Consortium Working Draft 03-March-1998 
+ * http://www.w3.org/TR/1998/WD-xptr-19980303
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XPTR_H__
+#define __XML_XPTR_H__
+
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A Location Set
+ */
+typedef struct _xmlLocationSet xmlLocationSet;
+typedef xmlLocationSet *xmlLocationSetPtr;
+struct _xmlLocationSet {
+    int locNr;		      /* number of locations in the set */
+    int locMax;		      /* size of the array as allocated */
+    xmlXPathObjectPtr *locTab;/* array of locations */
+};
+
+/*
+ * Handling of location sets
+ */
+
+void			xmlXPtrFreeLocationSet	(xmlLocationSetPtr obj);
+xmlLocationSetPtr	xmlXPtrLocationSetMerge	(xmlLocationSetPtr val1,
+						 xmlLocationSetPtr val2);
+
+/*
+ * Functions
+ */
+xmlXPathContextPtr	xmlXPtrNewContext	(xmlDocPtr doc,
+						 xmlNodePtr here,
+						 xmlNodePtr origin);
+xmlXPathObjectPtr	xmlXPtrEval		(const xmlChar *str,
+						 xmlXPathContextPtr ctx);
+void			xmlXPtrRangeToFunction	(xmlXPathParserContextPtr ctxt,
+       						 int nargs);
+xmlNodePtr		xmlXPtrBuildNodeList	(xmlXPathObjectPtr obj);
+void		xmlXPtrEvalRangePredicate	(xmlXPathParserContextPtr ctxt);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XPTR_H__ */
diff --git a/include/win32config.h b/include/win32config.h
new file mode 100644
index 0000000..ea2cd50
--- /dev/null
+++ b/include/win32config.h
@@ -0,0 +1,92 @@
+#define HAVE_CTYPE_H
+#define HAVE_STDLIB_H
+#define HAVE_MALLOC_H
+#define HAVE_TIME_H
+#define HAVE_FCNTL_H
+
+#include <io.h>
+
+#define LIBXML_DLL_IMPORT
+#define SOCKLEN_T int
+
+#ifdef INCLUDE_WINSOCK
+#include <winsock2.h>
+
+#define EWOULDBLOCK             WSAEWOULDBLOCK
+#define EINPROGRESS             WSAEINPROGRESS
+#define EALREADY                WSAEALREADY
+#define ENOTSOCK                WSAENOTSOCK
+#define EDESTADDRREQ            WSAEDESTADDRREQ
+#define EMSGSIZE                WSAEMSGSIZE
+#define EPROTOTYPE              WSAEPROTOTYPE
+#define ENOPROTOOPT             WSAENOPROTOOPT
+#define EPROTONOSUPPORT         WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT         WSAESOCKTNOSUPPORT
+#define EOPNOTSUPP              WSAEOPNOTSUPP
+#define EPFNOSUPPORT            WSAEPFNOSUPPORT
+#define EAFNOSUPPORT            WSAEAFNOSUPPORT
+#define EADDRINUSE              WSAEADDRINUSE
+#define EADDRNOTAVAIL           WSAEADDRNOTAVAIL
+#define ENETDOWN                WSAENETDOWN
+#define ENETUNREACH             WSAENETUNREACH
+#define ENETRESET               WSAENETRESET
+#define ECONNABORTED            WSAECONNABORTED
+#define ECONNRESET              WSAECONNRESET
+#define ENOBUFS                 WSAENOBUFS
+#define EISCONN                 WSAEISCONN
+#define ENOTCONN                WSAENOTCONN
+#define ESHUTDOWN               WSAESHUTDOWN
+#define ETOOMANYREFS            WSAETOOMANYREFS
+#define ETIMEDOUT               WSAETIMEDOUT
+#define ECONNREFUSED            WSAECONNREFUSED
+#define ELOOP                   WSAELOOP
+#define ENAMETOOLONG            WSAENAMETOOLONG
+#define EHOSTDOWN               WSAEHOSTDOWN
+#define EHOSTUNREACH            WSAEHOSTUNREACH
+#define ENOTEMPTY               WSAENOTEMPTY
+#define EPROCLIM                WSAEPROCLIM
+#define EUSERS                  WSAEUSERS
+#define EDQUOT                  WSAEDQUOT
+#define ESTALE                  WSAESTALE
+#define EREMOTE                 WSAEREMOTE
+#endif /* INCLUDE_WINSOCK */
+
+#define HAVE_ISINF
+#define HAVE_ISNAN
+
+#include <math.h>
+static int isinf (double d) {
+    int expon = 0;
+    double val = frexp (d, &expon);
+    if (expon == 1025) {
+        if (val == 0.5) {
+            return 1;
+        } else if (val == -0.5) {
+            return -1;
+        } else {
+            return 0;
+        }
+    } else {
+        return 0;
+    }
+}
+static int isnan (double d) {
+    int expon = 0;
+    double val = frexp (d, &expon);
+    if (expon == 1025) {
+        if (val == 0.5) {
+            return 0;
+        } else if (val == -0.5) {
+            return 0;
+        } else {
+            return 1;
+        }
+    } else {
+        return 0;
+    }
+}
+
+#include <direct.h>
+
+#define HAVE_SYS_STAT_H                                                         #define HAVE__STAT
+
diff --git a/libxml-2.0.pc.in b/libxml-2.0.pc.in
new file mode 100644
index 0000000..d93b3e7
--- /dev/null
+++ b/libxml-2.0.pc.in
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+
+Name: libXML
+Version: @VERSION@
+Description: libXML library.
+Requires:
+Libs: -L${libdir} -lxml2 @Z_LIBS@ @M_LIBS@ @LIBS@
+Cflags: @XML_INCLUDEDIR@ @XML_CFLAGS@
diff --git a/libxml.4 b/libxml.4
new file mode 100644
index 0000000..5aa868f
--- /dev/null
+++ b/libxml.4
@@ -0,0 +1,66 @@
+.TH libxml 4 "12 April 2000"
+.SH NAME
+libxml \- library used to parse XML files
+.SH DESCRIPTION
+The
+.I  libxml
+library is used to parse XML files. 
+Its internal document repesentation is as close as possible to the 
+.I DOM 
+(Document Object Model) interface,
+an API for accessing XML or HTML structured documents.
+.LP
+The
+.I libxml
+library also has a 
+.IR SAX -like
+interface, 
+which is designed to be compatible with 
+.IR expat (1).
+NOTE:
+.IR SAX , 
+the Simple API for XML,
+is a standard interface for event-based XML parsing,
+developed collaboratively by the members of the XML-DEV mailing list, 
+currently hosted by OASIS.
+The
+.I expat
+library is a XML 1.0 parser written in C,
+which aims to be fully conforming. 
+It is currently not a validating XML processor.
+.LP
+The
+.I libxml 
+library now includes a nearly complete 
+.I XPath 
+implementation. 
+The
+.I XPath
+(XML Path Language) is a language for addressing parts of an 
+XML document,
+designed to be used by both 
+.I XSLT 
+and 
+.IR XPointer .
+.LP
+The
+.I libxml 
+library exports Push and Pull type parser interfaces for both XML and 
+.IR html . 
+.SH FILES
+.TP 2.2i
+.B /depot/lib/libxml_2.0.0/libxml.a
+static library
+.TP
+.B /depot/lib/libxml_2.0.0/libxml.so
+shareable library
+.TP
+.B /depot/package/libxml_2.0.0/bin/xmllint
+binary application for parsing XML files
+.SH AUTHORS
+Daniel Veillard (Daniel.Veillard@w3.org).
+If you download and install this package please send the author email.
+Manual page by Ziying Sherwin (sherwin@nlm.nih.gov),
+Lister Hill National Center for Biomedical Communications,
+U.S. National Library of Medicine.
+.\" end of manual page
diff --git a/libxml.m4 b/libxml.m4
new file mode 100644
index 0000000..1401af5
--- /dev/null
+++ b/libxml.m4
@@ -0,0 +1,148 @@
+dnl Code shamelessly stolen from glib-config by Sebastian Rittau
+dnl AM_PATH_XML([MINIMUM-VERSION [, ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]])
+AC_DEFUN(AM_PATH_XML,[
+AC_ARG_WITH(xml-prefix,
+            [  --with-xml-prefix=PFX    Prefix where libxml is installed (optional)],
+            xml_config_prefix="$withval", xml_config_prefix="")
+AC_ARG_ENABLE(xmltest,
+              [  --disable-xmltest        Do not try to compile and run a test XML program],,
+              enable_xmltest=yes)
+
+  if test x$xml_config_prefix != x ; then
+    xml_config_args="$xml_config_args --prefix=$xml_config_prefix"
+    if test x${XML_CONFIG+set} != xset ; then
+      XML_CONFIG=$xml_config_prefix/bin/xml-config
+    fi
+  fi
+
+  AC_PATH_PROG(XML_CONFIG, xml-config, no)
+  min_xml_version=ifelse([$1], ,2.0.0, [$1])
+  AC_MSG_CHECKING(for libxml - version >= $min_xml_version)
+  no_xml=""
+  if test "$XML_CONFIG" = "no" ; then
+    no_xml=yes
+  else
+    XML_CFLAGS=`$XML_CONFIG $xml_config_args --cflags`
+    XML_LIBS=`$XML_CONFIG $xml_config_args --libs`
+    xml_config_major_version=`$XML_CONFIG $xml_config_args --version | \
+      sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    xml_config_minor_version=`$XML_CONFIG $xml_config_args --version | \
+      sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    xml_config_micro_version=`$XML_CONFIG $xml_config_args --version | \
+      sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    if test "x$enable_xmltest" = "xyes" ; then
+      ac_save_CFLAGS="$CFLAGS"
+      ac_save_LIBS="$LIBS"
+      CFLAGS="$CFLAGS $XML_CFLAGS"
+      LIBS="$XML_LIBS $LIBS"
+dnl
+dnl Now check if the installed libxml is sufficiently new.
+dnl
+      rm -f conf.xmltest
+      AC_TRY_RUN([
+#include <stdlib.h>
+#include <stdio.h>
+#include <xmlversion.h>
+#include <parser.h>
+
+int
+main()
+{
+  int xml_major_version, xml_minor_version, xml_micro_version;
+  int major, minor, micro;
+  char *tmp_version;
+
+  system("touch conf.xmltest");
+
+  tmp_version = xmlStrdup("$min_xml_version");
+  if(sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) {
+    printf("%s, bad version string\n", "$min_xml_version");
+    exit(1);
+  }
+
+  tmp_version = xmlStrdup(LIBXML_DOTTED_VERSION);
+  if(sscanf(tmp_version, "%d.%d.%d", &xml_major_version, &xml_minor_version, &xml_micro_version) != 3) {
+    printf("%s, bad version string\n", "$min_xml_version");
+    exit(1);
+  }
+
+  if((xml_major_version != $xml_config_major_version) ||
+     (xml_minor_version != $xml_config_minor_version) ||
+     (xml_micro_version != $xml_config_micro_version))
+    {
+      printf("\n*** 'xml-config --version' returned %d.%d.%d, but libxml (%d.%d.%d)\n", 
+             $xml_config_major_version, $xml_config_minor_version, $xml_config_micro_version,
+             xml_major_version, xml_minor_version, xml_micro_version);
+      printf("*** was found! If xml-config was correct, then it is best\n");
+      printf("*** to remove the old version of libxml. You may also be able to fix the error\n");
+      printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n");
+      printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n");
+      printf("*** required on your system.\n");
+      printf("*** If xml-config was wrong, set the environment variable XML_CONFIG\n");
+      printf("*** to point to the correct copy of xml-config, and remove the file config.cache\n");
+      printf("*** before re-running configure\n");
+    }
+  else
+    {
+      if ((xml_major_version > major) ||
+          ((xml_major_version == major) && (xml_minor_version > minor)) ||
+          ((xml_major_version == major) && (xml_minor_version == minor) &&
+           (xml_micro_version >= micro)))
+        {
+          return 0;
+        }
+      else
+        {
+          printf("\n*** An old version of libxml (%d.%d.%d) was found.\n",
+            xml_major_version, xml_minor_version, xml_micro_version);
+          printf("*** You need a version of libxml newer than %d.%d.%d. The latest version of\n",
+            major, minor, micro);
+          printf("*** libxml is always available from ftp://ftp.gnome.org.\n");
+          printf("***\n");
+          printf("*** If you have already installed a sufficiently new version, this error\n");
+          printf("*** probably means that the wrong copy of the xml-config shell script is\n");
+          printf("*** being found. The easiest way to fix this is to remove the old version\n");
+          printf("*** of libxml, but you can also set the XML_CONFIG environment to point to the\n");
+          printf("*** correct copy of xml-config. (In this case, you will have to\n");
+          printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+          printf("*** so that the correct libraries are found at run-time))\n");
+        }
+    }
+  return 1;
+}
+],, no_xml=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+
+      CFLAGS="$ac_save_CFLAGS"
+      LIBS="$ac_save_LIBS"
+    fi
+  fi
+
+  if test "x$no_xml" = x ; then
+    AC_MSG_RESULT(yes)
+    ifelse([$2], , :, [$2])
+  else
+    AC_MSG_RESULT(no)
+    if test "$XML_CONFIG" = "no" ; then
+      echo "*** The xml-config script installed by libxml could not be found"
+      echo "*** If libxml was installed in PREFIX, make sure PREFIX/bin is in"
+      echo "*** your path, or set the XML_CONFIG environment variable to the"
+      echo "*** full path to xml-config."
+    else
+      if test -f conf.xmltest ; then
+        :
+      else
+        echo "*** Could not run libxml test program, checking why..."
+        CFLAGS="$CFLAGS $XML_CFLAGS"
+        LIBS="$LIBS $XML_LIBS"
+        dnl FIXME: AC_TRY_LINK
+      fi
+    fi
+
+    XML_CFLAGS=""
+    XML_LIBS=""
+    ifelse([$3], , :, [$3])
+  fi
+  AC_SUBST(XML_CFLAGS)
+  AC_SUBST(XML_LIBS)
+  rm -f conf.xmltest
+])
diff --git a/list.c b/list.c
new file mode 100644
index 0000000..bbe6144
--- /dev/null
+++ b/list.c
@@ -0,0 +1,706 @@
+/*
+ * list.c: lists handling implementation
+ *
+ * Copyright (C) 2000 Gary Pennington and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: Gary.Pennington@uk.sun.com
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/list.h>
+
+/*
+ * Type definition are kept internal
+ */
+
+struct _xmlLink
+{
+    struct _xmlLink *next;
+    struct _xmlLink *prev;
+    void *data;
+};
+
+struct _xmlList
+{
+    xmlLinkPtr sentinel;
+    void (*linkDeallocator)(xmlLinkPtr );
+    int (*linkCompare)(const void *, const void*);
+};
+
+/************************************************************************
+ *                                    *
+ *                Interfaces                *
+ *                                    *
+ ************************************************************************/
+
+/**
+ * xmlLinkDeallocator:
+ * @l:  a list
+ * @lk:  a link
+ *
+ * Unlink and deallocate @lk from list @l
+ */
+static void
+xmlLinkDeallocator(xmlListPtr l, xmlLinkPtr lk)
+{
+    (lk->prev)->next = lk->next;
+    (lk->next)->prev = lk->prev;
+    if(l->linkDeallocator)
+        l->linkDeallocator(lk);
+    xmlFree(lk);
+}
+
+/**
+ * xmlLinkCompare:
+ * @data0:  first data
+ * @data1:  second data
+ *
+ * Compares two arbitrary data
+ *
+ * Returns -1, 0 or 1 depending on whether data1 is greater equal or smaller
+ *          than data0
+ */
+static int
+xmlLinkCompare(const void *data0, const void *data1)
+{
+    if (data0 < data1)
+        return (-1);
+    else if (data0 == data1)
+	return (0);
+    return (1);
+}
+
+/**
+ * xmlListLowerSearch:
+ * @l:  a list
+ * @data:  a data
+ *
+ * Search data in the ordered list walking from the beginning
+ *
+ * Returns the link containing the data or NULL
+ */
+static xmlLinkPtr 
+xmlListLowerSearch(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lk;
+
+    for(lk = l->sentinel->next;lk != l->sentinel && l->linkCompare(lk->data, data) <0 ;lk = lk->next);
+    return lk;    
+}
+
+/**
+ * xmlListHigherSearch:
+ * @l:  a list
+ * @data:  a data
+ *
+ * Search data in the ordered list walking backward from the end
+ *
+ * Returns the link containing the data or NULL
+ */
+static xmlLinkPtr 
+xmlListHigherSearch(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lk;
+
+    for(lk = l->sentinel->prev;lk != l->sentinel && l->linkCompare(lk->data, data) >0 ;lk = lk->prev);
+    return lk;    
+}
+
+/**
+ * xmlListSearch:
+ * @l:  a list
+ * @data:  a data
+ *
+ * Search data in the list
+ *
+ * Returns the link containing the data or NULL
+ */
+static xmlLinkPtr 
+xmlListLinkSearch(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lk;
+    lk = xmlListLowerSearch(l, data);
+    if (lk == l->sentinel)
+        return NULL;
+    else {
+        if (l->linkCompare(lk->data, data) ==0)
+            return lk;
+        return NULL;
+    }
+}
+
+/**
+ * xmlListLinkReverseSearch:
+ * @l:  a list
+ * @data:  a data
+ *
+ * Search data in the list processing backward
+ *
+ * Returns the link containing the data or NULL
+ */
+xmlLinkPtr 
+xmlListLinkReverseSearch(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lk;
+    lk = xmlListHigherSearch(l, data);
+    if (lk == l->sentinel)
+        return NULL;
+    else {
+        if (l->linkCompare(lk->data, data) ==0)
+            return lk;
+        return NULL;
+    }
+}
+
+/**
+ * xmlListCreate:
+ * @deallocator:  an optional deallocator function
+ * @compare:  an optional comparison function
+ *
+ * Create a new list
+ *
+ * Returns the new list or NULL in case of error
+ */
+xmlListPtr
+xmlListCreate(xmlListDeallocator deallocator, xmlListDataCompare compare)
+{
+    xmlListPtr l;
+    if (NULL == (l = (xmlListPtr )xmlMalloc( sizeof(xmlList)))) {
+        perror("Cannot initialize memory for list");
+        return (NULL);
+    }
+    /* Initialize the list to NULL */
+    memset(l, 0, sizeof(xmlList));
+    
+    /* Add the sentinel */
+    if (NULL ==(l->sentinel = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
+        perror("Cannot initialize memory for sentinel");
+	xmlFree(l);
+        return (NULL);
+    }
+    l->sentinel->next = l->sentinel;
+    l->sentinel->prev = l->sentinel;
+    l->sentinel->data = NULL;
+    
+    /* If there is a link deallocator, use it */
+    if (deallocator != NULL)
+        l->linkDeallocator = deallocator;
+    /* If there is a link comparator, use it */
+    if (compare != NULL)
+        l->linkCompare = compare;
+    else /* Use our own */
+        l->linkCompare = xmlLinkCompare;
+    return l;
+}
+    
+/**
+ * xmlListSearch:
+ * @l:  a list
+ * @data:  a search value
+ *
+ * Search the list for an existing value of @data
+ *
+ * Returns the value associated to @data or NULL in case of error
+ */
+void *
+xmlListSearch(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lk;
+    lk = xmlListLinkSearch(l, data);
+    if (lk)
+        return (lk->data);
+    return NULL;
+}
+
+/**
+ * xmlListLinkReverseSearch:
+ * @l:  a list
+ * @data:  a search value
+ *
+ * Search the list in reverse order for an existing value of @data
+ *
+ * Returns the value associated to @data or NULL in case of error
+ */
+void *
+xmlListReverseSearch(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lk;
+    lk = xmlListLinkReverseSearch(l, data);
+    if (lk)
+        return (lk->data);
+    return NULL;
+}
+
+/**
+ * xmlListInsert:
+ * @l:  a list
+ * @data:  the data
+ *
+ * Insert data in the ordered list at the beginning for this value
+ *
+ * Returns 0 in case of success, 1 in case of failure
+ */
+int
+xmlListInsert(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lkPlace, lkNew;
+
+    lkPlace = xmlListLowerSearch(l, data);
+    /* Add the new link */
+    lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
+    if (lkNew == NULL) {
+        perror("Cannot initialize memory for new link");
+        return (1);
+    }
+    lkNew->data = data;
+    lkPlace = lkPlace->prev;
+    lkNew->next = lkPlace->next;
+    (lkPlace->next)->prev = lkNew;
+    lkPlace->next = lkNew;
+    lkNew->prev = lkPlace;
+    return 0;
+}
+
+/**
+ * xmlListAppend:
+ * @l:  a list
+ * @data:  the data
+ *
+ * Insert data in the ordered list at the end for this value
+ *
+ * Returns 0 in case of success, 1 in case of failure
+ */
+int xmlListAppend(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lkPlace, lkNew;
+
+    lkPlace = xmlListHigherSearch(l, data);
+    /* Add the new link */
+    lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
+    if (lkNew == NULL) {
+        perror("Cannot initialize memory for new link");
+        return (0);
+    }
+    lkNew->data = data;
+    lkNew->next = lkPlace->next;
+    (lkPlace->next)->prev = lkNew;
+    lkPlace->next = lkNew;
+    lkNew->prev = lkPlace;
+    return 1;
+}
+
+/**
+ * xmlListDelete:
+ * @l:  a list
+ *
+ * Deletes the list and its associated data
+ */
+void xmlListDelete(xmlListPtr l)
+{
+    xmlListClear(l);
+    xmlFree(l->sentinel);
+    xmlFree(l);
+}
+
+/**
+ * xmlListRemoveFirst:
+ * @l:  a list
+ * @data:  list data
+ *
+ * Remove the first instance associated to data in the list
+ *
+ * Returns 1 if a deallocation occured, or 0 if not found
+ */
+int
+xmlListRemoveFirst(xmlListPtr l, void *data)
+{
+    xmlLinkPtr lk;
+    
+    /*Find the first instance of this data */
+    lk = xmlListLinkSearch(l, data);
+    if (lk != NULL) {
+        xmlLinkDeallocator(l, lk);
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ * xmlListRemoveLast:
+ * @l:  a list
+ * @data:  list data
+ *
+ * Remove the last instance associated to data in the list
+ *
+ * Returns 1 if a deallocation occured, or 0 if not found
+ */
+int
+xmlListRemoveLast(xmlListPtr l, void *data)
+{
+    xmlLinkPtr lk;
+    
+    /*Find the last instance of this data */
+    lk = xmlListLinkReverseSearch(l, data);
+    if (lk != NULL) {
+	xmlLinkDeallocator(l, lk);
+        return 1;
+    }
+    return 0;
+}
+
+/**
+ * xmlListRemoveAll:
+ * @l:  a list
+ * @data:  list data
+ *
+ * Remove the all instance associated to data in the list
+ *
+ * Returns the number of deallocation, or 0 if not found
+ */
+int
+xmlListRemoveAll(xmlListPtr l, void *data)
+{
+    int count=0;
+    
+
+    while(xmlListRemoveFirst(l, data))
+        count++;
+    return count;
+}
+
+/**
+ * xmlListClear:
+ * @l:  a list
+ *
+ * Remove the all data in the list
+ */
+void
+xmlListClear(xmlListPtr l)
+{
+    xmlLinkPtr  lk = l->sentinel->next;
+    
+    while(lk != l->sentinel) {
+        xmlLinkPtr next = lk->next;
+
+        xmlLinkDeallocator(l, lk);
+        lk = next;
+    }
+}
+
+/**
+ * xmlListEmpty:
+ * @l:  a list
+ *
+ * Returns 1 if the list is empty, 0 otherwise
+ */
+int
+xmlListEmpty(xmlListPtr l)
+{
+    return (l->sentinel->next == l->sentinel);
+}
+
+/**
+ * xmlListFront:
+ * @l:  a list
+ *
+ * Returns the first element in the list, or NULL
+ */
+xmlLinkPtr 
+xmlListFront(xmlListPtr l)
+{
+    return (l->sentinel->next);
+}
+    
+/**
+ * xmlListFront:
+ * @l:  a list
+ *
+ * Returns the last element in the list, or NULL
+ */
+xmlLinkPtr 
+xmlListEnd(xmlListPtr l)
+{
+    return (l->sentinel->prev);
+}
+    
+/**
+ * xmlListSize:
+ * @l:  a list
+ *
+ * Returns the number of elements in the list
+ */
+int
+xmlListSize(xmlListPtr l)
+{
+    xmlLinkPtr lk;
+    int count=0;
+
+    /* TODO: keep a counter in xmlList instead */
+    for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next, count++);
+    return count;
+}
+
+/**
+ * xmlListPopFront:
+ * @l:  a list
+ *
+ * Removes the first element in the list
+ */
+void
+xmlListPopFront(xmlListPtr l)
+{
+    if(!xmlListEmpty(l))
+        xmlLinkDeallocator(l, l->sentinel->next);
+}
+
+/**
+ * xmlListPopBack:
+ * @l:  a list
+ *
+ * Removes the last element in the list
+ */
+void
+xmlListPopBack(xmlListPtr l)
+{
+    if(!xmlListEmpty(l))
+        xmlLinkDeallocator(l, l->sentinel->prev);
+}
+
+/**
+ * xmlListPushFront:
+ * @l:  a list
+ * @data:  new data
+ *
+ * add the new data at the beginning of the list
+ *
+ * Returns 1 if successful, 0 otherwise
+ */
+int
+xmlListPushFront(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lkPlace, lkNew;
+
+    lkPlace = l->sentinel;
+    /* Add the new link */
+    lkNew = (xmlLinkPtr) xmlMalloc(sizeof(xmlLink));
+    if (lkNew == NULL) {
+        perror("Cannot initialize memory for new link");
+        return (0);
+    }
+    lkNew->data = data;
+    lkNew->next = lkPlace->next;
+    (lkPlace->next)->prev = lkNew;
+    lkPlace->next = lkNew;
+    lkNew->prev = lkPlace;
+    return 1;
+}
+
+/**
+ * xmlListPushBack:
+ * @l:  a list
+ * @data:  new data
+ *
+ * add the new data at the end of the list
+ *
+ * Returns 1 if successful, 0 otherwise
+ */
+int
+xmlListPushBack(xmlListPtr l, void *data) 
+{
+    xmlLinkPtr lkPlace, lkNew;
+
+    lkPlace = l->sentinel->prev;
+    /* Add the new link */
+    if (NULL ==(lkNew = (xmlLinkPtr )xmlMalloc(sizeof(xmlLink)))) {
+        perror("Cannot initialize memory for new link");
+        return (0);
+    }
+    lkNew->data = data;
+    lkNew->next = lkPlace->next;
+    (lkPlace->next)->prev = lkNew;
+    lkPlace->next = lkNew;
+    lkNew->prev = lkPlace;
+    return 1;
+}
+
+/**
+ * xmlLinkGetData:
+ * @lk:  a link
+ *
+ * See Returns.
+ *
+ * Returns a pointer to the data referenced from this link
+ */
+void *
+xmlLinkGetData(xmlLinkPtr lk)
+{
+    return lk->data;
+}
+
+/**
+ * xmlListReverse:
+ * @l:  a list
+ *
+ * Reverse the order of the elements in the list
+ */
+void
+xmlListReverse(xmlListPtr l) {
+  xmlLinkPtr lk;
+  xmlLinkPtr lkPrev = l->sentinel;
+  
+  for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
+    lkPrev->next = lkPrev->prev;
+    lkPrev->prev = lk;
+    lkPrev = lk;
+  }
+  /* Fix up the last node */
+  lkPrev->next = lkPrev->prev;
+  lkPrev->prev = lk;
+}
+
+/**
+ * xmlListSort:
+ * @l:  a list
+ *
+ * Sort all the elements in the list
+ */
+void
+xmlListSort(xmlListPtr l)
+{
+    xmlListPtr lTemp;
+    
+    if(xmlListEmpty(l))
+        return;
+
+    /* I think that the real answer is to implement quicksort, the
+     * alternative is to implement some list copying procedure which
+     * would be based on a list copy followed by a clear followed by
+     * an insert. This is slow...
+     */
+
+    if (NULL ==(lTemp = xmlListDup(l)))
+        return;
+    xmlListClear(l);
+    xmlListMerge(l, lTemp);
+    xmlListDelete(lTemp);
+    return;
+}
+
+/**
+ * xmlListWalk:
+ * @l:  a list
+ * @walker:  a processing function
+ *
+ * Walk all the element of the first from first to last and
+ * apply the walker function to it
+ */
+void
+xmlListWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
+    xmlLinkPtr lk;
+
+    for(lk = l->sentinel->next; lk != l->sentinel; lk = lk->next) {
+        if((walker(lk->data, user)) == 0)
+                break;
+    }
+}
+
+/**
+ * xmlListReverseWalk:
+ * @l:  a list
+ * @walker:  a processing function
+ *
+ * Walk all the element of the list in reverse order and
+ * apply the walker function to it
+ */
+void
+xmlListReverseWalk(xmlListPtr l, xmlListWalker walker, const void *user) {
+    xmlLinkPtr lk;
+
+    for(lk = l->sentinel->prev; lk != l->sentinel; lk = lk->prev) {
+        if((walker(lk->data, user)) == 0)
+                break;
+    }
+}
+
+/**
+ * xmlListMerge:
+ * @l1:  the original list
+ * @l2:  the new list
+ *
+ * include all the elements of the second list in the first one and
+ * clear the second list
+ */
+void
+xmlListMerge(xmlListPtr l1, xmlListPtr l2)
+{
+    xmlListCopy(l1, l2);
+    xmlListClear(l2);
+}
+
+/**
+ * xmlListDup:
+ * @old:  the list
+ *
+ * Duplicate the list
+ * 
+ * Returns a new copy of the list or NULL in case of error
+ */
+xmlListPtr 
+xmlListDup(const xmlListPtr old)
+{
+    xmlListPtr cur;
+    /* Hmmm, how to best deal with allocation issues when copying
+     * lists. If there is a de-allocator, should responsibility lie with
+     * the new list or the old list. Surely not both. I'll arbitrarily
+     * set it to be the old list for the time being whilst I work out
+     * the answer
+     */
+    if (NULL ==(cur = xmlListCreate(NULL, old->linkCompare)))
+        return (NULL);
+    if (0 != xmlListCopy(cur, old))
+        return NULL;
+    return cur;
+}
+
+/**
+ * xmlListCopy:
+ * @cur:  the new list
+ * @old:  the old list
+ *
+ * Move all the element from the old list in the new list
+ * 
+ * Returns 0 in case of success 1 in case of error
+ */
+int
+xmlListCopy(xmlListPtr cur, const xmlListPtr old)
+{
+    /* Walk the old tree and insert the data into the new one */
+    xmlLinkPtr lk;
+
+    for(lk = old->sentinel->next; lk != old->sentinel; lk = lk->next) {
+        if (0 !=xmlListInsert(cur, lk->data)) {
+            xmlListDelete(cur);
+            return (1);
+        }
+    }
+    return (0);    
+}
+/* xmlListUnique() */
+/* xmlListSwap */
diff --git a/list.h b/list.h
new file mode 100644
index 0000000..a708ef2
--- /dev/null
+++ b/list.h
@@ -0,0 +1,81 @@
+/*
+ * list.h: lists interfaces
+ *
+ * Copyright (C) 2000 Gary Pennington and Daniel Veillard.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE AUTHORS AND
+ * CONTRIBUTORS ACCEPT NO RESPONSIBILITY IN ANY CONCEIVABLE MANNER.
+ *
+ * Author: Gary.Pennington@uk.sun.com
+ */
+
+typedef struct _xmlLink xmlLink;
+typedef xmlLink *xmlLinkPtr;
+
+typedef struct _xmlList xmlList;
+typedef xmlList *xmlListPtr;
+
+typedef void (*xmlListDeallocator) (xmlLinkPtr lk);
+typedef int  (*xmlListDataCompare) (const void *data0, const void *data1);
+typedef int (*xmlListWalker) (const void *data, const void *user);
+
+/* Creation/Deletion */
+xmlListPtr	xmlListCreate		(xmlListDeallocator deallocator,
+	                                 xmlListDataCompare compare);
+void		xmlListDelete		(xmlListPtr l);
+
+/* Basic Operators */
+void *		xmlListSearch		(xmlListPtr l,
+					 void *data);
+void *		xmlListReverseSearch	(xmlListPtr l,
+					 void *data);
+int		xmlListInsert		(xmlListPtr l,
+					 void *data) ;
+int		xmlListAppend		(xmlListPtr l,
+					 void *data) ;
+int		xmlListRemoveFirst	(xmlListPtr l,
+					 void *data);
+int		xmlListRemoveLast	(xmlListPtr l,
+					 void *data);
+int		xmlListRemoveAll	(xmlListPtr l,
+					 void *data);
+void		xmlListClear		(xmlListPtr l);
+int		xmlListEmpty		(xmlListPtr l);
+xmlLinkPtr	xmlListFront		(xmlListPtr l);
+xmlLinkPtr	xmlListEnd		(xmlListPtr l);
+int		xmlListSize		(xmlListPtr l);
+
+void		xmlListPopFront		(xmlListPtr l);
+void		xmlListPopBack		(xmlListPtr l);
+int		xmlListPushFront	(xmlListPtr l,
+					 void *data);
+int		xmlListPushBack		(xmlListPtr l,
+					 void *data);
+
+/* Advanced Operators */
+void		xmlListReverse		(xmlListPtr l);
+void		xmlListSort		(xmlListPtr l);
+void		xmlListWalk		(xmlListPtr l,
+					 xmlListWalker walker,
+					 const void *user);
+void		xmlListReverseWalk	(xmlListPtr l,
+					 xmlListWalker walker,
+					 const void *user);
+void		xmlListMerge		(xmlListPtr l1,
+					 xmlListPtr l2);
+xmlListPtr	xmlListDup		(const xmlListPtr old);
+int		xmlListCopy		(xmlListPtr cur,
+					 const xmlListPtr old);
+/* Link operators */
+void *          xmlLinkGetData          (xmlLinkPtr lk);
+
+/* xmlListUnique() */
+/* xmlListSwap */
+
+
diff --git a/nanoftp.c b/nanoftp.c
new file mode 100644
index 0000000..c7ea79a
--- /dev/null
+++ b/nanoftp.c
@@ -0,0 +1,1964 @@
+/*
+ * nanoftp.c: basic FTP client support
+ *
+ *  Reference: RFC 959
+ */
+
+#ifdef TESTING
+#define STANDALONE
+#define HAVE_STDLIB_H
+#define HAVE_UNISTD_H
+#define HAVE_SYS_SOCKET_H
+#define HAVE_NETINET_IN_H
+#define HAVE_NETDB_H
+#define HAVE_SYS_TIME_H
+#else /* STANDALONE */
+#ifdef WIN32
+#define INCLUDE_WINSOCK
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+#endif /* STANDALONE */
+
+#include <libxml/xmlversion.h>
+
+#ifdef LIBXML_FTP_ENABLED
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h> 
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/nanoftp.h>
+#include <libxml/xmlerror.h>
+
+/* #define DEBUG_FTP 1  */
+#ifdef STANDALONE
+#ifndef DEBUG_FTP
+#define DEBUG_FTP 1
+#endif
+#endif
+
+/**
+ * A couple portability macros
+ */
+#ifndef _WINSOCKAPI_
+#define closesocket(s) close(s)
+#define SOCKET int
+#endif
+
+static char hostname[100];
+
+#define FTP_COMMAND_OK		200
+#define FTP_SYNTAX_ERROR	500
+#define FTP_GET_PASSWD		331
+#define FTP_BUF_SIZE		512
+
+typedef struct xmlNanoFTPCtxt {
+    char *protocol;	/* the protocol name */
+    char *hostname;	/* the host name */
+    int port;		/* the port */
+    char *path;		/* the path within the URL */
+    char *user;		/* user string */
+    char *passwd;	/* passwd string */
+    struct sockaddr_in ftpAddr; /* the socket address struct */
+    int passive;	/* currently we support only passive !!! */
+    SOCKET controlFd;	/* the file descriptor for the control socket */
+    SOCKET dataFd;	/* the file descriptor for the data socket */
+    int state;		/* WRITE / READ / CLOSED */
+    int returnValue;	/* the protocol return value */
+    /* buffer for data received from the control connection */
+    char controlBuf[FTP_BUF_SIZE + 1];
+    int controlBufIndex;
+    int controlBufUsed;
+    int controlBufAnswer;
+} xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr;
+
+static int initialized = 0;
+static char *proxy = NULL;	/* the proxy name if any */
+static int proxyPort = 0;	/* the proxy port if any */
+static char *proxyUser = NULL;	/* user for proxy authentication */
+static char *proxyPasswd = NULL;/* passwd for proxy authentication */
+static int proxyType = 0;	/* uses TYPE or a@b ? */
+
+/**
+ * xmlNanoFTPInit:
+ *
+ * Initialize the FTP protocol layer.
+ * Currently it just checks for proxy informations,
+ * and get the hostname
+ */
+
+void
+xmlNanoFTPInit(void) {
+    const char *env;
+#ifdef _WINSOCKAPI_
+    WSADATA wsaData;    
+#endif
+
+    if (initialized)
+	return;
+
+#ifdef _WINSOCKAPI_
+    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
+	return;
+#endif
+
+    gethostname(hostname, sizeof(hostname));
+
+    proxyPort = 21;
+    env = getenv("no_proxy");
+    if (env != NULL)
+	return;
+    env = getenv("ftp_proxy");
+    if (env != NULL) {
+	xmlNanoFTPScanProxy(env);
+    } else {
+	env = getenv("FTP_PROXY");
+	if (env != NULL) {
+	    xmlNanoFTPScanProxy(env);
+	}
+    }
+    env = getenv("ftp_proxy_user");
+    if (env != NULL) {
+	proxyUser = xmlMemStrdup(env);
+    }
+    env = getenv("ftp_proxy_password");
+    if (env != NULL) {
+	proxyPasswd = xmlMemStrdup(env);
+    }
+    initialized = 1;
+}
+
+/**
+ * xmlNanoFTPClenup:
+ *
+ * Cleanup the FTP protocol layer. This cleanup proxy informations.
+ */
+
+void
+xmlNanoFTPCleanup(void) {
+    if (proxy != NULL) {
+	xmlFree(proxy);
+	proxy = NULL;
+    }
+    if (proxyUser != NULL) {
+	xmlFree(proxyUser);
+	proxyUser = NULL;
+    }
+    if (proxyPasswd != NULL) {
+	xmlFree(proxyPasswd);
+	proxyPasswd = NULL;
+    }
+    hostname[0] = 0;
+#ifdef _WINSOCKAPI_
+    if (initialized)
+	WSACleanup();
+#endif
+    initialized = 0;
+    return;
+}
+
+/**
+ * xmlNanoFTPProxy:
+ * @host:  the proxy host name
+ * @port:  the proxy port
+ * @user:  the proxy user name
+ * @passwd:  the proxy password
+ * @type:  the type of proxy 1 for using SITE, 2 for USER a@b
+ *
+ * Setup the FTP proxy informations.
+ * This can also be done by using ftp_proxy ftp_proxy_user and
+ * ftp_proxy_password environment variables.
+ */
+
+void
+xmlNanoFTPProxy(const char *host, int port, const char *user,
+	        const char *passwd, int type) {
+    if (proxy != NULL)
+	xmlFree(proxy);
+    if (proxyUser != NULL)
+	xmlFree(proxyUser);
+    if (proxyPasswd != NULL)
+	xmlFree(proxyPasswd);
+    if (host)
+	proxy = xmlMemStrdup(host);
+    if (user)
+	proxyUser = xmlMemStrdup(user);
+    if (passwd)
+	proxyPasswd = xmlMemStrdup(passwd);
+    proxyPort = port;
+    proxyType = type;
+}
+
+/**
+ * xmlNanoFTPScanURL:
+ * @ctx:  an FTP context
+ * @URL:  The URL used to initialize the context
+ *
+ * (Re)Initialize an FTP context by parsing the URL and finding
+ * the protocol host port and path it indicates.
+ */
+
+static void
+xmlNanoFTPScanURL(void *ctx, const char *URL) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    const char *cur = URL;
+    char buf[4096];
+    int index = 0;
+    int port = 0;
+
+    if (ctxt->protocol != NULL) { 
+        xmlFree(ctxt->protocol);
+	ctxt->protocol = NULL;
+    }
+    if (ctxt->hostname != NULL) { 
+        xmlFree(ctxt->hostname);
+	ctxt->hostname = NULL;
+    }
+    if (ctxt->path != NULL) { 
+        xmlFree(ctxt->path);
+	ctxt->path = NULL;
+    }
+    if (URL == NULL) return;
+    buf[index] = 0;
+    while (*cur != 0) {
+        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
+	    buf[index] = 0;
+	    ctxt->protocol = xmlMemStrdup(buf);
+	    index = 0;
+            cur += 3;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0) return;
+
+    buf[index] = 0;
+    while (1) {
+        if (cur[0] == ':') {
+	    buf[index] = 0;
+	    ctxt->hostname = xmlMemStrdup(buf);
+	    index = 0;
+	    cur += 1;
+	    while ((*cur >= '0') && (*cur <= '9')) {
+	        port *= 10;
+		port += *cur - '0';
+		cur++;
+	    }
+	    if (port != 0) ctxt->port = port;
+	    while ((cur[0] != '/') && (*cur != 0)) 
+	        cur++;
+	    break;
+	}
+        if ((*cur == '/') || (*cur == 0)) {
+	    buf[index] = 0;
+	    ctxt->hostname = xmlMemStrdup(buf);
+	    index = 0;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0) 
+        ctxt->path = xmlMemStrdup("/");
+    else {
+        index = 0;
+        buf[index] = 0;
+	while (*cur != 0)
+	    buf[index++] = *cur++;
+	buf[index] = 0;
+	ctxt->path = xmlMemStrdup(buf);
+    }	
+}
+
+/**
+ * xmlNanoFTPUpdateURL:
+ * @ctx:  an FTP context
+ * @URL:  The URL used to update the context
+ *
+ * Update an FTP context by parsing the URL and finding
+ * new path it indicates. If there is an error in the 
+ * protocol, hostname, port or other information, the
+ * error is raised. It indicates a new connection has to
+ * be established.
+ *
+ * Returns 0 if Ok, -1 in case of error (other host).
+ */
+
+int
+xmlNanoFTPUpdateURL(void *ctx, const char *URL) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    const char *cur = URL;
+    char buf[4096];
+    int index = 0;
+    int port = 0;
+
+    if (URL == NULL)
+	return(-1);
+    if (ctxt == NULL)
+	return(-1);
+    if (ctxt->protocol == NULL)
+	return(-1);
+    if (ctxt->hostname == NULL)
+	return(-1);
+    buf[index] = 0;
+    while (*cur != 0) {
+        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
+	    buf[index] = 0;
+	    if (strcmp(ctxt->protocol, buf))
+		return(-1);
+	    index = 0;
+            cur += 3;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0)
+	return(-1);
+
+    buf[index] = 0;
+    while (1) {
+        if (cur[0] == ':') {
+	    buf[index] = 0;
+	    if (strcmp(ctxt->hostname, buf))
+		return(-1);
+	    index = 0;
+	    cur += 1;
+	    while ((*cur >= '0') && (*cur <= '9')) {
+	        port *= 10;
+		port += *cur - '0';
+		cur++;
+	    }
+	    if (port != ctxt->port)
+		return(-1);
+	    while ((cur[0] != '/') && (*cur != 0)) 
+	        cur++;
+	    break;
+	}
+        if ((*cur == '/') || (*cur == 0)) {
+	    buf[index] = 0;
+	    if (strcmp(ctxt->hostname, buf))
+		return(-1);
+	    index = 0;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (ctxt->path != NULL) {
+	xmlFree(ctxt->path);
+	ctxt->path = NULL;
+    }
+
+    if (*cur == 0) 
+        ctxt->path = xmlMemStrdup("/");
+    else {
+        index = 0;
+        buf[index] = 0;
+	while (*cur != 0)
+	    buf[index++] = *cur++;
+	buf[index] = 0;
+	ctxt->path = xmlMemStrdup(buf);
+    }	
+    return(0);
+}
+
+/**
+ * xmlNanoFTPScanProxy:
+ * @URL:  The proxy URL used to initialize the proxy context
+ *
+ * (Re)Initialize the FTP Proxy context by parsing the URL and finding
+ * the protocol host port it indicates.
+ * Should be like ftp://myproxy/ or ftp://myproxy:3128/
+ * A NULL URL cleans up proxy informations.
+ */
+
+void
+xmlNanoFTPScanProxy(const char *URL) {
+    const char *cur = URL;
+    char buf[4096];
+    int index = 0;
+    int port = 0;
+
+    if (proxy != NULL) { 
+        xmlFree(proxy);
+	proxy = NULL;
+    }
+    if (proxyPort != 0) { 
+	proxyPort = 0;
+    }
+#ifdef DEBUG_FTP
+    if (URL == NULL)
+	xmlGenericError(xmlGenericErrorContext, "Removing FTP proxy info\n");
+    else
+	xmlGenericError(xmlGenericErrorContext, "Using FTP proxy %s\n", URL);
+#endif
+    if (URL == NULL) return;
+    buf[index] = 0;
+    while (*cur != 0) {
+        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
+	    buf[index] = 0;
+	    index = 0;
+            cur += 3;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0) return;
+
+    buf[index] = 0;
+    while (1) {
+        if (cur[0] == ':') {
+	    buf[index] = 0;
+	    proxy = xmlMemStrdup(buf);
+	    index = 0;
+	    cur += 1;
+	    while ((*cur >= '0') && (*cur <= '9')) {
+	        port *= 10;
+		port += *cur - '0';
+		cur++;
+	    }
+	    if (port != 0) proxyPort = port;
+	    while ((cur[0] != '/') && (*cur != 0)) 
+	        cur++;
+	    break;
+	}
+        if ((*cur == '/') || (*cur == 0)) {
+	    buf[index] = 0;
+	    proxy = xmlMemStrdup(buf);
+	    index = 0;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+}
+
+/**
+ * xmlNanoFTPNewCtxt:
+ * @URL:  The URL used to initialize the context
+ *
+ * Allocate and initialize a new FTP context.
+ *
+ * Returns an FTP context or NULL in case of error.
+ */
+
+void*
+xmlNanoFTPNewCtxt(const char *URL) {
+    xmlNanoFTPCtxtPtr ret;
+
+    ret = (xmlNanoFTPCtxtPtr) xmlMalloc(sizeof(xmlNanoFTPCtxt));
+    if (ret == NULL) return(NULL);
+
+    memset(ret, 0, sizeof(xmlNanoFTPCtxt));
+    ret->port = 21;
+    ret->passive = 1;
+    ret->returnValue = 0;
+    ret->controlBufIndex = 0;
+    ret->controlBufUsed = 0;
+
+    if (URL != NULL)
+	xmlNanoFTPScanURL(ret, URL);
+
+    return(ret);
+}
+
+/**
+ * xmlNanoFTPFreeCtxt:
+ * @ctx:  an FTP context
+ *
+ * Frees the context after closing the connection.
+ */
+
+void
+xmlNanoFTPFreeCtxt(void * ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    if (ctxt == NULL) return;
+    if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
+    if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
+    if (ctxt->path != NULL) xmlFree(ctxt->path);
+    ctxt->passive = 1;
+    if (ctxt->controlFd >= 0) closesocket(ctxt->controlFd);
+    ctxt->controlFd = -1;
+    ctxt->controlBufIndex = -1;
+    ctxt->controlBufUsed = -1;
+    xmlFree(ctxt);
+}
+
+/**
+ * xmlNanoFTPParseResponse:
+ * @ctx:  the FTP connection context
+ * @buf:  the buffer containing the response
+ * @len:  the buffer length
+ * 
+ * Parsing of the server answer, we just extract the code.
+ *
+ * returns 0 for errors
+ *     +XXX for last line of response
+ *     -XXX for response to be continued
+ */
+static int
+xmlNanoFTPParseResponse(void *ctx, char *buf, int len) {
+    int val = 0;
+
+    if (len < 3) return(-1);
+    if ((*buf >= '0') && (*buf <= '9')) 
+        val = val * 10 + (*buf - '0');
+    else
+        return(0);
+    buf++;
+    if ((*buf >= '0') && (*buf <= '9')) 
+        val = val * 10 + (*buf - '0');
+    else
+        return(0);
+    buf++;
+    if ((*buf >= '0') && (*buf <= '9')) 
+        val = val * 10 + (*buf - '0');
+    else
+        return(0);
+    buf++;
+    if (*buf == '-') 
+        return(-val);
+    return(val);
+}
+
+/**
+ * xmlNanoFTPGetMore:
+ * @ctx:  an FTP context
+ *
+ * Read more information from the FTP control connection
+ * Returns the number of bytes read, < 0 indicates an error
+ */
+static int
+xmlNanoFTPGetMore(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    int len;
+    int size;
+
+    if ((ctxt->controlBufIndex < 0) || (ctxt->controlBufIndex > FTP_BUF_SIZE)) {
+#ifdef DEBUG_FTP
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNanoFTPGetMore : controlBufIndex = %d\n",
+		ctxt->controlBufIndex);
+#endif
+	return(-1);
+    }
+
+    if ((ctxt->controlBufUsed < 0) || (ctxt->controlBufUsed > FTP_BUF_SIZE)) {
+#ifdef DEBUG_FTP
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNanoFTPGetMore : controlBufUsed = %d\n",
+		ctxt->controlBufUsed);
+#endif
+	return(-1);
+    }
+    if (ctxt->controlBufIndex > ctxt->controlBufUsed) {
+#ifdef DEBUG_FTP
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNanoFTPGetMore : controlBufIndex > controlBufUsed %d > %d\n",
+	       ctxt->controlBufIndex, ctxt->controlBufUsed);
+#endif
+	return(-1);
+    }
+
+    /*
+     * First pack the control buffer
+     */
+    if (ctxt->controlBufIndex > 0) {
+	memmove(&ctxt->controlBuf[0], &ctxt->controlBuf[ctxt->controlBufIndex],
+		ctxt->controlBufUsed - ctxt->controlBufIndex);
+	ctxt->controlBufUsed -= ctxt->controlBufIndex;
+	ctxt->controlBufIndex = 0;
+    }
+    size = FTP_BUF_SIZE - ctxt->controlBufUsed;
+    if (size == 0) {
+#ifdef DEBUG_FTP
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNanoFTPGetMore : buffer full %d \n", ctxt->controlBufUsed);
+#endif
+	return(0);
+    }
+
+    /*
+     * Read the amount left on teh control connection
+     */
+    if ((len = recv(ctxt->controlFd, &ctxt->controlBuf[ctxt->controlBufIndex],
+		    size, 0)) < 0) {
+	closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+        ctxt->controlFd = -1;
+        return(-1);
+    }
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext,
+	    "xmlNanoFTPGetMore : read %d [%d - %d]\n", len,
+	   ctxt->controlBufUsed, ctxt->controlBufUsed + len);
+#endif
+    ctxt->controlBufUsed += len;
+    ctxt->controlBuf[ctxt->controlBufUsed] = 0;
+
+    return(len);
+}
+
+/**
+ * xmlNanoFTPReadResponse:
+ * @ctx:  an FTP context
+ *
+ * Read the response from the FTP server after a command.
+ * Returns the code number
+ */
+static int
+xmlNanoFTPReadResponse(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char *ptr, *end;
+    int len;
+    int res = -1, cur = -1;
+
+get_more:
+    /*
+     * Assumes everything up to controlBuf[controlBufIndex] has been read
+     * and analyzed.
+     */
+    len = xmlNanoFTPGetMore(ctx);
+    if (len < 0) {
+        return(-1);
+    }
+    if ((ctxt->controlBufUsed == 0) && (len == 0)) {
+        return(-1);
+    }
+    ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
+    end = &ctxt->controlBuf[ctxt->controlBufUsed];
+
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext,
+	    "\n<<<\n%s\n--\n", ptr);
+#endif
+    while (ptr < end) {
+        cur = xmlNanoFTPParseResponse(ctxt, ptr, end - ptr);
+	if (cur > 0) {
+	    /*
+	     * Successfully scanned the control code, scratch
+	     * till the end of the line, but keep the index to be
+	     * able to analyze the result if needed.
+	     */
+	    res = cur;
+	    ptr += 3;
+	    ctxt->controlBufAnswer = ptr - ctxt->controlBuf;
+	    while ((ptr < end) && (*ptr != '\n')) ptr++;
+	    if (*ptr == '\n') ptr++;
+	    if (*ptr == '\r') ptr++;
+	    break;
+	}
+	while ((ptr < end) && (*ptr != '\n')) ptr++;
+	if (ptr >= end) {
+	    ctxt->controlBufIndex = ctxt->controlBufUsed;
+	    goto get_more;
+	}
+	if (*ptr != '\r') ptr++;
+    }
+
+    if (res < 0) goto get_more;
+    ctxt->controlBufIndex = ptr - ctxt->controlBuf;
+#ifdef DEBUG_FTP
+    ptr = &ctxt->controlBuf[ctxt->controlBufIndex];
+    xmlGenericError(xmlGenericErrorContext, "\n---\n%s\n--\n", ptr);
+#endif
+
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, "Got %d\n", res);
+#endif
+    return(res / 100);
+}
+
+/**
+ * xmlNanoFTPGetResponse:
+ * @ctx:  an FTP context
+ *
+ * Get the response from the FTP server after a command.
+ * Returns the code number
+ */
+
+int
+xmlNanoFTPGetResponse(void *ctx) {
+    int res;
+
+    res = xmlNanoFTPReadResponse(ctx);
+
+    return(res);
+}
+
+/**
+ * xmlNanoFTPCheckResponse:
+ * @ctx:  an FTP context
+ *
+ * Check if there is a response from the FTP server after a command.
+ * Returns the code number, or 0
+ */
+
+int
+xmlNanoFTPCheckResponse(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    fd_set rfd;
+    struct timeval tv;
+
+    tv.tv_sec = 0;
+    tv.tv_usec = 0;
+    FD_ZERO(&rfd);
+    FD_SET(ctxt->controlFd, &rfd);
+    switch(select(ctxt->controlFd + 1, &rfd, NULL, NULL, &tv)) {
+	case 0:
+	    return(0);
+	case -1:
+#ifdef DEBUG_FTP
+	    perror("select");
+#endif
+	    return(-1);
+			
+    }
+
+    return(xmlNanoFTPReadResponse(ctx));
+}
+
+/**
+ * Send the user authentification
+ */
+
+static int
+xmlNanoFTPSendUser(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[200];
+    int len;
+    int res;
+
+    if (ctxt->user == NULL)
+	sprintf(buf, "USER anonymous\r\n");
+    else
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "USER %s\r\n", ctxt->user);
+#else
+	sprintf(buf, "USER %s\r\n", ctxt->user);
+#endif
+    buf[sizeof(buf) - 1] = 0;
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    if (res < 0) return(res);
+    return(0);
+}
+
+/**
+ * Send the password authentification
+ */
+
+static int
+xmlNanoFTPSendPasswd(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[200];
+    int len;
+    int res;
+
+    if (ctxt->passwd == NULL)
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", hostname);
+#else
+	sprintf(buf, "PASS libxml@%s\r\n", hostname);
+#endif
+    else
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
+#else
+	sprintf(buf, "PASS %s\r\n", ctxt->passwd);
+#endif
+    buf[sizeof(buf) - 1] = 0;
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    if (res < 0) return(res);
+    return(0);
+}
+
+/**
+ * xmlNanoFTPQuit:
+ * @ctx:  an FTP context
+ *
+ * Send a QUIT command to the server
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+
+
+int
+xmlNanoFTPQuit(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[200];
+    int len;
+    int res;
+
+    sprintf(buf, "QUIT\r\n");
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    return(0);
+}
+
+/**
+ * xmlNanoFTPConnect:
+ * @ctx:  an FTP context
+ *
+ * Tries to open a control connection
+ *
+ * Returns -1 in case of error, 0 otherwise
+ */
+
+int
+xmlNanoFTPConnect(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    struct hostent *hp;
+    int port;
+    int res;
+
+    if (ctxt == NULL)
+	return(-1);
+    if (ctxt->hostname == NULL)
+	return(-1);
+
+    /*
+     * do the blocking DNS query.
+     */
+    if (proxy)
+	hp = gethostbyname(proxy);
+    else
+	hp = gethostbyname(ctxt->hostname);
+    if (hp == NULL)
+        return(-1);
+
+    /*
+     * Prepare the socket
+     */
+    memset(&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr));
+    ctxt->ftpAddr.sin_family = AF_INET;
+    memcpy(&ctxt->ftpAddr.sin_addr, hp->h_addr_list[0], hp->h_length);
+    if (proxy) {
+        port = proxyPort;
+    } else {
+	port = ctxt->port;
+    }
+    if (port == 0)
+	port = 21;
+    ctxt->ftpAddr.sin_port = htons(port);
+    ctxt->controlFd = socket(AF_INET, SOCK_STREAM, 0);
+    if (ctxt->controlFd < 0)
+        return(-1);
+
+    /*
+     * Do the connect.
+     */
+    if (connect(ctxt->controlFd, (struct sockaddr *) &ctxt->ftpAddr,
+                sizeof(struct sockaddr_in)) < 0) {
+        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+        ctxt->controlFd = -1;
+	return(-1);
+    }
+
+    /*
+     * Wait for the HELLO from the server.
+     */
+    res = xmlNanoFTPGetResponse(ctxt);
+    if (res != 2) {
+        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+        ctxt->controlFd = -1;
+	return(-1);
+    }
+
+    /*
+     * State diagram for the login operation on the FTP server
+     *
+     * Reference: RFC 959
+     *
+     *                       1
+     * +---+   USER    +---+------------->+---+
+     * | B |---------->| W | 2       ---->| E |
+     * +---+           +---+------  |  -->+---+
+     *                  | |       | | |
+     *                3 | | 4,5   | | |
+     *    --------------   -----  | | |
+     *   |                      | | | |
+     *   |                      | | | |
+     *   |                 ---------  |
+     *   |               1|     | |   |
+     *   V                |     | |   |
+     * +---+   PASS    +---+ 2  |  ------>+---+
+     * |   |---------->| W |------------->| S |
+     * +---+           +---+   ---------->+---+
+     *                  | |   | |     |
+     *                3 | |4,5| |     |
+     *    --------------   --------   |
+     *   |                    | |  |  |
+     *   |                    | |  |  |
+     *   |                 -----------
+     *   |             1,3|   | |  |
+     *   V                |  2| |  |
+     * +---+   ACCT    +---+--  |   ----->+---+
+     * |   |---------->| W | 4,5 -------->| F |
+     * +---+           +---+------------->+---+
+     *
+     * Of course in case of using a proxy this get really nasty and is not
+     * standardized at all :-(
+     */
+    if (proxy) {
+        int len;
+	char buf[400];
+
+        if (proxyUser != NULL) {
+	    /*
+	     * We need proxy auth
+	     */
+#ifdef HAVE_SNPRINTF
+	    snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser);
+#else
+	    sprintf(buf, "USER %s\r\n", proxyUser);
+#endif
+            buf[sizeof(buf) - 1] = 0;
+            len = strlen(buf);
+#ifdef DEBUG_FTP
+	    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+	    res = send(ctxt->controlFd, buf, len, 0);
+	    if (res < 0) {
+		closesocket(ctxt->controlFd);
+		ctxt->controlFd = -1;
+	        return(res);
+	    }
+	    res = xmlNanoFTPGetResponse(ctxt);
+	    switch (res) {
+		case 2:
+		    if (proxyPasswd == NULL)
+			break;
+		case 3:
+		    if (proxyPasswd != NULL)
+#ifdef HAVE_SNPRINTF
+			snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd);
+#else
+			sprintf(buf, "PASS %s\r\n", proxyPasswd);
+#endif
+		    else
+#ifdef HAVE_SNPRINTF
+			snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n",
+			               hostname);
+#else
+			sprintf(buf, "PASS libxml@%s\r\n", hostname);
+#endif
+                    buf[sizeof(buf) - 1] = 0;
+                    len = strlen(buf);
+#ifdef DEBUG_FTP
+		    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+		    res = send(ctxt->controlFd, buf, len, 0);
+		    if (res < 0) {
+			closesocket(ctxt->controlFd);
+			ctxt->controlFd = -1;
+			return(res);
+		    }
+		    res = xmlNanoFTPGetResponse(ctxt);
+		    if (res > 3) {
+			closesocket(ctxt->controlFd);
+			ctxt->controlFd = -1;
+			return(-1);
+		    }
+		    break;
+		case 1:
+		    break;
+		case 4:
+		case 5:
+		case -1:
+		default:
+		    closesocket(ctxt->controlFd);
+		    ctxt->controlFd = -1;
+		    return(-1);
+	    }
+	}
+
+	/*
+	 * We assume we don't need more authentication to the proxy
+	 * and that it succeeded :-\
+	 */
+	switch (proxyType) {
+	    case 0:
+		/* we will try in seqence */
+	    case 1:
+		/* Using SITE command */
+#ifdef HAVE_SNPRINTF
+		snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname);
+#else
+		sprintf(buf, "SITE %s\r\n", ctxt->hostname);
+#endif
+                buf[sizeof(buf) - 1] = 0;
+                len = strlen(buf);
+#ifdef DEBUG_FTP
+		xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+		res = send(ctxt->controlFd, buf, len, 0);
+		if (res < 0) {
+		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+		    ctxt->controlFd = -1;
+		    return(res);
+		}
+		res = xmlNanoFTPGetResponse(ctxt);
+		if (res == 2) {
+		    /* we assume it worked :-\ 1 is error for SITE command */
+		    proxyType = 1;
+		    break;
+		}    
+		if (proxyType == 1) {
+		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+		    ctxt->controlFd = -1;
+		    return(-1);
+		}
+	    case 2:
+		/* USER user@host command */
+		if (ctxt->user == NULL)
+#ifdef HAVE_SNPRINTF
+		    snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n",
+			           ctxt->hostname);
+#else
+		    sprintf(buf, "USER anonymous@%s\r\n", ctxt->hostname);
+#endif
+		else
+#ifdef HAVE_SNPRINTF
+		    snprintf(buf, sizeof(buf), "USER %s@%s\r\n",
+			           ctxt->user, ctxt->hostname);
+#else
+		    sprintf(buf, "USER %s@%s\r\n",
+			           ctxt->user, ctxt->hostname);
+#endif
+                buf[sizeof(buf) - 1] = 0;
+                len = strlen(buf);
+#ifdef DEBUG_FTP
+		xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+		res = send(ctxt->controlFd, buf, len, 0);
+		if (res < 0) {
+		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+		    ctxt->controlFd = -1;
+		    return(res);
+		}
+		res = xmlNanoFTPGetResponse(ctxt);
+		if ((res == 1) || (res == 2)) {
+		    /* we assume it worked :-\ */
+		    proxyType = 2;
+		    return(0);
+		}    
+		if (ctxt->passwd == NULL)
+#ifdef HAVE_SNPRINTF
+		    snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", hostname);
+#else
+		    sprintf(buf, "PASS libxml@%s\r\n", hostname);
+#endif
+		else
+#ifdef HAVE_SNPRINTF
+		    snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd);
+#else
+		    sprintf(buf, "PASS %s\r\n", ctxt->passwd);
+#endif
+                buf[sizeof(buf) - 1] = 0;
+                len = strlen(buf);
+#ifdef DEBUG_FTP
+		xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+		res = send(ctxt->controlFd, buf, len, 0);
+		if (res < 0) {
+		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+		    ctxt->controlFd = -1;
+		    return(res);
+		}
+		res = xmlNanoFTPGetResponse(ctxt);
+		if ((res == 1) || (res == 2)) {
+		    /* we assume it worked :-\ */
+		    proxyType = 2;
+		    return(0);
+		}
+		if (proxyType == 2) {
+		    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+		    ctxt->controlFd = -1;
+		    return(-1);
+		}
+	    case 3:
+		/*
+		 * If you need support for other Proxy authentication scheme
+		 * send the code or at least the sequence in use.
+		 */
+	    default:
+		closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+		ctxt->controlFd = -1;
+		return(-1);
+	}
+    }
+    /*
+     * Non-proxy handling.
+     */
+    res = xmlNanoFTPSendUser(ctxt);
+    if (res < 0) {
+        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+        ctxt->controlFd = -1;
+	return(-1);
+    }
+    res = xmlNanoFTPGetResponse(ctxt);
+    switch (res) {
+	case 2:
+	    return(0);
+	case 3:
+	    break;
+	case 1:
+	case 4:
+	case 5:
+        case -1:
+	default:
+	    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+	    ctxt->controlFd = -1;
+	    return(-1);
+    }
+    res = xmlNanoFTPSendPasswd(ctxt);
+    if (res < 0) {
+        closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+        ctxt->controlFd = -1;
+	return(-1);
+    }
+    res = xmlNanoFTPGetResponse(ctxt);
+    switch (res) {
+	case 2:
+	    break;
+	case 3:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "FTP server asking for ACCNT on anonymous\n");
+	case 1:
+	case 4:
+	case 5:
+        case -1:
+	default:
+	    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+	    ctxt->controlFd = -1;
+	    return(-1);
+    }
+
+    return(0);
+}
+
+/**
+ * xmlNanoFTPConnectTo:
+ * @server:  an FTP server name
+ * @port:  the port (use 21 if 0)
+ *
+ * Tries to open a control connection to the given server/port
+ *
+ * Returns an fTP context or NULL if it failed
+ */
+
+void*
+xmlNanoFTPConnectTo(const char *server, int port) {
+    xmlNanoFTPCtxtPtr ctxt;
+    int res;
+
+    xmlNanoFTPInit();
+    if (server == NULL) 
+	return(NULL);
+    ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(NULL);
+    ctxt->hostname = xmlMemStrdup(server);
+    if (port != 0)
+	ctxt->port = port;
+    res = xmlNanoFTPConnect(ctxt);
+    if (res < 0) {
+	xmlNanoFTPFreeCtxt(ctxt);
+	return(NULL);
+    }
+    return(ctxt);
+}
+
+/**
+ * xmlNanoFTPCwd:
+ * @ctx:  an FTP context
+ * @directory:  a directory on the server
+ *
+ * Tries to change the remote directory
+ *
+ * Returns -1 incase of error, 1 if CWD worked, 0 if it failed
+ */
+
+int
+xmlNanoFTPCwd(void *ctx, char *directory) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[400];
+    int len;
+    int res;
+
+    /*
+     * Expected response code for CWD:
+     *
+     * CWD
+     *     250
+     *     500, 501, 502, 421, 530, 550
+     */
+#ifdef HAVE_SNPRINTF
+    snprintf(buf, sizeof(buf), "CWD %s\r\n", directory);
+#else
+    sprintf(buf, "CWD %s\r\n", directory);
+#endif
+    buf[sizeof(buf) - 1] = 0;
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    if (res < 0) return(res);
+    res = xmlNanoFTPGetResponse(ctxt);
+    if (res == 4) {
+	return(-1);
+    }
+    if (res == 2) return(1);
+    if (res == 5) {
+	return(0);
+    }
+    return(0);
+}
+
+/**
+ * xmlNanoFTPGetConnection:
+ * @ctx:  an FTP context
+ *
+ * Try to open a data connection to the server. Currently only
+ * passive mode is supported.
+ *
+ * Returns -1 incase of error, 0 otherwise
+ */
+
+int
+xmlNanoFTPGetConnection(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[200], *cur;
+    int len, i;
+    int res;
+    unsigned char ad[6], *adp, *portp;
+    unsigned int temp[6];
+    struct sockaddr_in dataAddr;
+    SOCKLEN_T dataAddrLen;
+
+    ctxt->dataFd = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
+    if (ctxt->dataFd < 0) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNanoFTPGetConnection: failed to create socket\n");
+	return(-1);
+    }
+    dataAddrLen = sizeof(dataAddr);
+    memset(&dataAddr, 0, dataAddrLen);
+    dataAddr.sin_family = AF_INET;
+
+    if (ctxt->passive) {
+	sprintf(buf, "PASV\r\n");
+        len = strlen(buf);
+#ifdef DEBUG_FTP
+	xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+	res = send(ctxt->controlFd, buf, len, 0);
+	if (res < 0) {
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return(res);
+	}
+        res = xmlNanoFTPReadResponse(ctx);
+	if (res != 2) {
+	    if (res == 5) {
+	        closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+		return(-1);
+	    } else {
+		/*
+		 * retry with an active connection
+		 */
+	        closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	        ctxt->passive = 0;
+	    }
+	}
+	cur = &ctxt->controlBuf[ctxt->controlBufAnswer]; 
+	while (((*cur < '0') || (*cur > '9')) && *cur != '\0') cur++;
+	if (sscanf(cur, "%u,%u,%u,%u,%u,%u", &temp[0], &temp[1], &temp[2],
+	            &temp[3], &temp[4], &temp[5]) != 6) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Invalid answer to PASV\n");
+	    if (ctxt->dataFd != -1) {
+		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    }
+	    return(-1);
+	}
+	for (i=0; i<6; i++) ad[i] = (unsigned char) (temp[i] & 0xff);
+	memcpy(&dataAddr.sin_addr, &ad[0], 4);
+	memcpy(&dataAddr.sin_port, &ad[4], 2);
+	if (connect(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Failed to create a data connection\n");
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return (-1);
+	}
+    } else {
+        getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
+	dataAddr.sin_port = 0;
+	if (bind(ctxt->dataFd, (struct sockaddr *) &dataAddr, dataAddrLen) < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Failed to bind a port\n");
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return (-1);
+	}
+        getsockname(ctxt->dataFd, (struct sockaddr *) &dataAddr, &dataAddrLen);
+
+	if (listen(ctxt->dataFd, 1) < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Could not listen on port %d\n",
+	            ntohs(dataAddr.sin_port));
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return (-1);
+	}
+	adp = (unsigned char *) &dataAddr.sin_addr;
+	portp = (unsigned char *) &dataAddr.sin_port;
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "PORT %d,%d,%d,%d,%d,%d\r\n",
+	       adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
+	       portp[0] & 0xff, portp[1] & 0xff);
+#else
+	sprintf(buf, "PORT %d,%d,%d,%d,%d,%d\r\n",
+	       adp[0] & 0xff, adp[1] & 0xff, adp[2] & 0xff, adp[3] & 0xff,
+	       portp[0] & 0xff, portp[1] & 0xff);
+#endif
+        buf[sizeof(buf) - 1] = 0;
+        len = strlen(buf);
+#ifdef DEBUG_FTP
+	xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+
+	res = send(ctxt->controlFd, buf, len, 0);
+	if (res < 0) {
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return(res);
+	}
+        res = xmlNanoFTPGetResponse(ctxt);
+	if (res != 2) {
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return(-1);
+        }
+    }
+    return(ctxt->dataFd);
+    
+}
+
+/**
+ * xmlNanoFTPCloseConnection:
+ * @ctx:  an FTP context
+ *
+ * Close the data connection from the server
+ *
+ * Returns -1 incase of error, 0 otherwise
+ */
+
+int
+xmlNanoFTPCloseConnection(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    int res;
+    fd_set rfd, efd;
+    struct timeval tv;
+
+    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+    tv.tv_sec = 15;
+    tv.tv_usec = 0;
+    FD_ZERO(&rfd);
+    FD_SET(ctxt->controlFd, &rfd);
+    FD_ZERO(&efd);
+    FD_SET(ctxt->controlFd, &efd);
+    res = select(ctxt->controlFd + 1, &rfd, NULL, &efd, &tv);
+    if (res < 0) {
+#ifdef DEBUG_FTP
+	perror("select");
+#endif
+	closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+	return(-1);
+    }
+    if (res == 0) {
+#ifdef DEBUG_FTP
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNanoFTPCloseConnection: timeout\n");
+#endif
+	closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+    } else {
+	res = xmlNanoFTPGetResponse(ctxt);
+	if (res != 2) {
+	    closesocket(ctxt->controlFd); ctxt->controlFd = -1;
+	    return(-1);
+	}
+    }
+    return(0);
+}
+
+/**
+ * xmlNanoFTPParseList:
+ * @list:  some data listing received from the server
+ * @callback:  the user callback
+ * @userData:  the user callback data
+ *
+ * Parse at most one entry from the listing. 
+ *
+ * Returns -1 incase of error, the lenght of data parsed otherwise
+ */
+
+static int
+xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) {
+    const char *cur = list;
+    char filename[151];
+    char attrib[11];
+    char owner[11];
+    char group[11];
+    char month[4];
+    int year = 0;
+    int minute = 0;
+    int hour = 0;
+    int day = 0;
+    unsigned long size = 0;
+    int links = 0;
+    int i;
+
+    if (!strncmp(cur, "total", 5)) {
+        cur += 5;
+	while (*cur == ' ') cur++;
+	while ((*cur >= '0') && (*cur <= '9'))
+	    links = (links * 10) + (*cur++ - '0');
+	while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
+	    cur++;
+	return(cur - list);
+    } else if (*list == '+') {
+	return(0);
+    } else {
+	while ((*cur == ' ') || (*cur == '\n')  || (*cur == '\r'))
+	    cur++;
+	if (*cur == 0) return(0);
+	i = 0;
+	while (*cur != ' ') {
+	    if (i < 10) 
+		attrib[i++] = *cur;
+	    cur++;
+	    if (*cur == 0) return(0);
+	}
+	attrib[10] = 0;
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	while ((*cur >= '0') && (*cur <= '9'))
+	    links = (links * 10) + (*cur++ - '0');
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	i = 0;
+	while (*cur != ' ') {
+	    if (i < 10) 
+		owner[i++] = *cur;
+	    cur++;
+	    if (*cur == 0) return(0);
+	}
+	owner[i] = 0;
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	i = 0;
+	while (*cur != ' ') {
+	    if (i < 10) 
+		group[i++] = *cur;
+	    cur++;
+	    if (*cur == 0) return(0);
+	}
+	group[i] = 0;
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	while ((*cur >= '0') && (*cur <= '9'))
+	    size = (size * 10) + (*cur++ - '0');
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	i = 0;
+	while (*cur != ' ') {
+	    if (i < 3)
+		month[i++] = *cur;
+	    cur++;
+	    if (*cur == 0) return(0);
+	}
+	month[i] = 0;
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+        while ((*cur >= '0') && (*cur <= '9'))
+	    day = (day * 10) + (*cur++ - '0');
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	if ((cur[1] == 0) || (cur[2] == 0)) return(0);
+	if ((cur[1] == ':') || (cur[2] == ':')) {
+	    while ((*cur >= '0') && (*cur <= '9'))
+		hour = (hour * 10) + (*cur++ - '0');
+	    if (*cur == ':') cur++;
+	    while ((*cur >= '0') && (*cur <= '9'))
+		minute = (minute * 10) + (*cur++ - '0');
+	} else {
+	    while ((*cur >= '0') && (*cur <= '9'))
+		year = (year * 10) + (*cur++ - '0');
+	}
+	while (*cur == ' ') cur++;
+	if (*cur == 0) return(0);
+	i = 0;
+	while ((*cur != '\n')  && (*cur != '\r')) {
+	    if (i < 150)
+		filename[i++] = *cur;
+	    cur++;
+	    if (*cur == 0) return(0);
+	}
+	filename[i] = 0;
+	if ((*cur != '\n') && (*cur != '\r'))
+	    return(0);
+	while ((*cur == '\n')  || (*cur == '\r'))
+	    cur++;
+    }
+    if (callback != NULL) {
+        callback(userData, filename, attrib, owner, group, size, links,
+		 year, month, day, hour, minute);
+    }
+    return(cur - list);
+}
+
+/**
+ * xmlNanoFTPList:
+ * @ctx:  an FTP context
+ * @callback:  the user callback
+ * @userData:  the user callback data
+ * @filename:  optional files to list
+ *
+ * Do a listing on the server. All files info are passed back
+ * in the callbacks.
+ *
+ * Returns -1 incase of error, 0 otherwise
+ */
+
+int
+xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData,
+	       char *filename) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[4096 + 1];
+    int len, res;
+    int index = 0, base;
+    fd_set rfd, efd;
+    struct timeval tv;
+
+    if (filename == NULL) {
+        if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
+	    return(-1);
+	ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
+	if (ctxt->dataFd == -1)
+	    return(-1);
+	sprintf(buf, "LIST -L\r\n");
+    } else {
+	if (filename[0] != '/') {
+	    if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1)
+		return(-1);
+	}
+	ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
+	if (ctxt->dataFd == -1)
+	    return(-1);
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename);
+#else
+	sprintf(buf, "LIST -L %s\r\n", filename);
+#endif
+    }
+    buf[sizeof(buf) - 1] = 0;
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    if (res < 0) {
+	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	return(res);
+    }
+    res = xmlNanoFTPReadResponse(ctxt);
+    if (res != 1) {
+	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	return(-res);
+    }
+
+    do {
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	FD_ZERO(&rfd);
+	FD_SET(ctxt->dataFd, &rfd);
+	FD_ZERO(&efd);
+	FD_SET(ctxt->dataFd, &efd);
+	res = select(ctxt->dataFd + 1, &rfd, NULL, &efd, &tv);
+	if (res < 0) {
+#ifdef DEBUG_FTP
+	    perror("select");
+#endif
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return(-1);
+	}
+	if (res == 0) {
+	    res = xmlNanoFTPCheckResponse(ctxt);
+	    if (res < 0) {
+		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+		ctxt->dataFd = -1;
+		return(-1);
+	    }
+	    if (res == 2) {
+		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+		return(0);
+	    }
+
+	    continue;
+	}
+
+	if ((len = recv(ctxt->dataFd, &buf[index], sizeof(buf) - (index + 1), 0)) < 0) {
+#ifdef DEBUG_FTP
+	    perror("recv");
+#endif
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    ctxt->dataFd = -1;
+	    return(-1);
+	}
+#ifdef DEBUG_FTP
+        write(1, &buf[index], len);
+#endif
+	index += len;
+	buf[index] = 0;
+	base = 0;
+	do {
+	    res = xmlNanoFTPParseList(&buf[base], callback, userData);
+	    base += res;
+	} while (res > 0);
+
+	memmove(&buf[0], &buf[base], index - base);
+	index -= base;
+    } while (len != 0);
+    xmlNanoFTPCloseConnection(ctxt);
+    return(0);
+}
+
+/**
+ * xmlNanoFTPGetSocket:
+ * @ctx:  an FTP context
+ * @filename:  the file to retrieve (or NULL if path is in context).
+ *
+ * Initiate fetch of the given file from the server.
+ *
+ * Returns the socket for the data connection, or <0 in case of error
+ */
+
+
+int
+xmlNanoFTPGetSocket(void *ctx, const char *filename) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[300];
+    int res, len;
+    if ((filename == NULL) && (ctxt->path == NULL))
+	return(-1);
+    ctxt->dataFd = xmlNanoFTPGetConnection(ctxt);
+    if (ctxt->dataFd == -1)
+	return(-1);
+
+    sprintf(buf, "TYPE I\r\n");
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    if (res < 0) {
+	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	return(res);
+    }
+    res = xmlNanoFTPReadResponse(ctxt);
+    if (res != 2) {
+	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	return(-res);
+    }
+    if (filename == NULL)
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path);
+#else
+	sprintf(buf, "RETR %s\r\n", ctxt->path);
+#endif
+    else
+#ifdef HAVE_SNPRINTF
+	snprintf(buf, sizeof(buf), "RETR %s\r\n", filename);
+#else
+	sprintf(buf, "RETR %s\r\n", filename);
+#endif
+    buf[sizeof(buf) - 1] = 0;
+    len = strlen(buf);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, buf);
+#endif
+    res = send(ctxt->controlFd, buf, len, 0);
+    if (res < 0) {
+	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	return(res);
+    }
+    res = xmlNanoFTPReadResponse(ctxt);
+    if (res != 1) {
+	closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	return(-res);
+    }
+    return(ctxt->dataFd);
+}
+
+/**
+ * xmlNanoFTPGet:
+ * @ctx:  an FTP context
+ * @callback:  the user callback
+ * @userData:  the user callback data
+ * @filename:  the file to retrieve
+ *
+ * Fetch the given file from the server. All data are passed back
+ * in the callbacks. The last callback has a size of 0 block.
+ *
+ * Returns -1 incase of error, 0 otherwise
+ */
+
+int
+xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData,
+	      const char *filename) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+    char buf[4096];
+    int len = 0, res;
+    fd_set rfd;
+    struct timeval tv;
+
+    if ((filename == NULL) && (ctxt->path == NULL))
+	return(-1);
+    if (callback == NULL)
+	return(-1);
+    if (xmlNanoFTPGetSocket(ctxt, filename) < 0)
+	return(-1);
+
+    do {
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+	FD_ZERO(&rfd);
+	FD_SET(ctxt->dataFd, &rfd);
+	res = select(ctxt->dataFd + 1, &rfd, NULL, NULL, &tv);
+	if (res < 0) {
+#ifdef DEBUG_FTP
+	    perror("select");
+#endif
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return(-1);
+	}
+	if (res == 0) {
+	    res = xmlNanoFTPCheckResponse(ctxt);
+	    if (res < 0) {
+		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+		ctxt->dataFd = -1;
+		return(-1);
+	    }
+	    if (res == 2) {
+		closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+		return(0);
+	    }
+
+	    continue;
+	}
+	if ((len = recv(ctxt->dataFd, buf, sizeof(buf), 0)) < 0) {
+	    callback(userData, buf, len);
+	    closesocket(ctxt->dataFd); ctxt->dataFd = -1;
+	    return(-1);
+	}
+	callback(userData, buf, len);
+    } while (len != 0);
+
+    return(xmlNanoFTPCloseConnection(ctxt));
+}
+
+/**
+ * xmlNanoFTPRead:
+ * @ctx:  the FTP context
+ * @dest:  a buffer
+ * @len:  the buffer length
+ *
+ * This function tries to read @len bytes from the existing FTP connection
+ * and saves them in @dest. This is a blocking call.
+ *
+ * Returns the number of byte read. 0 is an indication of an end of connection.
+ *         -1 indicates a parameter error.
+ */
+int
+xmlNanoFTPRead(void *ctx, void *dest, int len) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+
+    if (ctx == NULL) return(-1);
+    if (ctxt->dataFd < 0) return(0);
+    if (dest == NULL) return(-1);
+    if (len <= 0) return(0);
+
+    len = recv(ctxt->dataFd, dest, len, 0);
+#ifdef DEBUG_FTP
+    xmlGenericError(xmlGenericErrorContext, "Recvd %d bytes\n", len);
+#endif
+    if (len <= 0) {
+	xmlNanoFTPCloseConnection(ctxt);
+    }
+    return(len);
+}
+
+/**
+ * xmlNanoFTPOpen:
+ * @URL: the URL to the resource
+ *
+ * Start to fetch the given ftp:// resource
+ *
+ * Returns an FTP context, or NULL 
+ */
+
+void*
+xmlNanoFTPOpen(const char *URL) {
+    xmlNanoFTPCtxtPtr ctxt;
+    int sock;
+
+    xmlNanoFTPInit();
+    if (URL == NULL) return(NULL);
+    if (strncmp("ftp://", URL, 6)) return(NULL);
+
+    ctxt = (xmlNanoFTPCtxtPtr) xmlNanoFTPNewCtxt(URL);
+    if (ctxt == NULL) return(NULL);
+    if (xmlNanoFTPConnect(ctxt) < 0) {
+	xmlNanoFTPFreeCtxt(ctxt);
+	return(NULL);
+    }
+    sock = xmlNanoFTPGetSocket(ctxt, ctxt->path);
+    if (sock < 0) {
+	xmlNanoFTPFreeCtxt(ctxt);
+	return(NULL);
+    }
+    return(ctxt);
+}
+
+/**
+ * xmlNanoFTPClose:
+ * @ctx: an FTP context
+ *
+ * Close the connection and both control and transport
+ *
+ * Returns -1 incase of error, 0 otherwise
+ */
+
+int
+xmlNanoFTPClose(void *ctx) {
+    xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx;
+
+    if (ctxt == NULL)
+	return(-1);
+
+    if (ctxt->dataFd >= 0) {
+	closesocket(ctxt->dataFd);
+	ctxt->dataFd = -1;
+    }
+    if (ctxt->controlFd >= 0) {
+	xmlNanoFTPQuit(ctxt);
+	closesocket(ctxt->controlFd);
+	ctxt->controlFd = -1;
+    }
+    xmlNanoFTPFreeCtxt(ctxt);
+    return(0);
+}
+
+#ifdef STANDALONE
+/************************************************************************
+ * 									*
+ * 			Basic test in Standalone mode			*
+ * 									*
+ ************************************************************************/
+void ftpList(void *userData, const char *filename, const char* attrib,
+	     const char *owner, const char *group, unsigned long size, int links,
+	     int year, const char *month, int day, int hour, int minute) {
+    xmlGenericError(xmlGenericErrorContext,
+	    "%s %s %s %ld %s\n", attrib, owner, group, size, filename);
+}
+void ftpData(void *userData, const char *data, int len) {
+    if (userData == NULL) return;
+    if (len <= 0) {
+	fclose(userData);
+	return;
+    }	
+    fwrite(data, len, 1, userData);
+}
+
+int main(int argc, char **argv) {
+    void *ctxt;
+    FILE *output;
+    char *tstfile = NULL;
+
+    xmlNanoFTPInit();
+    if (argc > 1) {
+	ctxt = xmlNanoFTPNewCtxt(argv[1]);
+	if (xmlNanoFTPConnect(ctxt) < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Couldn't connect to %s\n", argv[1]);
+	    exit(1);
+	}
+	if (argc > 2)
+	    tstfile = argv[2];
+    } else
+	ctxt = xmlNanoFTPConnectTo("localhost", 0);
+    if (ctxt == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"Couldn't connect to localhost\n");
+        exit(1);
+    }
+    xmlNanoFTPList(ctxt, ftpList, NULL, tstfile);
+    output = fopen("/tmp/tstdata", "w");
+    if (output != NULL) {
+	if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0)
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Failed to get file\n");
+	
+    }
+    xmlNanoFTPClose(ctxt);
+    xmlMemoryDump();
+    exit(0);
+}
+#endif /* STANDALONE */
+#else /* !LIBXML_FTP_ENABLED */
+#ifdef STANDALONE
+#include <stdio.h>
+int main(int argc, char **argv) {
+    xmlGenericError(xmlGenericErrorContext,
+	    "%s : FTP support not compiled in\n", argv[0]);
+    return(0);
+}
+#endif /* STANDALONE */
+#endif /* LIBXML_FTP_ENABLED */
diff --git a/nanoftp.h b/nanoftp.h
new file mode 100644
index 0000000..5346528
--- /dev/null
+++ b/nanoftp.h
@@ -0,0 +1,110 @@
+/*
+ * nanohttp.c: minimalist FTP implementation to fetch external subsets.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+ 
+#ifndef __NANO_FTP_H__
+#define __NANO_FTP_H__
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_FTP_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * ftpListCallback: 
+ * @userData:  user provided data for the callback
+ * @filename:  the file name (including "->" when links are shown)
+ * @attrib:  the attribute string
+ * @owner:  the owner string
+ * @group:  the group string
+ * @size:  the file size
+ * @links:  the link count
+ * @year:  the year
+ * @month:  the month
+ * @day:  the day
+ * @hour:  the hour
+ * @minute:  the minute
+ *
+ * A callback for the xmlNanoFTPList command
+ * Note that only one of year and day:minute are specified
+ */
+typedef void (*ftpListCallback) (void *userData,
+	                         const char *filename, const char* attrib,
+	                         const char *owner, const char *group,
+				 unsigned long size, int links, int year,
+				 const char *month, int day, int hour,
+				 int minute);
+/**
+ * ftpDataCallback: 
+ * A callback for the xmlNanoFTPGet command
+ */
+typedef void (*ftpDataCallback) (void *userData, const char *data, int len);
+
+/*
+ * Init
+ */
+void	xmlNanoFTPInit		(void);
+void	xmlNanoFTPCleanup	(void);
+
+/*
+ * Creating/freeing contexts
+ */
+void *	xmlNanoFTPNewCtxt	(const char *URL);
+void	xmlNanoFTPFreeCtxt	(void * ctx);
+void * 	xmlNanoFTPConnectTo	(const char *server,
+				 int port);
+/*
+ * Opening/closing session connections
+ */
+void * 	xmlNanoFTPOpen		(const char *URL);
+int	xmlNanoFTPConnect	(void *ctx);
+int	xmlNanoFTPClose		(void *ctx);
+int	xmlNanoFTPQuit		(void *ctx);
+void	xmlNanoFTPScanProxy	(const char *URL);
+void	xmlNanoFTPProxy		(const char *host,
+				 int port,
+				 const char *user,
+				 const char *passwd,
+				 int type);
+int	xmlNanoFTPUpdateURL	(void *ctx,
+				 const char *URL);
+
+/*
+ * Rathern internal commands
+ */
+int	xmlNanoFTPGetResponse	(void *ctx);
+int	xmlNanoFTPCheckResponse	(void *ctx);
+
+/*
+ * CD/DIR/GET handlers
+ */
+int	xmlNanoFTPCwd		(void *ctx,
+				 char *directory);
+
+int	xmlNanoFTPGetConnection	(void *ctx);
+int	xmlNanoFTPCloseConnection(void *ctx);
+int	xmlNanoFTPList		(void *ctx,
+				 ftpListCallback callback,
+				 void *userData,
+				 char *filename);
+int	xmlNanoFTPGetSocket	(void *ctx,
+				 const char *filename);
+int	xmlNanoFTPGet		(void *ctx,
+				 ftpDataCallback callback,
+				 void *userData,
+				 const char *filename);
+int	xmlNanoFTPRead		(void *ctx,
+				 void *dest,
+				 int len);
+
+#ifdef __cplusplus
+}
+#endif /* LIBXML_FTP_ENABLED */
+#endif
+#endif /* __NANO_FTP_H__ */
diff --git a/nanohttp.c b/nanohttp.c
new file mode 100644
index 0000000..cf30c53
--- /dev/null
+++ b/nanohttp.c
@@ -0,0 +1,1202 @@
+/*
+ * nanohttp.c: minimalist HTTP GET implementation to fetch external subsets.
+ *             focuses on size, streamability, reentrancy and portability
+ *
+ * This is clearly not a general purpose HTTP implementation
+ * If you look for one, check:
+ *         http://www.w3.org/Library/
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+ 
+/* TODO add compression support, Send the Accept- , and decompress on the
+        fly with ZLIB if found at compile-time */
+
+#ifdef WIN32
+#define INCLUDE_WINSOCK
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <libxml/xmlversion.h>
+
+#ifdef LIBXML_HTTP_ENABLED
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h> 
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+#ifdef HAVE_STRINGS_H
+#include <strings.h>
+#endif
+#ifdef SUPPORT_IP6
+#include <resolv.h>
+#endif
+
+#ifdef VMS
+#include <stropts>
+#define SOCKLEN_T unsigned int
+#define SOCKET int
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h> /* for xmlStr(n)casecmp() */
+#include <libxml/nanohttp.h>
+
+/**
+ * A couple portability macros
+ */
+#ifndef _WINSOCKAPI_
+#define closesocket(s) close(s)
+#define SOCKET int
+#endif
+
+#ifdef STANDALONE
+#define DEBUG_HTTP
+#define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
+#define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
+#endif
+
+#define XML_NANO_HTTP_MAX_REDIR	10
+
+#define XML_NANO_HTTP_CHUNK	4096
+
+#define XML_NANO_HTTP_CLOSED	0
+#define XML_NANO_HTTP_WRITE	1
+#define XML_NANO_HTTP_READ	2
+#define XML_NANO_HTTP_NONE	4
+
+typedef struct xmlNanoHTTPCtxt {
+    char *protocol;	/* the protocol name */
+    char *hostname;	/* the host name */
+    int port;		/* the port */
+    char *path;		/* the path within the URL */
+    SOCKET fd;		/* the file descriptor for the socket */
+    int state;		/* WRITE / READ / CLOSED */
+    char *out;		/* buffer sent (zero terminated) */
+    char *outptr;	/* index within the buffer sent */
+    char *in;		/* the receiving buffer */
+    char *content;	/* the start of the content */
+    char *inptr;	/* the next byte to read from network */
+    char *inrptr;	/* the next byte to give back to the client */
+    int inlen;		/* len of the input buffer */
+    int last;		/* return code for last operation */
+    int returnValue;	/* the protocol return value */
+    char *contentType;	/* the MIME type for the input */
+    char *location;	/* the new URL in case of redirect */
+    char *authHeader;	/* contents of {WWW,Proxy}-Authenticate header */
+} xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr;
+
+static int initialized = 0;
+static char *proxy = NULL;	 /* the proxy name if any */
+static int proxyPort;	/* the proxy port if any */
+static unsigned int timeout = 60;/* the select() timeout in seconds */
+
+/**
+ * A portability function
+ */
+int socket_errno(void) {
+#ifdef _WINSOCKAPI_
+    return(WSAGetLastError());
+#else
+    return(errno);
+#endif
+}
+
+/**
+ * xmlNanoHTTPInit:
+ *
+ * Initialize the HTTP protocol layer.
+ * Currently it just checks for proxy informations
+ */
+
+void
+xmlNanoHTTPInit(void) {
+    const char *env;
+#ifdef _WINSOCKAPI_
+    WSADATA wsaData;    
+#endif
+
+    if (initialized)
+	return;
+
+#ifdef _WINSOCKAPI_
+    if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0)
+	return;
+#endif
+
+    if (proxy == NULL) {
+	proxyPort = 80;
+	env = getenv("no_proxy");
+	if (env != NULL)
+	    goto done;
+	env = getenv("http_proxy");
+	if (env != NULL) {
+	    xmlNanoHTTPScanProxy(env);
+	    goto done;
+	}
+	env = getenv("HTTP_PROXY");
+	if (env != NULL) {
+	    xmlNanoHTTPScanProxy(env);
+	    goto done;
+	}
+    }
+done:
+    initialized = 1;
+}
+
+/**
+ * xmlNanoHTTPClenup:
+ *
+ * Cleanup the HTTP protocol layer.
+ */
+
+void
+xmlNanoHTTPCleanup(void) {
+    if (proxy != NULL)
+	xmlFree(proxy);
+#ifdef _WINSOCKAPI_
+    if (initialized)
+	WSACleanup();
+#endif
+    initialized = 0;
+    return;
+}
+
+/**
+ * xmlNanoHTTPTimeout:
+ * @delay:  the delay in seconds
+ *
+ * Set the HTTP timeout, (default is 60secs).  0 means immediate
+ * return, while -1 infinite.
+ */
+
+void
+xmlNanoHTTPTimeout(int delay) {
+    timeout = (unsigned int) delay;
+}
+
+/**
+ * xmlNanoHTTPScanURL:
+ * @ctxt:  an HTTP context
+ * @URL:  The URL used to initialize the context
+ *
+ * (Re)Initialize an HTTP context by parsing the URL and finding
+ * the protocol host port and path it indicates.
+ */
+
+static void
+xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) {
+    const char *cur = URL;
+    char buf[4096];
+    int index = 0;
+    int port = 0;
+
+    if (ctxt->protocol != NULL) { 
+        xmlFree(ctxt->protocol);
+	ctxt->protocol = NULL;
+    }
+    if (ctxt->hostname != NULL) { 
+        xmlFree(ctxt->hostname);
+	ctxt->hostname = NULL;
+    }
+    if (ctxt->path != NULL) { 
+        xmlFree(ctxt->path);
+	ctxt->path = NULL;
+    }
+    if (URL == NULL) return;
+    buf[index] = 0;
+    while (*cur != 0) {
+        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
+	    buf[index] = 0;
+	    ctxt->protocol = xmlMemStrdup(buf);
+	    index = 0;
+            cur += 3;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0) return;
+
+    buf[index] = 0;
+    while (1) {
+        if (cur[0] == ':') {
+	    buf[index] = 0;
+	    ctxt->hostname = xmlMemStrdup(buf);
+	    index = 0;
+	    cur += 1;
+	    while ((*cur >= '0') && (*cur <= '9')) {
+	        port *= 10;
+		port += *cur - '0';
+		cur++;
+	    }
+	    if (port != 0) ctxt->port = port;
+	    while ((cur[0] != '/') && (*cur != 0)) 
+	        cur++;
+	    break;
+	}
+        if ((*cur == '/') || (*cur == 0)) {
+	    buf[index] = 0;
+	    ctxt->hostname = xmlMemStrdup(buf);
+	    index = 0;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0) 
+        ctxt->path = xmlMemStrdup("/");
+    else {
+        index = 0;
+        buf[index] = 0;
+	while (*cur != 0)
+	    buf[index++] = *cur++;
+	buf[index] = 0;
+	ctxt->path = xmlMemStrdup(buf);
+    }	
+}
+
+/**
+ * xmlNanoHTTPScanProxy:
+ * @URL:  The proxy URL used to initialize the proxy context
+ *
+ * (Re)Initialize the HTTP Proxy context by parsing the URL and finding
+ * the protocol host port it indicates.
+ * Should be like http://myproxy/ or http://myproxy:3128/
+ * A NULL URL cleans up proxy informations.
+ */
+
+void
+xmlNanoHTTPScanProxy(const char *URL) {
+    const char *cur = URL;
+    char buf[4096];
+    int index = 0;
+    int port = 0;
+
+    if (proxy != NULL) { 
+        xmlFree(proxy);
+	proxy = NULL;
+    }
+    if (proxyPort != 0) { 
+	proxyPort = 0;
+    }
+#ifdef DEBUG_HTTP
+    if (URL == NULL)
+	xmlGenericError(xmlGenericErrorContext,
+		"Removing HTTP proxy info\n");
+    else
+	xmlGenericError(xmlGenericErrorContext,
+		"Using HTTP proxy %s\n", URL);
+#endif
+    if (URL == NULL) return;
+    buf[index] = 0;
+    while (*cur != 0) {
+        if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) {
+	    buf[index] = 0;
+	    index = 0;
+            cur += 3;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+    if (*cur == 0) return;
+
+    buf[index] = 0;
+    while (1) {
+        if (cur[0] == ':') {
+	    buf[index] = 0;
+	    proxy = xmlMemStrdup(buf);
+	    index = 0;
+	    cur += 1;
+	    while ((*cur >= '0') && (*cur <= '9')) {
+	        port *= 10;
+		port += *cur - '0';
+		cur++;
+	    }
+	    if (port != 0) proxyPort = port;
+	    while ((cur[0] != '/') && (*cur != 0)) 
+	        cur++;
+	    break;
+	}
+        if ((*cur == '/') || (*cur == 0)) {
+	    buf[index] = 0;
+	    proxy = xmlMemStrdup(buf);
+	    index = 0;
+	    break;
+	}
+	buf[index++] = *cur++;
+    }
+}
+
+/**
+ * xmlNanoHTTPNewCtxt:
+ * @URL:  The URL used to initialize the context
+ *
+ * Allocate and initialize a new HTTP context.
+ *
+ * Returns an HTTP context or NULL in case of error.
+ */
+
+static xmlNanoHTTPCtxtPtr
+xmlNanoHTTPNewCtxt(const char *URL) {
+    xmlNanoHTTPCtxtPtr ret;
+
+    ret = (xmlNanoHTTPCtxtPtr) xmlMalloc(sizeof(xmlNanoHTTPCtxt));
+    if (ret == NULL) return(NULL);
+
+    memset(ret, 0, sizeof(xmlNanoHTTPCtxt));
+    ret->port = 80;
+    ret->returnValue = 0;
+    ret->fd = -1;
+
+    xmlNanoHTTPScanURL(ret, URL);
+
+    return(ret);
+}
+
+/**
+ * xmlNanoHTTPFreeCtxt:
+ * @ctxt:  an HTTP context
+ *
+ * Frees the context after closing the connection.
+ */
+
+static void
+xmlNanoHTTPFreeCtxt(xmlNanoHTTPCtxtPtr ctxt) {
+    if (ctxt == NULL) return;
+    if (ctxt->hostname != NULL) xmlFree(ctxt->hostname);
+    if (ctxt->protocol != NULL) xmlFree(ctxt->protocol);
+    if (ctxt->path != NULL) xmlFree(ctxt->path);
+    if (ctxt->out != NULL) xmlFree(ctxt->out);
+    if (ctxt->in != NULL) xmlFree(ctxt->in);
+    if (ctxt->contentType != NULL) xmlFree(ctxt->contentType);
+    if (ctxt->location != NULL) xmlFree(ctxt->location);
+    if (ctxt->authHeader != NULL) xmlFree(ctxt->authHeader);
+    ctxt->state = XML_NANO_HTTP_NONE;
+    if (ctxt->fd >= 0) closesocket(ctxt->fd);
+    ctxt->fd = -1;
+    xmlFree(ctxt);
+}
+
+/**
+ * xmlNanoHTTPSend:
+ * @ctxt:  an HTTP context
+ *
+ * Send the input needed to initiate the processing on the server side
+ */
+
+static void
+xmlNanoHTTPSend(xmlNanoHTTPCtxtPtr ctxt) {
+    if (ctxt->state & XML_NANO_HTTP_WRITE) {
+        int total_sent = 0;
+        while (total_sent <strlen(ctxt->outptr)) {
+            int nsent = send(ctxt->fd, ctxt->outptr+total_sent,
+                             strlen(ctxt->outptr)-total_sent, 0);
+            if (nsent>0)
+                total_sent += nsent;
+}
+
+        ctxt->last = total_sent;
+    }
+}
+
+/**
+ * xmlNanoHTTPRecv:
+ * @ctxt:  an HTTP context
+ *
+ * Read information coming from the HTTP connection.
+ * This is a blocking call (but it blocks in select(), not read()).
+ *
+ * Returns the number of byte read or -1 in case of error.
+ */
+
+static int
+xmlNanoHTTPRecv(xmlNanoHTTPCtxtPtr ctxt) {
+    fd_set rfd;
+    struct timeval tv;
+
+
+    while (ctxt->state & XML_NANO_HTTP_READ) {
+	if (ctxt->in == NULL) {
+	    ctxt->in = (char *) xmlMalloc(65000 * sizeof(char));
+	    if (ctxt->in == NULL) {
+	        ctxt->last = -1;
+		return(-1);
+	    }
+	    ctxt->inlen = 65000;
+	    ctxt->inptr = ctxt->content = ctxt->inrptr = ctxt->in;
+	}
+	if (ctxt->inrptr > ctxt->in + XML_NANO_HTTP_CHUNK) {
+	    int delta = ctxt->inrptr - ctxt->in;
+	    int len = ctxt->inptr - ctxt->inrptr;
+	    
+	    memmove(ctxt->in, ctxt->inrptr, len);
+	    ctxt->inrptr -= delta;
+	    ctxt->content -= delta;
+	    ctxt->inptr -= delta;
+	}
+        if ((ctxt->in + ctxt->inlen) < (ctxt->inptr + XML_NANO_HTTP_CHUNK)) {
+	    int d_inptr = ctxt->inptr - ctxt->in;
+	    int d_content = ctxt->content - ctxt->in;
+	    int d_inrptr = ctxt->inrptr - ctxt->in;
+
+	    ctxt->inlen *= 2;
+            ctxt->in = (char *) xmlRealloc(ctxt->in, ctxt->inlen);
+	    if (ctxt->in == NULL) {
+	        ctxt->last = -1;
+		return(-1);
+	    }
+            ctxt->inptr = ctxt->in + d_inptr;
+            ctxt->content = ctxt->in + d_content;
+            ctxt->inrptr = ctxt->in + d_inrptr;
+	}
+	ctxt->last = recv(ctxt->fd, ctxt->inptr, XML_NANO_HTTP_CHUNK, 0);
+	if (ctxt->last > 0) {
+	    ctxt->inptr += ctxt->last;
+	    return(ctxt->last);
+	}
+	if (ctxt->last == 0) {
+	    return(0);
+	}
+	if (ctxt->last == -1) {
+	    switch (socket_errno()) {
+		case EINPROGRESS:
+		case EWOULDBLOCK:
+#if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
+		case EAGAIN:
+#endif
+		    break;
+		default:
+		    return(0);
+	    }
+	}
+
+	tv.tv_sec = timeout;
+	tv.tv_usec = 0;
+	FD_ZERO(&rfd);
+	FD_SET(ctxt->fd, &rfd);
+	
+	if (select(ctxt->fd+1, &rfd, NULL, NULL, &tv)<1)
+		return(0);
+    }
+    return(0);
+}
+
+/**
+ * xmlNanoHTTPReadLine:
+ * @ctxt:  an HTTP context
+ *
+ * Read one line in the HTTP server output, usually for extracting
+ * the HTTP protocol informations from the answer header.
+ *
+ * Returns a newly allocated string with a copy of the line, or NULL
+ *         which indicate the end of the input.
+ */
+
+static char *
+xmlNanoHTTPReadLine(xmlNanoHTTPCtxtPtr ctxt) {
+    char buf[4096];
+    char *bp = buf;
+    
+    while (bp - buf < 4095) {
+	if (ctxt->inrptr == ctxt->inptr) {
+	    if (xmlNanoHTTPRecv(ctxt) == 0) {
+		if (bp == buf)
+		    return(NULL);
+		else
+		    *bp = 0;
+		return(xmlMemStrdup(buf));
+	    }
+	}
+	*bp = *ctxt->inrptr++;
+	if (*bp == '\n') {
+	    *bp = 0;
+	    return(xmlMemStrdup(buf));
+	}
+	if (*bp != '\r')
+	    bp++;
+    }
+    buf[4095] = 0;
+    return(xmlMemStrdup(buf));
+}
+
+
+/**
+ * xmlNanoHTTPScanAnswer:
+ * @ctxt:  an HTTP context
+ * @line:  an HTTP header line
+ *
+ * Try to extract useful informations from the server answer.
+ * We currently parse and process:
+ *  - The HTTP revision/ return code
+ *  - The Content-Type
+ *  - The Location for redirrect processing.
+ *
+ * Returns -1 in case of failure, the file descriptor number otherwise
+ */
+
+static void
+xmlNanoHTTPScanAnswer(xmlNanoHTTPCtxtPtr ctxt, const char *line) {
+    const char *cur = line;
+
+    if (line == NULL) return;
+
+    if (!strncmp(line, "HTTP/", 5)) {
+        int version = 0;
+	int ret = 0;
+
+	cur += 5;
+	while ((*cur >= '0') && (*cur <= '9')) {
+	    version *= 10;
+	    version += *cur - '0';
+	    cur++;
+	}
+	if (*cur == '.') {
+	    cur++;
+	    if ((*cur >= '0') && (*cur <= '9')) {
+		version *= 10;
+		version += *cur - '0';
+		cur++;
+	    }
+	    while ((*cur >= '0') && (*cur <= '9'))
+		cur++;
+	} else
+	    version *= 10;
+	if ((*cur != ' ') && (*cur != '\t')) return;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	if ((*cur < '0') || (*cur > '9')) return;
+	while ((*cur >= '0') && (*cur <= '9')) {
+	    ret *= 10;
+	    ret += *cur - '0';
+	    cur++;
+	}
+	if ((*cur != 0) && (*cur != ' ') && (*cur != '\t')) return;
+	ctxt->returnValue = ret;
+    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Content-Type:", 13)) {
+        cur += 13;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	if (ctxt->contentType != NULL)
+	    xmlFree(ctxt->contentType);
+	ctxt->contentType = xmlMemStrdup(cur);
+    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"ContentType:", 12)) {
+        cur += 12;
+	if (ctxt->contentType != NULL) return;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	ctxt->contentType = xmlMemStrdup(cur);
+    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Location:", 9)) {
+        cur += 9;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	if (ctxt->location != NULL)
+	    xmlFree(ctxt->location);
+	ctxt->location = xmlMemStrdup(cur);
+    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"WWW-Authenticate:", 17)) {
+        cur += 17;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	if (ctxt->authHeader != NULL)
+	    xmlFree(ctxt->authHeader);
+	ctxt->authHeader = xmlMemStrdup(cur);
+    } else if (!xmlStrncasecmp(BAD_CAST line, BAD_CAST"Proxy-Authenticate:", 19)) {
+        cur += 19;
+	while ((*cur == ' ') || (*cur == '\t')) cur++;
+	if (ctxt->authHeader != NULL)
+	    xmlFree(ctxt->authHeader);
+	ctxt->authHeader = xmlMemStrdup(cur);
+    }
+}
+
+/**
+ * xmlNanoHTTPConnectAttempt:
+ * @ia:  an internet adress structure
+ * @port:  the port number
+ *
+ * Attempt a connection to the given IP:port endpoint. It forces
+ * non-blocking semantic on the socket, and allow 60 seconds for
+ * the host to answer.
+ *
+ * Returns -1 in case of failure, the file descriptor number otherwise
+ */
+
+static int
+xmlNanoHTTPConnectAttempt(struct sockaddr *addr, int port)
+{
+    SOCKET s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
+    fd_set wfd;
+    struct timeval tv;
+    int status;
+    
+    if (s==-1) {
+#ifdef DEBUG_HTTP
+	perror("socket");
+#endif
+	return(-1);
+    }
+    
+#ifdef _WINSOCKAPI_
+    {
+	u_long one = 1;
+
+	status = ioctlsocket(s, FIONBIO, &one) == SOCKET_ERROR ? -1 : 0;
+    }
+#else /* _WINSOCKAPI_ */
+#if defined(VMS)
+    {
+	int enable = 1;
+	status = ioctl(s, FIONBIO, &enable);
+    }
+#else /* VMS */
+    if ((status = fcntl(s, F_GETFL, 0)) != -1) {
+#ifdef O_NONBLOCK
+	status |= O_NONBLOCK;
+#else /* O_NONBLOCK */
+#ifdef F_NDELAY
+	status |= F_NDELAY;
+#endif /* F_NDELAY */
+#endif /* !O_NONBLOCK */
+	status = fcntl(s, F_SETFL, status);
+    }
+    if (status < 0) {
+#ifdef DEBUG_HTTP
+	perror("nonblocking");
+#endif
+	closesocket(s);
+	return(-1);
+    }
+#endif /* !VMS */
+#endif /* !_WINSOCKAPI_ */
+
+
+    if ((connect(s, addr, sizeof(*addr))==-1)) {
+	switch (socket_errno()) {
+	    case EINPROGRESS:
+	    case EWOULDBLOCK:
+		break;
+	    default:
+		perror("connect");
+		closesocket(s);
+		return(-1);
+	}
+    }	
+    
+    tv.tv_sec = timeout;
+    tv.tv_usec = 0;
+    
+    FD_ZERO(&wfd);
+    FD_SET(s, &wfd);
+    
+    switch(select(s+1, NULL, &wfd, NULL, &tv))
+    {
+	case 0:
+	    /* Time out */
+	    closesocket(s);
+	    return(-1);
+	case -1:
+	    /* Ermm.. ?? */
+#ifdef DEBUG_HTTP
+	    perror("select");
+#endif
+	    closesocket(s);
+	    return(-1);
+    }
+
+    if ( FD_ISSET(s, &wfd) ) {
+	SOCKLEN_T len;
+	len = sizeof(status);
+	if (getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&status, &len) < 0 ) {
+	    /* Solaris error code */
+	    return (-1);
+	}
+	if ( status ) {
+	    closesocket(s);
+	    errno = status;
+	    return (-1);
+	}
+    } else {
+	/* pbm */
+	return (-1);
+    }
+    
+    return(s);
+}
+ 
+/**
+ * xmlNanoHTTPConnectHost:
+ * @host:  the host name
+ * @port:  the port number
+ *
+ * Attempt a connection to the given host:port endpoint. It tries
+ * the multiple IP provided by the DNS if available.
+ *
+ * Returns -1 in case of failure, the file descriptor number otherwise
+ */
+
+static int
+xmlNanoHTTPConnectHost(const char *host, int port)
+{
+    struct hostent *h;
+    struct sockaddr *addr;
+    struct in_addr ia;
+    struct sockaddr_in sin;
+#ifdef SUPPORT_IP6
+    struct in6_addr ia6;
+    struct sockaddr_in6 sin6;
+#endif
+    int i;
+    int s;
+    
+#if defined(SUPPORT_IP6) && defined(RES_USE_INET6)
+    if (!(_res.options & RES_INIT))
+	res_init();
+    _res.options |= RES_USE_INET6;
+#endif
+    h=gethostbyname(host);
+    if (h==NULL)
+    {
+#ifdef DEBUG_HTTP
+	xmlGenericError(xmlGenericErrorContext,"unable to resolve '%s'.\n", host);
+#endif
+	return(-1);
+    }
+    
+    for(i=0; h->h_addr_list[i]; i++)
+    {
+	if (h->h_addrtype == AF_INET) {
+	    /* A records (IPv4) */
+	    memcpy(&ia, h->h_addr_list[i], h->h_length);
+	    sin.sin_family = h->h_addrtype;
+	    sin.sin_addr   = ia;
+	    sin.sin_port   = htons(port);
+	    addr = (struct sockaddr *)&sin;
+#ifdef SUPPORT_IP6
+	} else if (h->h_addrtype == AF_INET6) {
+	    /* AAAA records (IPv6) */
+	    memcpy(&ia6, h->h_addr_list[i], h->h_length);
+	    sin6.sin_family = h->h_addrtype;
+	    sin6.sin_addr   = ia6;
+	    sin6.sin_port   = htons(port);
+	    addr = (struct sockaddr *)&sin6;
+#endif
+	} else
+	    break; /* for */
+	
+	s = xmlNanoHTTPConnectAttempt(addr, port);
+	if (s != -1)
+	    return(s);
+    }
+
+#ifdef DEBUG_HTTP
+    xmlGenericError(xmlGenericErrorContext,
+	    "unable to connect to '%s'.\n", host);
+#endif
+    return(-1);
+}
+
+
+/**
+ * xmlNanoHTTPOpen:
+ * @URL:  The URL to load
+ * @contentType:  if available the Content-Type information will be
+ *                returned at that location
+ *
+ * This function try to open a connection to the indicated resource
+ * via HTTP GET.
+ *
+ * Returns NULL in case of failure, otherwise a request handler.
+ *     The contentType, if provided must be freed by the caller
+ */
+
+void*
+xmlNanoHTTPOpen(const char *URL, char **contentType) {
+    if (contentType != NULL) *contentType = NULL;
+    return xmlNanoHTTPMethod(URL, NULL, NULL, contentType, NULL);
+}
+
+/**
+ * xmlNanoHTTPRead:
+ * @ctx:  the HTTP context
+ * @dest:  a buffer
+ * @len:  the buffer length
+ *
+ * This function tries to read @len bytes from the existing HTTP connection
+ * and saves them in @dest. This is a blocking call.
+ *
+ * Returns the number of byte read. 0 is an indication of an end of connection.
+ *         -1 indicates a parameter error.
+ */
+int
+xmlNanoHTTPRead(void *ctx, void *dest, int len) {
+    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
+
+    if (ctx == NULL) return(-1);
+    if (dest == NULL) return(-1);
+    if (len <= 0) return(0);
+
+    while (ctxt->inptr - ctxt->inrptr < len) {
+        if (xmlNanoHTTPRecv(ctxt) == 0) break;
+    }
+    if (ctxt->inptr - ctxt->inrptr < len)
+        len = ctxt->inptr - ctxt->inrptr;
+    memcpy(dest, ctxt->inrptr, len);
+    ctxt->inrptr += len;
+    return(len);
+}
+
+/**
+ * xmlNanoHTTPClose:
+ * @ctx:  the HTTP context
+ *
+ * This function closes an HTTP context, it ends up the connection and
+ * free all data related to it.
+ */
+void
+xmlNanoHTTPClose(void *ctx) {
+    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
+
+    if (ctx == NULL) return;
+
+    xmlNanoHTTPFreeCtxt(ctxt);
+}
+
+/**
+ * xmlNanoHTTPMethod:
+ * @URL:  The URL to load
+ * @method:  the HTTP method to use
+ * @input:  the input string if any
+ * @contentType:  the Content-Type information IN and OUT
+ * @headers:  the extra headers
+ *
+ * This function try to open a connection to the indicated resource
+ * via HTTP using the given @method, adding the given extra headers
+ * and the input buffer for the request content.
+ *
+ * Returns NULL in case of failure, otherwise a request handler.
+ *     The contentType, if provided must be freed by the caller
+ */
+
+void*
+xmlNanoHTTPMethod(const char *URL, const char *method, const char *input,
+                  char **contentType, const char *headers) {
+    xmlNanoHTTPCtxtPtr ctxt;
+    char *bp, *p;
+    int blen, ilen, ret;
+    int head;
+    int nbRedirects = 0;
+    char *redirURL = NULL;
+    
+    if (URL == NULL) return(NULL);
+    if (method == NULL) method = "GET";
+    xmlNanoHTTPInit();
+
+retry:
+    if (redirURL == NULL)
+	ctxt = xmlNanoHTTPNewCtxt(URL);
+    else {
+	ctxt = xmlNanoHTTPNewCtxt(redirURL);
+	xmlFree(redirURL);
+	redirURL = NULL;
+    }
+
+    if ((ctxt->protocol == NULL) || (strcmp(ctxt->protocol, "http"))) {
+        xmlNanoHTTPFreeCtxt(ctxt);
+	if (redirURL != NULL) xmlFree(redirURL);
+        return(NULL);
+    }
+    if (ctxt->hostname == NULL) {
+        xmlNanoHTTPFreeCtxt(ctxt);
+        return(NULL);
+    }
+    if (proxy) {
+	blen = strlen(ctxt->hostname) * 2 + 16;
+	ret = xmlNanoHTTPConnectHost(proxy, proxyPort);
+    }
+    else {
+	blen = strlen(ctxt->hostname);
+	ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port);
+    }
+    if (ret < 0) {
+        xmlNanoHTTPFreeCtxt(ctxt);
+        return(NULL);
+    }
+    ctxt->fd = ret;
+
+    if (input != NULL) {
+	ilen = strlen(input);
+	blen += ilen + 32;
+    }
+    else
+	ilen = 0;
+    if (headers != NULL)
+	blen += strlen(headers);
+    if (contentType && *contentType)
+	blen += strlen(*contentType) + 16;
+    blen += strlen(method) + strlen(ctxt->path) + 23;
+    bp = xmlMalloc(blen);
+    if (proxy) {
+	if (ctxt->port != 80) {
+	    sprintf(bp, "%s http://%s:%d%s", method, ctxt->hostname,
+		 ctxt->port, ctxt->path);
+	}
+	else
+	    sprintf(bp, "%s http://%s%s", method, ctxt->hostname, ctxt->path);
+    }
+    else
+	sprintf(bp, "%s %s", method, ctxt->path);
+    p = bp + strlen(bp);
+    sprintf(p, " HTTP/1.0\r\nHost: %s\r\n", ctxt->hostname);
+    p += strlen(p);
+    if (contentType != NULL && *contentType) {
+	sprintf(p, "Content-Type: %s\r\n", *contentType);
+	p += strlen(p);
+    }
+    if (headers != NULL) {
+	strcpy(p, headers);
+	p += strlen(p);
+    }
+    if (input != NULL)
+	sprintf(p, "Content-Length: %d\r\n\r\n%s", ilen, input);
+    else
+	strcpy(p, "\r\n");
+#ifdef DEBUG_HTTP
+    xmlGenericError(xmlGenericErrorContext,
+	    "-> %s%s", proxy? "(Proxy) " : "", bp);
+    if ((blen -= strlen(bp)+1) < 0)
+	xmlGenericError(xmlGenericErrorContext,
+		"ERROR: overflowed buffer by %d bytes\n", -blen);
+#endif
+    ctxt->outptr = ctxt->out = bp;
+    ctxt->state = XML_NANO_HTTP_WRITE;
+    xmlNanoHTTPSend(ctxt);
+    ctxt->state = XML_NANO_HTTP_READ;
+    head = 1;
+
+    while ((p = xmlNanoHTTPReadLine(ctxt)) != NULL) {
+        if (head && (*p == 0)) {
+	    head = 0;
+	    ctxt->content = ctxt->inrptr;
+	    xmlFree(p);
+	    break;
+	}
+	xmlNanoHTTPScanAnswer(ctxt, p);
+
+#ifdef DEBUG_HTTP
+	xmlGenericError(xmlGenericErrorContext, "<- %s\n", p);
+#endif
+        xmlFree(p);
+    }
+
+    if ((ctxt->location != NULL) && (ctxt->returnValue >= 300) &&
+        (ctxt->returnValue < 400)) {
+#ifdef DEBUG_HTTP
+	xmlGenericError(xmlGenericErrorContext,
+		"\nRedirect to: %s\n", ctxt->location);
+#endif
+	while (xmlNanoHTTPRecv(ctxt)) ;
+        if (nbRedirects < XML_NANO_HTTP_MAX_REDIR) {
+	    nbRedirects++;
+	    redirURL = xmlMemStrdup(ctxt->location);
+	    xmlNanoHTTPFreeCtxt(ctxt);
+	    goto retry;
+	}
+	xmlNanoHTTPFreeCtxt(ctxt);
+#ifdef DEBUG_HTTP
+	xmlGenericError(xmlGenericErrorContext,
+		"Too many redirects, aborting ...\n");
+#endif
+	return(NULL);
+
+    }
+
+    if (contentType != NULL) {
+	if (ctxt->contentType != NULL)
+	    *contentType = xmlMemStrdup(ctxt->contentType);
+	else
+	    *contentType = NULL;
+    }
+
+#ifdef DEBUG_HTTP
+    if (ctxt->contentType != NULL)
+	xmlGenericError(xmlGenericErrorContext,
+		"\nCode %d, content-type '%s'\n\n",
+	       ctxt->returnValue, ctxt->contentType);
+    else
+	xmlGenericError(xmlGenericErrorContext,
+		"\nCode %d, no content-type\n\n",
+	       ctxt->returnValue);
+#endif
+
+    return((void *) ctxt);
+}
+
+/**
+ * xmlNanoHTTPFetch:
+ * @URL:  The URL to load
+ * @filename:  the filename where the content should be saved
+ * @contentType:  if available the Content-Type information will be
+ *                returned at that location
+ *
+ * This function try to fetch the indicated resource via HTTP GET
+ * and save it's content in the file.
+ *
+ * Returns -1 in case of failure, 0 incase of success. The contentType,
+ *     if provided must be freed by the caller
+ */
+int
+xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) {
+    void *ctxt;
+    char buf[4096];
+    int fd;
+    int len;
+    
+    ctxt = xmlNanoHTTPOpen(URL, contentType);
+    if (ctxt == NULL) return(-1);
+
+    if (!strcmp(filename, "-")) 
+        fd = 0;
+    else {
+        fd = open(filename, O_CREAT | O_WRONLY, 00644);
+	if (fd < 0) {
+	    xmlNanoHTTPClose(ctxt);
+	    if ((contentType != NULL) && (*contentType != NULL)) {
+	        xmlFree(*contentType);
+		*contentType = NULL;
+	    }
+	    return(-1);
+	}
+    }
+
+    while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
+	write(fd, buf, len);
+    }
+
+    xmlNanoHTTPClose(ctxt);
+    close(fd);
+    return(0);
+}
+
+/**
+ * xmlNanoHTTPSave:
+ * @ctxt:  the HTTP context
+ * @filename:  the filename where the content should be saved
+ *
+ * This function saves the output of the HTTP transaction to a file
+ * It closes and free the context at the end
+ *
+ * Returns -1 in case of failure, 0 incase of success.
+ */
+int
+xmlNanoHTTPSave(void *ctxt, const char *filename) {
+    char buf[4096];
+    int fd;
+    int len;
+    
+    if (ctxt == NULL) return(-1);
+
+    if (!strcmp(filename, "-")) 
+        fd = 0;
+    else {
+        fd = open(filename, O_CREAT | O_WRONLY);
+	if (fd < 0) {
+	    xmlNanoHTTPClose(ctxt);
+	    return(-1);
+	}
+    }
+
+    while ((len = xmlNanoHTTPRead(ctxt, buf, sizeof(buf))) > 0) {
+	write(fd, buf, len);
+    }
+
+    xmlNanoHTTPClose(ctxt);
+    return(0);
+}
+
+/**
+ * xmlNanoHTTPReturnCode:
+ * @ctx:  the HTTP context
+ *
+ * Returns the HTTP return code for the request.
+ */
+int
+xmlNanoHTTPReturnCode(void *ctx) {
+    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
+
+    if (ctxt == NULL) return(-1);
+
+    return(ctxt->returnValue);
+}
+
+/**
+ * xmlNanoHTTPAuthHeader:
+ * @ctx:  the HTTP context
+ *
+ * Returns the stashed value of the WWW-Authenticate or Proxy-Authenticate
+ * header.
+ */
+const char *
+xmlNanoHTTPAuthHeader(void *ctx) {
+    xmlNanoHTTPCtxtPtr ctxt = (xmlNanoHTTPCtxtPtr) ctx;
+
+    if (ctxt == NULL) return(NULL);
+
+    return(ctxt->authHeader);
+}
+
+#ifdef STANDALONE
+int main(int argc, char **argv) {
+    char *contentType = NULL;
+
+    if (argv[1] != NULL) {
+	if (argv[2] != NULL) 
+	    xmlNanoHTTPFetch(argv[1], argv[2], &contentType);
+        else
+	    xmlNanoHTTPFetch(argv[1], "-", &contentType);
+	if (contentType != NULL) xmlFree(contentType);
+    } else {
+        xmlGenericError(xmlGenericErrorContext,
+		"%s: minimal HTTP GET implementation\n", argv[0]);
+        xmlGenericError(xmlGenericErrorContext,
+		"\tusage %s [ URL [ filename ] ]\n", argv[0]);
+    }
+    xmlNanoHTTPCleanup();
+    xmlMemoryDump();
+    return(0);
+}
+#endif /* STANDALONE */
+#else /* !LIBXML_HTTP_ENABLED */
+#ifdef STANDALONE
+#include <stdio.h>
+int main(int argc, char **argv) {
+    xmlGenericError(xmlGenericErrorContext,
+	    "%s : HTTP support not compiled in\n", argv[0]);
+    return(0);
+}
+#endif /* STANDALONE */
+#endif /* LIBXML_HTTP_ENABLED */
diff --git a/nanohttp.h b/nanohttp.h
new file mode 100644
index 0000000..78d1c44
--- /dev/null
+++ b/nanohttp.h
@@ -0,0 +1,44 @@
+/*
+ * nanohttp.c: minimalist HTTP implementation to fetch external subsets.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+ 
+#ifndef __NANO_HTTP_H__
+#define __NANO_HTTP_H__
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_HTTP_ENABLED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+void	xmlNanoHTTPInit		(void);
+void	xmlNanoHTTPCleanup	(void);
+void	xmlNanoHTTPScanProxy	(const char *URL);
+int	xmlNanoHTTPFetch	(const char *URL,
+				 const char *filename,
+				 char **contentType);
+void *	xmlNanoHTTPMethod	(const char *URL,
+				 const char *method,
+				 const char *input,
+				 char **contentType,
+				 const char *headers);
+void *	xmlNanoHTTPOpen		(const char *URL,
+				 char **contentType);
+int	xmlNanoHTTPReturnCode	(void *ctx);
+const char * xmlNanoHTTPAuthHeader(void *ctx);
+int	xmlNanoHTTPRead		(void *ctx,
+				 void *dest,
+				 int len);
+int	xmlNanoHTTPSave		(void *ctxt,
+				 const char *filename);
+void	xmlNanoHTTPClose	(void *ctx);
+#ifdef __cplusplus
+}
+
+#endif /* LIBXML_HTTP_ENABLED */
+#endif
+#endif /* __NANO_HTTP_H__ */
diff --git a/parser.c b/parser.c
new file mode 100644
index 0000000..5541628
--- /dev/null
+++ b/parser.c
@@ -0,0 +1,9867 @@
+/*
+ * parser.c : an XML 1.0 parser, namespaces and validity support are mostly
+ *            implemented on top of the SAX interfaces
+ *
+ * References:
+ *   The XML specification:
+ *     http://www.w3.org/TR/REC-xml
+ *   Original 1.0 version:
+ *     http://www.w3.org/TR/1998/REC-xml-19980210
+ *   XML second edition working draft
+ *     http://www.w3.org/TR/2000/WD-xml-2e-20000814
+ *
+ * Okay this is a big file, the parser core is around 7000 lines, then it
+ * is followed by the progressive parser top routines, then the various
+ * high level APIs to call the parser and a few miscelaneous functions.
+ * A number of helper functions and deprecated ones have been moved to
+ * parserInternals.c to reduce this file size.
+ * As much as possible the functions are associated with their relative
+ * production in the XML specification. A few productions defining the
+ * different ranges of character are actually implanted either in 
+ * parserInternals.h or parserInternals.c
+ * The DOM tree build is realized from the default SAX callbacks in
+ * the module SAX.c.
+ * The routines doing the validation checks are in valid.c and called either
+ * from the SAx callbacks or as standalones functions using a preparsed
+ * document.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - truncated definitions of xmlSubstituteEntitiesDefaultValue
+ * and xmlDoValidityCheckingDefaultValue for VMS
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#define XML_DIR_SEP '\\'
+#else
+#include "config.h"
+#define XML_DIR_SEP '/'
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/valid.h>
+#include <libxml/entities.h>
+#include <libxml/xmlerror.h>
+#include <libxml/encoding.h>
+#include <libxml/xmlIO.h>
+#include <libxml/uri.h>
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+
+#define XML_PARSER_BIG_BUFFER_SIZE 1000
+#define XML_PARSER_BUFFER_SIZE 100
+
+/*
+ * Various global defaults for parsing
+ */
+int xmlGetWarningsDefaultValue = 1;
+int xmlParserDebugEntities = 0;
+#ifdef VMS
+int xmlSubstituteEntitiesDefaultVal = 0;
+#define xmlSubstituteEntitiesDefaultValue xmlSubstituteEntitiesDefaultVal 
+int xmlDoValidityCheckingDefaultVal = 0;
+#define xmlDoValidityCheckingDefaultValue xmlDoValidityCheckingDefaultVal
+#else
+int xmlSubstituteEntitiesDefaultValue = 0;
+int xmlDoValidityCheckingDefaultValue = 0;
+#endif
+int xmlLoadExtDtdDefaultValue = 0;
+int xmlPedanticParserDefaultValue = 0;
+int xmlKeepBlanksDefaultValue = 1;
+
+/*
+ * List of XML prefixed PI allowed by W3C specs
+ */
+
+const char *xmlW3CPIs[] = {
+    "xml-stylesheet",
+    NULL
+};
+
+/* DEPR void xmlParserHandleReference(xmlParserCtxtPtr ctxt); */
+void xmlParserHandlePEReference(xmlParserCtxtPtr ctxt);
+xmlEntityPtr xmlParseStringPEReference(xmlParserCtxtPtr ctxt,
+                                       const xmlChar **str);
+
+
+/************************************************************************
+ *									*
+ * 		Parser stacks related functions and macros		*
+ *									*
+ ************************************************************************/
+
+xmlEntityPtr xmlParseStringEntityRef(xmlParserCtxtPtr ctxt,
+                                     const xmlChar ** str);
+
+/*
+ * Generic function for accessing stacks in the Parser Context
+ */
+
+#define PUSH_AND_POP(scope, type, name)					\
+scope int name##Push(xmlParserCtxtPtr ctxt, type value) {		\
+    if (ctxt->name##Nr >= ctxt->name##Max) {				\
+	ctxt->name##Max *= 2;						\
+        ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,		\
+	             ctxt->name##Max * sizeof(ctxt->name##Tab[0]));	\
+        if (ctxt->name##Tab == NULL) {					\
+	    xmlGenericError(xmlGenericErrorContext,			\
+		    "realloc failed !\n");				\
+	    return(0);							\
+	}								\
+    }									\
+    ctxt->name##Tab[ctxt->name##Nr] = value;				\
+    ctxt->name = value;							\
+    return(ctxt->name##Nr++);						\
+}									\
+scope type name##Pop(xmlParserCtxtPtr ctxt) {				\
+    type ret;								\
+    if (ctxt->name##Nr <= 0) return(0);					\
+    ctxt->name##Nr--;							\
+    if (ctxt->name##Nr > 0)						\
+	ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];		\
+    else								\
+        ctxt->name = NULL;						\
+    ret = ctxt->name##Tab[ctxt->name##Nr];				\
+    ctxt->name##Tab[ctxt->name##Nr] = 0;				\
+    return(ret);							\
+}									\
+
+/*
+ * Those macros actually generate the functions
+ */
+PUSH_AND_POP(extern, xmlParserInputPtr, input)
+PUSH_AND_POP(extern, xmlNodePtr, node)
+PUSH_AND_POP(extern, xmlChar*, name)
+
+int spacePush(xmlParserCtxtPtr ctxt, int val) {
+    if (ctxt->spaceNr >= ctxt->spaceMax) {
+	ctxt->spaceMax *= 2;
+        ctxt->spaceTab = (int *) xmlRealloc(ctxt->spaceTab,
+	             ctxt->spaceMax * sizeof(ctxt->spaceTab[0]));
+        if (ctxt->spaceTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return(0);
+	}
+    }
+    ctxt->spaceTab[ctxt->spaceNr] = val;
+    ctxt->space = &ctxt->spaceTab[ctxt->spaceNr];
+    return(ctxt->spaceNr++);
+}
+
+int spacePop(xmlParserCtxtPtr ctxt) {
+    int ret;
+    if (ctxt->spaceNr <= 0) return(0);
+    ctxt->spaceNr--;
+    if (ctxt->spaceNr > 0)
+	ctxt->space = &ctxt->spaceTab[ctxt->spaceNr - 1];
+    else
+        ctxt->space = NULL;
+    ret = ctxt->spaceTab[ctxt->spaceNr];
+    ctxt->spaceTab[ctxt->spaceNr] = -1;
+    return(ret);
+}
+
+/*
+ * Macros for accessing the content. Those should be used only by the parser,
+ * and not exported.
+ *
+ * Dirty macros, i.e. one often need to make assumption on the context to
+ * use them
+ *
+ *   CUR_PTR return the current pointer to the xmlChar to be parsed.
+ *           To be used with extreme caution since operations consuming
+ *           characters may move the input buffer to a different location !
+ *   CUR     returns the current xmlChar value, i.e. a 8 bit value if compiled
+ *           This should be used internally by the parser
+ *           only to compare to ASCII values otherwise it would break when
+ *           running with UTF-8 encoding.
+ *   RAW     same as CUR but in the input buffer, bypass any token
+ *           extraction that may have been done
+ *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
+ *           to compare on ASCII based substring.
+ *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
+ *           strings within the parser.
+ *
+ * Clean macros, not dependent of an ASCII context, expect UTF-8 encoding
+ *
+ *   NEXT    Skip to the next character, this does the proper decoding
+ *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
+ *   NEXTL(l) Skip l xmlChars in the input buffer
+ *   CUR_CHAR(l) returns the current unicode character (int), set l
+ *           to the number of xmlChars used for the encoding [0-5].
+ *   CUR_SCHAR  same but operate on a string instead of the context
+ *   COPY_BUF  copy the current unicode char to the target buffer, increment
+ *            the index
+ *   GROW, SHRINK  handling of input buffers
+ */
+
+#define RAW (ctxt->token ? -1 : (*ctxt->input->cur))
+#define CUR (ctxt->token ? ctxt->token : (*ctxt->input->cur))
+#define NXT(val) ctxt->input->cur[(val)]
+#define CUR_PTR ctxt->input->cur
+
+#define SKIP(val) do {							\
+    ctxt->nbChars += (val),ctxt->input->cur += (val);			\
+    if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);	\
+    /* DEPR if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); */\
+    if ((*ctxt->input->cur == 0) &&					\
+        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))		\
+	    xmlPopInput(ctxt);						\
+  } while (0)
+
+#define SHRINK do {							\
+    xmlParserInputShrink(ctxt->input);					\
+    if ((*ctxt->input->cur == 0) &&					\
+        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))		\
+	    xmlPopInput(ctxt);						\
+  } while (0)
+
+#define GROW do {							\
+    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);			\
+    if ((*ctxt->input->cur == 0) &&					\
+        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))		\
+	    xmlPopInput(ctxt);						\
+  } while (0)
+
+#define SKIP_BLANKS xmlSkipBlankChars(ctxt)
+
+#define NEXT xmlNextChar(ctxt)
+
+#define NEXTL(l) do {							\
+    if (*(ctxt->input->cur) == '\n') {					\
+	ctxt->input->line++; ctxt->input->col = 1;			\
+    } else ctxt->input->col++;						\
+    ctxt->token = 0; ctxt->input->cur += l;				\
+    if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);	\
+    /* DEPR if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); */\
+  } while (0)
+
+#define CUR_CHAR(l) xmlCurrentChar(ctxt, &l)
+#define CUR_SCHAR(s, l) xmlStringCurrentChar(ctxt, s, &l)
+
+#define COPY_BUF(l,b,i,v)						\
+    if (l == 1) b[i++] = (xmlChar) v;					\
+    else i += xmlCopyChar(l,&b[i],v)
+
+/**
+ * xmlSkipBlankChars:
+ * @ctxt:  the XML parser context
+ *
+ * skip all blanks character found at that point in the input streams.
+ * It pops up finished entities in the process if allowable at that point.
+ *
+ * Returns the number of space chars skipped
+ */
+
+int
+xmlSkipBlankChars(xmlParserCtxtPtr ctxt) {
+    int cur, res = 0;
+
+    /*
+     * It's Okay to use CUR/NEXT here since all the blanks are on
+     * the ASCII range.
+     */
+    do {
+	cur = CUR;
+	while (IS_BLANK(cur)) { /* CHECKED tstblanks.xml */
+	    NEXT;
+	    cur = CUR;
+	    res++;
+	}
+	while ((cur == 0) && (ctxt->inputNr > 1) &&
+	       (ctxt->instate != XML_PARSER_COMMENT)) {
+	    xmlPopInput(ctxt);
+	    cur = CUR;
+	}
+	/*
+	 * Need to handle support of entities branching here
+	 */
+	if (*ctxt->input->cur == '%') xmlParserHandlePEReference(ctxt);
+	/* DEPR if (*ctxt->input->cur == '&') xmlParserHandleReference(ctxt); */
+    } while (IS_BLANK(cur)); /* CHECKED tstblanks.xml */
+    return(res);
+}
+
+/************************************************************************
+ *									*
+ *		Commodity functions to handle entities			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlPopInput:
+ * @ctxt:  an XML parser context
+ *
+ * xmlPopInput: the current input pointed by ctxt->input came to an end
+ *          pop it and return the next char.
+ *
+ * Returns the current xmlChar in the parser context
+ */
+xmlChar
+xmlPopInput(xmlParserCtxtPtr ctxt) {
+    if (ctxt->inputNr == 1) return(0); /* End of main Input */
+    if (xmlParserDebugEntities)
+	xmlGenericError(xmlGenericErrorContext,
+		"Popping input %d\n", ctxt->inputNr);
+    xmlFreeInputStream(inputPop(ctxt));
+    if ((*ctxt->input->cur == 0) &&
+        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
+	    return(xmlPopInput(ctxt));
+    return(CUR);
+}
+
+/**
+ * xmlPushInput:
+ * @ctxt:  an XML parser context
+ * @input:  an XML parser input fragment (entity, XML fragment ...).
+ *
+ * xmlPushInput: switch to a new input stream which is stacked on top
+ *               of the previous one(s).
+ */
+void
+xmlPushInput(xmlParserCtxtPtr ctxt, xmlParserInputPtr input) {
+    if (input == NULL) return;
+
+    if (xmlParserDebugEntities) {
+	if ((ctxt->input != NULL) && (ctxt->input->filename))
+	    xmlGenericError(xmlGenericErrorContext,
+		    "%s(%d): ", ctxt->input->filename,
+		    ctxt->input->line);
+	xmlGenericError(xmlGenericErrorContext,
+		"Pushing input %d : %.30s\n", ctxt->inputNr+1, input->cur);
+    }
+    inputPush(ctxt, input);
+    GROW;
+}
+
+/**
+ * xmlParseCharRef:
+ * @ctxt:  an XML parser context
+ *
+ * parse Reference declarations
+ *
+ * [66] CharRef ::= '&#' [0-9]+ ';' |
+ *                  '&#x' [0-9a-fA-F]+ ';'
+ *
+ * [ WFC: Legal Character ]
+ * Characters referred to using character references must match the
+ * production for Char. 
+ *
+ * Returns the value parsed (as an int), 0 in case of error
+ */
+int
+xmlParseCharRef(xmlParserCtxtPtr ctxt) {
+    int val = 0;
+    int count = 0;
+
+    if (ctxt->token != 0) {
+	val = ctxt->token;
+        ctxt->token = 0;
+        return(val);
+    }
+    /*
+     * Using RAW/CUR/NEXT is okay since we are working on ASCII range here
+     */
+    if ((RAW == '&') && (NXT(1) == '#') &&
+        (NXT(2) == 'x')) {
+	SKIP(3);
+	GROW;
+	while (RAW != ';') { /* loop blocked by count */
+	    if ((RAW >= '0') && (RAW <= '9') && (count < 20)) 
+	        val = val * 16 + (CUR - '0');
+	    else if ((RAW >= 'a') && (RAW <= 'f') && (count < 20))
+	        val = val * 16 + (CUR - 'a') + 10;
+	    else if ((RAW >= 'A') && (RAW <= 'F') && (count < 20))
+	        val = val * 16 + (CUR - 'A') + 10;
+	    else {
+		ctxt->errNo = XML_ERR_INVALID_HEX_CHARREF;
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		         "xmlParseCharRef: invalid hexadecimal value\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		val = 0;
+		break;
+	    }
+	    NEXT;
+	    count++;
+	}
+	if (RAW == ';') {
+	    /* on purpose to avoid reentrancy problems with NEXT and SKIP */
+	    ctxt->nbChars ++;
+	    ctxt->input->cur++;
+	}
+    } else if  ((RAW == '&') && (NXT(1) == '#')) {
+	SKIP(2);
+	GROW;
+	while (RAW != ';') { /* loop blocked by count */
+	    if ((RAW >= '0') && (RAW <= '9') && (count < 20)) 
+	        val = val * 10 + (CUR - '0');
+	    else {
+		ctxt->errNo = XML_ERR_INVALID_DEC_CHARREF;
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		         "xmlParseCharRef: invalid decimal value\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		val = 0;
+		break;
+	    }
+	    NEXT;
+	    count++;
+	}
+	if (RAW == ';') {
+	    /* on purpose to avoid reentrancy problems with NEXT and SKIP */
+	    ctxt->nbChars ++;
+	    ctxt->input->cur++;
+	}
+    } else {
+	ctxt->errNo = XML_ERR_INVALID_CHARREF;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	       "xmlParseCharRef: invalid value\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    /*
+     * [ WFC: Legal Character ]
+     * Characters referred to using character references must match the
+     * production for Char. 
+     */
+    if (IS_CHAR(val)) {
+        return(val);
+    } else {
+	ctxt->errNo = XML_ERR_INVALID_CHAR;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "CharRef: invalid xmlChar value %d\n",
+	                     val);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    return(0);
+}
+
+/**
+ * xmlParseStringCharRef:
+ * @ctxt:  an XML parser context
+ * @str:  a pointer to an index in the string
+ *
+ * parse Reference declarations, variant parsing from a string rather
+ * than an an input flow.
+ *
+ * [66] CharRef ::= '&#' [0-9]+ ';' |
+ *                  '&#x' [0-9a-fA-F]+ ';'
+ *
+ * [ WFC: Legal Character ]
+ * Characters referred to using character references must match the
+ * production for Char. 
+ *
+ * Returns the value parsed (as an int), 0 in case of error, str will be
+ *         updated to the current value of the index
+ */
+int
+xmlParseStringCharRef(xmlParserCtxtPtr ctxt, const xmlChar **str) {
+    const xmlChar *ptr;
+    xmlChar cur;
+    int val = 0;
+
+    if ((str == NULL) || (*str == NULL)) return(0);
+    ptr = *str;
+    cur = *ptr;
+    if ((cur == '&') && (ptr[1] == '#') && (ptr[2] == 'x')) {
+	ptr += 3;
+	cur = *ptr;
+	while (cur != ';') { /* Non input consuming loop */
+	    if ((cur >= '0') && (cur <= '9')) 
+	        val = val * 16 + (cur - '0');
+	    else if ((cur >= 'a') && (cur <= 'f'))
+	        val = val * 16 + (cur - 'a') + 10;
+	    else if ((cur >= 'A') && (cur <= 'F'))
+	        val = val * 16 + (cur - 'A') + 10;
+	    else {
+		ctxt->errNo = XML_ERR_INVALID_HEX_CHARREF;
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		         "xmlParseStringCharRef: invalid hexadecimal value\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		val = 0;
+		break;
+	    }
+	    ptr++;
+	    cur = *ptr;
+	}
+	if (cur == ';')
+	    ptr++;
+    } else if  ((cur == '&') && (ptr[1] == '#')){
+	ptr += 2;
+	cur = *ptr;
+	while (cur != ';') { /* Non input consuming loops */
+	    if ((cur >= '0') && (cur <= '9')) 
+	        val = val * 10 + (cur - '0');
+	    else {
+		ctxt->errNo = XML_ERR_INVALID_DEC_CHARREF;
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		         "xmlParseStringCharRef: invalid decimal value\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		val = 0;
+		break;
+	    }
+	    ptr++;
+	    cur = *ptr;
+	}
+	if (cur == ';')
+	    ptr++;
+    } else {
+	ctxt->errNo = XML_ERR_INVALID_CHARREF;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	       "xmlParseCharRef: invalid value\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(0);
+    }
+    *str = ptr;
+
+    /*
+     * [ WFC: Legal Character ]
+     * Characters referred to using character references must match the
+     * production for Char. 
+     */
+    if (IS_CHAR(val)) {
+        return(val);
+    } else {
+	ctxt->errNo = XML_ERR_INVALID_CHAR;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		             "CharRef: invalid xmlChar value %d\n", val);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    return(0);
+}
+
+/**
+ * xmlParserHandlePEReference:
+ * @ctxt:  the parser context
+ * 
+ * [69] PEReference ::= '%' Name ';'
+ *
+ * [ WFC: No Recursion ]
+ * A parsed entity must not contain a recursive
+ * reference to itself, either directly or indirectly. 
+ *
+ * [ WFC: Entity Declared ]
+ * In a document without any DTD, a document with only an internal DTD
+ * subset which contains no parameter entity references, or a document
+ * with "standalone='yes'", ...  ... The declaration of a parameter
+ * entity must precede any reference to it...
+ *
+ * [ VC: Entity Declared ]
+ * In a document with an external subset or external parameter entities
+ * with "standalone='no'", ...  ... The declaration of a parameter entity
+ * must precede any reference to it...
+ *
+ * [ WFC: In DTD ]
+ * Parameter-entity references may only appear in the DTD.
+ * NOTE: misleading but this is handled.
+ *
+ * A PEReference may have been detected in the current input stream
+ * the handling is done accordingly to 
+ *      http://www.w3.org/TR/REC-xml#entproc
+ * i.e. 
+ *   - Included in literal in entity values
+ *   - Included as Paraemeter Entity reference within DTDs
+ */
+void
+xmlParserHandlePEReference(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlEntityPtr entity = NULL;
+    xmlParserInputPtr input;
+
+    if (ctxt->token != 0) {
+        return;
+    }	
+    if (RAW != '%') return;
+    switch(ctxt->instate) {
+	case XML_PARSER_CDATA_SECTION:
+	    return;
+        case XML_PARSER_COMMENT:
+	    return;
+	case XML_PARSER_START_TAG:
+	    return;
+	case XML_PARSER_END_TAG:
+	    return;
+        case XML_PARSER_EOF:
+	    ctxt->errNo = XML_ERR_PEREF_AT_EOF;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "PEReference at EOF\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+        case XML_PARSER_PROLOG:
+	case XML_PARSER_START:
+	case XML_PARSER_MISC:
+	    ctxt->errNo = XML_ERR_PEREF_IN_PROLOG;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "PEReference in prolog!\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	case XML_PARSER_ENTITY_DECL:
+        case XML_PARSER_CONTENT:
+        case XML_PARSER_ATTRIBUTE_VALUE:
+        case XML_PARSER_PI:
+	case XML_PARSER_SYSTEM_LITERAL:
+	    /* we just ignore it there */
+	    return;
+        case XML_PARSER_EPILOG:
+	    ctxt->errNo = XML_ERR_PEREF_IN_EPILOG;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "PEReference in epilog!\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	case XML_PARSER_ENTITY_VALUE:
+	    /*
+	     * NOTE: in the case of entity values, we don't do the
+	     *       substitution here since we need the literal
+	     *       entity value to be able to save the internal
+	     *       subset of the document.
+	     *       This will be handled by xmlStringDecodeEntities
+	     */
+	    return;
+        case XML_PARSER_DTD:
+	    /*
+	     * [WFC: Well-Formedness Constraint: PEs in Internal Subset]
+	     * In the internal DTD subset, parameter-entity references
+	     * can occur only where markup declarations can occur, not
+	     * within markup declarations.
+	     * In that case this is handled in xmlParseMarkupDecl
+	     */
+	    if ((ctxt->external == 0) && (ctxt->inputNr == 1))
+		return;
+            break;
+        case XML_PARSER_IGNORE:
+            return;
+    }
+
+    NEXT;
+    name = xmlParseName(ctxt);
+    if (xmlParserDebugEntities)
+	xmlGenericError(xmlGenericErrorContext,
+		"PE Reference: %s\n", name);
+    if (name == NULL) {
+        ctxt->errNo = XML_ERR_PEREF_NO_NAME;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "xmlHandlePEReference: no name\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else {
+	if (RAW == ';') {
+	    NEXT;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->getParameterEntity != NULL))
+		entity = ctxt->sax->getParameterEntity(ctxt->userData, name);
+	    if (entity == NULL) {
+	        
+		/*
+		 * [ WFC: Entity Declared ]
+		 * In a document without any DTD, a document with only an
+		 * internal DTD subset which contains no parameter entity
+		 * references, or a document with "standalone='yes'", ...
+		 * ... The declaration of a parameter entity must precede
+		 * any reference to it...
+		 */
+		if ((ctxt->standalone == 1) ||
+		    ((ctxt->hasExternalSubset == 0) &&
+		     (ctxt->hasPErefs == 0))) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			 "PEReference: %%%s; not found\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+	        } else {
+		    /*
+		     * [ VC: Entity Declared ]
+		     * In a document with an external subset or external
+		     * parameter entities with "standalone='no'", ...
+		     * ... The declaration of a parameter entity must precede
+		     * any reference to it...
+		     */
+		    if ((!ctxt->disableSAX) &&
+			(ctxt->validate) && (ctxt->vctxt.error != NULL)) {
+			ctxt->vctxt.error(ctxt->vctxt.userData,
+			     "PEReference: %%%s; not found\n", name);
+		    } else if ((!ctxt->disableSAX) &&
+			(ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			ctxt->sax->warning(ctxt->userData,
+			 "PEReference: %%%s; not found\n", name);
+		    ctxt->valid = 0;
+		}
+	    } else {
+	        if ((entity->etype == XML_INTERNAL_PARAMETER_ENTITY) ||
+		    (entity->etype == XML_EXTERNAL_PARAMETER_ENTITY)) {
+		    /*
+		     * handle the extra spaces added before and after
+		     * c.f. http://www.w3.org/TR/REC-xml#as-PE
+		     * this is done independantly.
+		     */
+		    input = xmlNewEntityInputStream(ctxt, entity);
+		    xmlPushInput(ctxt, input);
+		    if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
+			(RAW == '<') && (NXT(1) == '?') &&
+			(NXT(2) == 'x') && (NXT(3) == 'm') &&
+			(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+			xmlParseTextDecl(ctxt);
+		    }
+		    if (ctxt->token == 0)
+			ctxt->token = ' ';
+		} else {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			 "xmlHandlePEReference: %s is not a parameter entity\n",
+			                 name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+	    }
+	} else {
+	    ctxt->errNo = XML_ERR_PEREF_SEMICOL_MISSING;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+				 "xmlHandlePEReference: expecting ';'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	xmlFree(name);
+    }
+}
+
+/*
+ * Macro used to grow the current buffer.
+ */
+#define growBuffer(buffer) {						\
+    buffer##_size *= 2;							\
+    buffer = (xmlChar *)						\
+    		xmlRealloc(buffer, buffer##_size * sizeof(xmlChar));	\
+    if (buffer == NULL) {						\
+	perror("realloc failed");					\
+	return(NULL);							\
+    }									\
+}
+
+/**
+ * xmlStringDecodeEntities:
+ * @ctxt:  the parser context
+ * @str:  the input string
+ * @what:  combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
+ * @end:  an end marker xmlChar, 0 if none
+ * @end2:  an end marker xmlChar, 0 if none
+ * @end3:  an end marker xmlChar, 0 if none
+ * 
+ * Takes a entity string content and process to do the adequate subtitutions.
+ *
+ * [67] Reference ::= EntityRef | CharRef
+ *
+ * [69] PEReference ::= '%' Name ';'
+ *
+ * Returns A newly allocated string with the substitution done. The caller
+ *      must deallocate it !
+ */
+xmlChar *
+xmlStringDecodeEntities(xmlParserCtxtPtr ctxt, const xmlChar *str, int what,
+		        xmlChar end, xmlChar  end2, xmlChar end3) {
+    xmlChar *buffer = NULL;
+    int buffer_size = 0;
+
+    xmlChar *current = NULL;
+    xmlEntityPtr ent;
+    int c,l;
+    int nbchars = 0;
+
+    if (str == NULL)
+	return(NULL);
+
+    if (ctxt->depth > 40) {
+	ctxt->errNo = XML_ERR_ENTITY_LOOP;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"Detected entity reference loop\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+
+    /*
+     * allocate a translation buffer.
+     */
+    buffer_size = XML_PARSER_BIG_BUFFER_SIZE;
+    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+	perror("xmlDecodeEntities: malloc failed");
+	return(NULL);
+    }
+
+    /*
+     * Ok loop until we reach one of the ending char or a size limit.
+     * we are operating on already parsed values.
+     */
+    c = CUR_SCHAR(str, l);
+    while ((c != 0) && (c != end) && /* non input consuming loop */
+	   (c != end2) && (c != end3)) {
+
+	if (c == 0) break;
+        if ((c == '&') && (str[1] == '#')) {
+	    int val = xmlParseStringCharRef(ctxt, &str);
+	    if (val != 0) {
+		COPY_BUF(0,buffer,nbchars,val);
+	    }
+	} else if ((c == '&') && (what & XML_SUBSTITUTE_REF)) {
+	    if (xmlParserDebugEntities)
+		xmlGenericError(xmlGenericErrorContext,
+			"String decoding Entity Reference: %.30s\n",
+			str);
+	    ent = xmlParseStringEntityRef(ctxt, &str);
+	    if ((ent != NULL) &&
+		(ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
+		if (ent->content != NULL) {
+		    COPY_BUF(0,buffer,nbchars,ent->content[0]);
+		} else {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			    "internal error entity has no content\n");
+		}
+	    } else if ((ent != NULL) && (ent->content != NULL)) {
+		xmlChar *rep;
+
+		ctxt->depth++;
+		rep = xmlStringDecodeEntities(ctxt, ent->content, what,
+			                      0, 0, 0);
+		ctxt->depth--;
+		if (rep != NULL) {
+		    current = rep;
+		    while (*current != 0) { /* non input consuming loop */
+			buffer[nbchars++] = *current++;
+			if (nbchars >
+		            buffer_size - XML_PARSER_BUFFER_SIZE) {
+			    growBuffer(buffer);
+			}
+		    }
+		    xmlFree(rep);
+		}
+	    } else if (ent != NULL) {
+		int i = xmlStrlen(ent->name);
+		const xmlChar *cur = ent->name;
+
+		buffer[nbchars++] = '&';
+		if (nbchars > buffer_size - i - XML_PARSER_BUFFER_SIZE) {
+		    growBuffer(buffer);
+		}
+		for (;i > 0;i--)
+		    buffer[nbchars++] = *cur++;
+		buffer[nbchars++] = ';';
+	    }
+	} else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) {
+	    if (xmlParserDebugEntities)
+		xmlGenericError(xmlGenericErrorContext,
+			"String decoding PE Reference: %.30s\n", str);
+	    ent = xmlParseStringPEReference(ctxt, &str);
+	    if (ent != NULL) {
+		xmlChar *rep;
+
+		ctxt->depth++;
+		rep = xmlStringDecodeEntities(ctxt, ent->content, what,
+			                      0, 0, 0);
+		ctxt->depth--;
+		if (rep != NULL) {
+		    current = rep;
+		    while (*current != 0) { /* non input consuming loop */
+			buffer[nbchars++] = *current++;
+			if (nbchars >
+		            buffer_size - XML_PARSER_BUFFER_SIZE) {
+			    growBuffer(buffer);
+			}
+		    }
+		    xmlFree(rep);
+		}
+	    }
+	} else {
+	    COPY_BUF(l,buffer,nbchars,c);
+	    str += l;
+	    if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) {
+	      growBuffer(buffer);
+	    }
+	}
+	c = CUR_SCHAR(str, l);
+    }
+    buffer[nbchars++] = 0;
+    return(buffer);
+}
+
+
+/************************************************************************
+ *									*
+ *		Commodity functions to handle xmlChars			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlStrndup:
+ * @cur:  the input xmlChar *
+ * @len:  the len of @cur
+ *
+ * a strndup for array of xmlChar's
+ *
+ * Returns a new xmlChar * or NULL
+ */
+xmlChar *
+xmlStrndup(const xmlChar *cur, int len) {
+    xmlChar *ret;
+    
+    if ((cur == NULL) || (len < 0)) return(NULL);
+    ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"malloc of %ld byte failed\n",
+	        (len + 1) * (long)sizeof(xmlChar));
+        return(NULL);
+    }
+    memcpy(ret, cur, len * sizeof(xmlChar));
+    ret[len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlStrdup:
+ * @cur:  the input xmlChar *
+ *
+ * a strdup for array of xmlChar's. Since they are supposed to be
+ * encoded in UTF-8 or an encoding with 8bit based chars, we assume
+ * a termination mark of '0'.
+ *
+ * Returns a new xmlChar * or NULL
+ */
+xmlChar *
+xmlStrdup(const xmlChar *cur) {
+    const xmlChar *p = cur;
+
+    if (cur == NULL) return(NULL);
+    while (*p != 0) p++; /* non input consuming */
+    return(xmlStrndup(cur, p - cur));
+}
+
+/**
+ * xmlCharStrndup:
+ * @cur:  the input char *
+ * @len:  the len of @cur
+ *
+ * a strndup for char's to xmlChar's
+ *
+ * Returns a new xmlChar * or NULL
+ */
+
+xmlChar *
+xmlCharStrndup(const char *cur, int len) {
+    int i;
+    xmlChar *ret;
+    
+    if ((cur == NULL) || (len < 0)) return(NULL);
+    ret = (xmlChar *) xmlMalloc((len + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext, "malloc of %ld byte failed\n",
+	        (len + 1) * (long)sizeof(xmlChar));
+        return(NULL);
+    }
+    for (i = 0;i < len;i++)
+        ret[i] = (xmlChar) cur[i];
+    ret[len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlCharStrdup:
+ * @cur:  the input char *
+ * @len:  the len of @cur
+ *
+ * a strdup for char's to xmlChar's
+ *
+ * Returns a new xmlChar * or NULL
+ */
+
+xmlChar *
+xmlCharStrdup(const char *cur) {
+    const char *p = cur;
+
+    if (cur == NULL) return(NULL);
+    while (*p != '\0') p++; /* non input consuming */
+    return(xmlCharStrndup(cur, p - cur));
+}
+
+/**
+ * xmlStrcmp:
+ * @str1:  the first xmlChar *
+ * @str2:  the second xmlChar *
+ *
+ * a strcmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+int
+xmlStrcmp(const xmlChar *str1, const xmlChar *str2) {
+    register int tmp;
+
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+        tmp = *str1++ - *str2;
+	if (tmp != 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+/**
+ * xmlStrEqual:
+ * @str1:  the first xmlChar *
+ * @str2:  the second xmlChar *
+ *
+ * Check if both string are equal of have same content
+ * Should be a bit more readable and faster than xmlStrEqual()
+ *
+ * Returns 1 if they are equal, 0 if they are different
+ */
+
+int
+xmlStrEqual(const xmlChar *str1, const xmlChar *str2) {
+    if (str1 == str2) return(1);
+    if (str1 == NULL) return(0);
+    if (str2 == NULL) return(0);
+    do {
+	if (*str1++ != *str2) return(0);
+    } while (*str2++);
+    return(1);
+}
+
+/**
+ * xmlStrncmp:
+ * @str1:  the first xmlChar *
+ * @str2:  the second xmlChar *
+ * @len:  the max comparison length
+ *
+ * a strncmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+int
+xmlStrncmp(const xmlChar *str1, const xmlChar *str2, int len) {
+    register int tmp;
+
+    if (len <= 0) return(0);
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+        tmp = *str1++ - *str2;
+	if (tmp != 0 || --len == 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+static xmlChar casemap[256] = {
+    0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
+    0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,
+    0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,
+    0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,
+    0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,
+    0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,
+    0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,
+    0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,
+    0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+    0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+    0x78,0x79,0x7A,0x7B,0x5C,0x5D,0x5E,0x5F,
+    0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,
+    0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,
+    0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,
+    0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x7F,
+    0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,
+    0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,
+    0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,
+    0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
+    0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,
+    0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,
+    0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,
+    0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
+    0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,
+    0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,
+    0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,
+    0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
+    0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,
+    0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,
+    0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,
+    0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF
+};
+
+/**
+ * xmlStrcasecmp:
+ * @str1:  the first xmlChar *
+ * @str2:  the second xmlChar *
+ *
+ * a strcasecmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+int
+xmlStrcasecmp(const xmlChar *str1, const xmlChar *str2) {
+    register int tmp;
+
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+	tmp = casemap[*str1++] - casemap[*str2];
+	if (tmp != 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+/**
+ * xmlStrncasecmp:
+ * @str1:  the first xmlChar *
+ * @str2:  the second xmlChar *
+ * @len:  the max comparison length
+ *
+ * a strncasecmp for xmlChar's
+ *
+ * Returns the integer result of the comparison
+ */
+
+int
+xmlStrncasecmp(const xmlChar *str1, const xmlChar *str2, int len) {
+    register int tmp;
+
+    if (len <= 0) return(0);
+    if (str1 == str2) return(0);
+    if (str1 == NULL) return(-1);
+    if (str2 == NULL) return(1);
+    do {
+	tmp = casemap[*str1++] - casemap[*str2];
+	if (tmp != 0 || --len == 0) return(tmp);
+    } while (*str2++ != 0);
+    return 0;
+}
+
+/**
+ * xmlStrchr:
+ * @str:  the xmlChar * array
+ * @val:  the xmlChar to search
+ *
+ * a strchr for xmlChar's
+ *
+ * Returns the xmlChar * for the first occurence or NULL.
+ */
+
+const xmlChar *
+xmlStrchr(const xmlChar *str, xmlChar val) {
+    if (str == NULL) return(NULL);
+    while (*str != 0) { /* non input consuming */
+        if (*str == val) return((xmlChar *) str);
+	str++;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlStrstr:
+ * @str:  the xmlChar * array (haystack)
+ * @val:  the xmlChar to search (needle)
+ *
+ * a strstr for xmlChar's
+ *
+ * Returns the xmlChar * for the first occurence or NULL.
+ */
+
+const xmlChar *
+xmlStrstr(const xmlChar *str, xmlChar *val) {
+    int n;
+    
+    if (str == NULL) return(NULL);
+    if (val == NULL) return(NULL);
+    n = xmlStrlen(val);
+
+    if (n == 0) return(str);
+    while (*str != 0) { /* non input consuming */
+        if (*str == *val) {
+	    if (!xmlStrncmp(str, val, n)) return((const xmlChar *) str);
+	}
+	str++;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlStrcasestr:
+ * @str:  the xmlChar * array (haystack)
+ * @val:  the xmlChar to search (needle)
+ *
+ * a case-ignoring strstr for xmlChar's
+ *
+ * Returns the xmlChar * for the first occurence or NULL.
+ */
+
+const xmlChar *
+xmlStrcasestr(const xmlChar *str, xmlChar *val) {
+    int n;
+    
+    if (str == NULL) return(NULL);
+    if (val == NULL) return(NULL);
+    n = xmlStrlen(val);
+
+    if (n == 0) return(str);
+    while (*str != 0) { /* non input consuming */
+	if (casemap[*str] == casemap[*val])
+	    if (!xmlStrncasecmp(str, val, n)) return(str);
+	str++;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlStrsub:
+ * @str:  the xmlChar * array (haystack)
+ * @start:  the index of the first char (zero based)
+ * @len:  the length of the substring
+ *
+ * Extract a substring of a given string
+ *
+ * Returns the xmlChar * for the first occurence or NULL.
+ */
+
+xmlChar *
+xmlStrsub(const xmlChar *str, int start, int len) {
+    int i;
+    
+    if (str == NULL) return(NULL);
+    if (start < 0) return(NULL);
+    if (len < 0) return(NULL);
+
+    for (i = 0;i < start;i++) {
+        if (*str == 0) return(NULL);
+	str++;
+    }
+    if (*str == 0) return(NULL);
+    return(xmlStrndup(str, len));
+}
+
+/**
+ * xmlStrlen:
+ * @str:  the xmlChar * array
+ *
+ * length of a xmlChar's string
+ *
+ * Returns the number of xmlChar contained in the ARRAY.
+ */
+
+int
+xmlStrlen(const xmlChar *str) {
+    int len = 0;
+
+    if (str == NULL) return(0);
+    while (*str != 0) { /* non input consuming */
+	str++;
+	len++;
+    }
+    return(len);
+}
+
+/**
+ * xmlStrncat:
+ * @cur:  the original xmlChar * array
+ * @add:  the xmlChar * array added
+ * @len:  the length of @add
+ *
+ * a strncat for array of xmlChar's, it will extend cur with the len
+ * first bytes of @add.
+ *
+ * Returns a new xmlChar *, the original @cur is reallocated if needed
+ * and should not be freed
+ */
+
+xmlChar *
+xmlStrncat(xmlChar *cur, const xmlChar *add, int len) {
+    int size;
+    xmlChar *ret;
+
+    if ((add == NULL) || (len == 0))
+        return(cur);
+    if (cur == NULL)
+        return(xmlStrndup(add, len));
+
+    size = xmlStrlen(cur);
+    ret = (xmlChar *) xmlRealloc(cur, (size + len + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlStrncat: realloc of %ld byte failed\n",
+	        (size + len + 1) * (long)sizeof(xmlChar));
+        return(cur);
+    }
+    memcpy(&ret[size], add, len * sizeof(xmlChar));
+    ret[size + len] = 0;
+    return(ret);
+}
+
+/**
+ * xmlStrcat:
+ * @cur:  the original xmlChar * array
+ * @add:  the xmlChar * array added
+ *
+ * a strcat for array of xmlChar's. Since they are supposed to be
+ * encoded in UTF-8 or an encoding with 8bit based chars, we assume
+ * a termination mark of '0'.
+ *
+ * Returns a new xmlChar * containing the concatenated string.
+ */
+xmlChar *
+xmlStrcat(xmlChar *cur, const xmlChar *add) {
+    const xmlChar *p = add;
+
+    if (add == NULL) return(cur);
+    if (cur == NULL) 
+        return(xmlStrdup(add));
+
+    while (*p != 0) p++; /* non input consuming */
+    return(xmlStrncat(cur, add, p - add));
+}
+
+/************************************************************************
+ *									*
+ *		Commodity functions, cleanup needed ?			*
+ *									*
+ ************************************************************************/
+
+/**
+ * areBlanks:
+ * @ctxt:  an XML parser context
+ * @str:  a xmlChar *
+ * @len:  the size of @str
+ *
+ * Is this a sequence of blank chars that one can ignore ?
+ *
+ * Returns 1 if ignorable 0 otherwise.
+ */
+
+static int areBlanks(xmlParserCtxtPtr ctxt, const xmlChar *str, int len) {
+    int i, ret;
+    xmlNodePtr lastChild;
+
+    /*
+     * Check for xml:space value.
+     */
+    if (*(ctxt->space) == 1)
+	return(0);
+
+    /*
+     * Check that the string is made of blanks
+     */
+    for (i = 0;i < len;i++)
+        if (!(IS_BLANK(str[i]))) return(0);
+
+    /*
+     * Look if the element is mixed content in the Dtd if available
+     */
+    if (ctxt->myDoc != NULL) {
+	ret = xmlIsMixedElement(ctxt->myDoc, ctxt->node->name);
+        if (ret == 0) return(1);
+        if (ret == 1) return(0);
+    }
+
+    /*
+     * Otherwise, heuristic :-\
+     */
+    if (ctxt->keepBlanks)
+	return(0);
+    if (RAW != '<') return(0);
+    if (ctxt->node == NULL) return(0);
+    if ((ctxt->node->children == NULL) &&
+	(RAW == '<') && (NXT(1) == '/')) return(0);
+
+    lastChild = xmlGetLastChild(ctxt->node);
+    if (lastChild == NULL) {
+        if (ctxt->node->content != NULL) return(0);
+    } else if (xmlNodeIsText(lastChild))
+        return(0);
+    else if ((ctxt->node->children != NULL) &&
+             (xmlNodeIsText(ctxt->node->children)))
+        return(0);
+    return(1);
+}
+
+/*
+ * Forward definition for recusive behaviour.
+ */
+void xmlParsePEReference(xmlParserCtxtPtr ctxt);
+void xmlParseReference(xmlParserCtxtPtr ctxt);
+
+/************************************************************************
+ *									*
+ *		Extra stuff for namespace support			*
+ *	Relates to http://www.w3.org/TR/WD-xml-names			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSplitQName:
+ * @ctxt:  an XML parser context
+ * @name:  an XML parser context
+ * @prefix:  a xmlChar ** 
+ *
+ * parse an UTF8 encoded XML qualified name string
+ *
+ * [NS 5] QName ::= (Prefix ':')? LocalPart
+ *
+ * [NS 6] Prefix ::= NCName
+ *
+ * [NS 7] LocalPart ::= NCName
+ *
+ * Returns the local part, and prefix is updated
+ *   to get the Prefix if any.
+ */
+
+xmlChar *
+xmlSplitQName(xmlParserCtxtPtr ctxt, const xmlChar *name, xmlChar **prefix) {
+    xmlChar buf[XML_MAX_NAMELEN + 5];
+    xmlChar *buffer = NULL;
+    int len = 0;
+    int max = XML_MAX_NAMELEN;
+    xmlChar *ret = NULL;
+    const xmlChar *cur = name;
+    int c;
+
+    *prefix = NULL;
+
+#ifndef XML_XML_NAMESPACE
+    /* xml: prefix is not really a namespace */
+    if ((cur[0] == 'x') && (cur[1] == 'm') &&
+        (cur[2] == 'l') && (cur[3] == ':'))
+	return(xmlStrdup(name));
+#endif
+
+    /* nasty but valid */
+    if (cur[0] == ':')
+	return(xmlStrdup(name));
+
+    c = *cur++;
+    while ((c != 0) && (c != ':') && (len < max)) { /* tested bigname.xml */
+	buf[len++] = c;
+	c = *cur++;
+    }
+    if (len >= max) {
+	/*
+	 * Okay someone managed to make a huge name, so he's ready to pay
+	 * for the processing speed.
+	 */
+	max = len * 2;
+	
+	buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
+	if (buffer == NULL) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+				 "xmlSplitQName: out of memory\n");
+	    return(NULL);
+	}
+	memcpy(buffer, buf, len);
+	while ((c != 0) && (c != ':')) { /* tested bigname.xml */
+	    if (len + 10 > max) {
+		max *= 2;
+		buffer = (xmlChar *) xmlRealloc(buffer,
+						max * sizeof(xmlChar));
+		if (buffer == NULL) {
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+					 "xmlSplitQName: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    buffer[len++] = c;
+	    c = *cur++;
+	}
+	buffer[len] = 0;
+    }
+    
+    if (buffer == NULL)
+	ret = xmlStrndup(buf, len);
+    else {
+	ret = buffer;
+	buffer = NULL;
+	max = XML_MAX_NAMELEN;
+    }
+
+
+    if (c == ':') {
+	c = *cur++;
+	if (c == 0) return(ret);
+        *prefix = ret;
+	len = 0;
+
+	while ((c != 0) && (len < max)) { /* tested bigname2.xml */
+	    buf[len++] = c;
+	    c = *cur++;
+	}
+	if (len >= max) {
+	    /*
+	     * Okay someone managed to make a huge name, so he's ready to pay
+	     * for the processing speed.
+	     */
+	    max = len * 2;
+	    
+	    buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
+	    if (buffer == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+				     "xmlSplitQName: out of memory\n");
+		return(NULL);
+	    }
+	    memcpy(buffer, buf, len);
+	    while (c != 0) { /* tested bigname2.xml */
+		if (len + 10 > max) {
+		    max *= 2;
+		    buffer = (xmlChar *) xmlRealloc(buffer,
+						    max * sizeof(xmlChar));
+		    if (buffer == NULL) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+					     "xmlSplitQName: out of memory\n");
+			return(NULL);
+		    }
+		}
+		buffer[len++] = c;
+		c = *cur++;
+	    }
+	    buffer[len] = 0;
+	}
+	
+	if (buffer == NULL)
+	    ret = xmlStrndup(buf, len);
+	else {
+	    ret = buffer;
+	}
+    }
+
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *			The parser itself				*
+ *	Relates to http://www.w3.org/TR/REC-xml				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlParseName:
+ * @ctxt:  an XML parser context
+ *
+ * parse an XML name.
+ *
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ *                  CombiningChar | Extender
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * [6] Names ::= Name (S Name)*
+ *
+ * Returns the Name parsed or NULL
+ */
+
+xmlChar *
+xmlParseName(xmlParserCtxtPtr ctxt) {
+    xmlChar buf[XML_MAX_NAMELEN + 5];
+    int len = 0, l;
+    int c;
+    int count = 0;
+
+    GROW;
+    c = CUR_CHAR(l);
+    if ((c == ' ') || (c == '>') || (c == '/') || /* accelerators */
+	(!IS_LETTER(c) && (c != '_') &&
+         (c != ':'))) {
+	return(NULL);
+    }
+
+    while ((c != ' ') && (c != '>') && (c != '/') && /* test bigname.xml */
+	   ((IS_LETTER(c)) || (IS_DIGIT(c)) ||
+            (c == '.') || (c == '-') ||
+	    (c == '_') || (c == ':') || 
+	    (IS_COMBINING(c)) ||
+	    (IS_EXTENDER(c)))) {
+	if (count++ > 100) {
+	    count = 0;
+	    GROW;
+	}
+	COPY_BUF(l,buf,len,c);
+	NEXTL(l);
+	c = CUR_CHAR(l);
+	if (len >= XML_MAX_NAMELEN) {
+	    /*
+	     * Okay someone managed to make a huge name, so he's ready to pay
+	     * for the processing speed.
+	     */
+	    xmlChar *buffer;
+	    int max = len * 2;
+	    
+	    buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
+	    if (buffer == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+			             "xmlParseName: out of memory\n");
+		return(NULL);
+	    }
+	    memcpy(buffer, buf, len);
+	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigname.xml */
+		   (c == '.') || (c == '-') ||
+		   (c == '_') || (c == ':') || 
+		   (IS_COMBINING(c)) ||
+		   (IS_EXTENDER(c))) {
+		if (count++ > 100) {
+		    count = 0;
+		    GROW;
+		}
+		if (len + 10 > max) {
+		    max *= 2;
+		    buffer = (xmlChar *) xmlRealloc(buffer,
+			                            max * sizeof(xmlChar));
+		    if (buffer == NULL) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+					     "xmlParseName: out of memory\n");
+			return(NULL);
+		    }
+		}
+		COPY_BUF(l,buffer,len,c);
+		NEXTL(l);
+		c = CUR_CHAR(l);
+	    }
+	    buffer[len] = 0;
+	    return(buffer);
+	}
+    }
+    return(xmlStrndup(buf, len));
+}
+
+/**
+ * xmlParseStringName:
+ * @ctxt:  an XML parser context
+ * @str:  a pointer to the string pointer (IN/OUT)
+ *
+ * parse an XML name.
+ *
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ *                  CombiningChar | Extender
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * [6] Names ::= Name (S Name)*
+ *
+ * Returns the Name parsed or NULL. The str pointer 
+ * is updated to the current location in the string.
+ */
+
+xmlChar *
+xmlParseStringName(xmlParserCtxtPtr ctxt, const xmlChar** str) {
+    xmlChar buf[XML_MAX_NAMELEN + 5];
+    const xmlChar *cur = *str;
+    int len = 0, l;
+    int c;
+
+    c = CUR_SCHAR(cur, l);
+    if (!IS_LETTER(c) && (c != '_') &&
+        (c != ':')) {
+	return(NULL);
+    }
+
+    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigentname.xml */
+           (c == '.') || (c == '-') ||
+	   (c == '_') || (c == ':') || 
+	   (IS_COMBINING(c)) ||
+	   (IS_EXTENDER(c))) {
+	COPY_BUF(l,buf,len,c);
+	cur += l;
+	c = CUR_SCHAR(cur, l);
+	if (len >= XML_MAX_NAMELEN) { /* test bigentname.xml */
+	    /*
+	     * Okay someone managed to make a huge name, so he's ready to pay
+	     * for the processing speed.
+	     */
+	    xmlChar *buffer;
+	    int max = len * 2;
+	    
+	    buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
+	    if (buffer == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+			             "xmlParseStringName: out of memory\n");
+		return(NULL);
+	    }
+	    memcpy(buffer, buf, len);
+	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigentname.xml */
+		   (c == '.') || (c == '-') ||
+		   (c == '_') || (c == ':') || 
+		   (IS_COMBINING(c)) ||
+		   (IS_EXTENDER(c))) {
+		if (len + 10 > max) {
+		    max *= 2;
+		    buffer = (xmlChar *) xmlRealloc(buffer,
+			                            max * sizeof(xmlChar));
+		    if (buffer == NULL) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				     "xmlParseStringName: out of memory\n");
+			return(NULL);
+		    }
+		}
+		COPY_BUF(l,buffer,len,c);
+		cur += l;
+		c = CUR_SCHAR(cur, l);
+	    }
+	    buffer[len] = 0;
+	    *str = cur;
+	    return(buffer);
+	}
+    }
+    *str = cur;
+    return(xmlStrndup(buf, len));
+}
+
+/**
+ * xmlParseNmtoken:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML Nmtoken.
+ *
+ * [7] Nmtoken ::= (NameChar)+
+ *
+ * [8] Nmtokens ::= Nmtoken (S Nmtoken)*
+ *
+ * Returns the Nmtoken parsed or NULL
+ */
+
+xmlChar *
+xmlParseNmtoken(xmlParserCtxtPtr ctxt) {
+    xmlChar buf[XML_MAX_NAMELEN + 5];
+    int len = 0, l;
+    int c;
+    int count = 0;
+
+    GROW;
+    c = CUR_CHAR(l);
+
+    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigtoken.xml */
+           (c == '.') || (c == '-') ||
+	   (c == '_') || (c == ':') || 
+	   (IS_COMBINING(c)) ||
+	   (IS_EXTENDER(c))) {
+	if (count++ > 100) {
+	    count = 0;
+	    GROW;
+	}
+	COPY_BUF(l,buf,len,c);
+	NEXTL(l);
+	c = CUR_CHAR(l);
+	if (len >= XML_MAX_NAMELEN) {
+	    /*
+	     * Okay someone managed to make a huge token, so he's ready to pay
+	     * for the processing speed.
+	     */
+	    xmlChar *buffer;
+	    int max = len * 2;
+	    
+	    buffer = (xmlChar *) xmlMalloc(max * sizeof(xmlChar));
+	    if (buffer == NULL) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+			             "xmlParseNmtoken: out of memory\n");
+		return(NULL);
+	    }
+	    memcpy(buffer, buf, len);
+	    while ((IS_LETTER(c)) || (IS_DIGIT(c)) || /* test bigtoken.xml */
+		   (c == '.') || (c == '-') ||
+		   (c == '_') || (c == ':') || 
+		   (IS_COMBINING(c)) ||
+		   (IS_EXTENDER(c))) {
+		if (count++ > 100) {
+		    count = 0;
+		    GROW;
+		}
+		if (len + 10 > max) {
+		    max *= 2;
+		    buffer = (xmlChar *) xmlRealloc(buffer,
+			                            max * sizeof(xmlChar));
+		    if (buffer == NULL) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+					     "xmlParseName: out of memory\n");
+			return(NULL);
+		    }
+		}
+		COPY_BUF(l,buffer,len,c);
+		NEXTL(l);
+		c = CUR_CHAR(l);
+	    }
+	    buffer[len] = 0;
+	    return(buffer);
+	}
+    }
+    if (len == 0)
+        return(NULL);
+    return(xmlStrndup(buf, len));
+}
+
+/**
+ * xmlParseEntityValue:
+ * @ctxt:  an XML parser context
+ * @orig:  if non-NULL store a copy of the original entity value
+ *
+ * parse a value for ENTITY declarations
+ *
+ * [9] EntityValue ::= '"' ([^%&"] | PEReference | Reference)* '"' |
+ *	               "'" ([^%&'] | PEReference | Reference)* "'"
+ *
+ * Returns the EntityValue parsed with reference substitued or NULL
+ */
+
+xmlChar *
+xmlParseEntityValue(xmlParserCtxtPtr ctxt, xmlChar **orig) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = XML_PARSER_BUFFER_SIZE;
+    int c, l;
+    xmlChar stop;
+    xmlChar *ret = NULL;
+    const xmlChar *cur = NULL;
+    xmlParserInputPtr input;
+
+    if (RAW == '"') stop = '"';
+    else if (RAW == '\'') stop = '\'';
+    else {
+	ctxt->errNo = XML_ERR_ENTITY_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "EntityValue: \" or ' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	return(NULL);
+    }
+
+    /*
+     * The content of the entity definition is copied in a buffer.
+     */
+
+    ctxt->instate = XML_PARSER_ENTITY_VALUE;
+    input = ctxt->input;
+    GROW;
+    NEXT;
+    c = CUR_CHAR(l);
+    /*
+     * NOTE: 4.4.5 Included in Literal
+     * When a parameter entity reference appears in a literal entity
+     * value, ... a single or double quote character in the replacement
+     * text is always treated as a normal data character and will not
+     * terminate the literal. 
+     * In practice it means we stop the loop only when back at parsing
+     * the initial entity and the quote is found
+     */
+    while ((IS_CHAR(c)) && ((c != stop) || /* checked */
+	   (ctxt->input != input))) {
+	if (len + 5 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		return(NULL);
+	    }
+	}
+	COPY_BUF(l,buf,len,c);
+	NEXTL(l);
+	/*
+	 * Pop-up of finished entities.
+	 */
+	while ((RAW == 0) && (ctxt->inputNr > 1)) /* non input consuming */
+	    xmlPopInput(ctxt);
+
+	GROW;
+	c = CUR_CHAR(l);
+	if (c == 0) {
+	    GROW;
+	    c = CUR_CHAR(l);
+	}
+    }
+    buf[len] = 0;
+
+    /*
+     * Raise problem w.r.t. '&' and '%' being used in non-entities
+     * reference constructs. Note Charref will be handled in
+     * xmlStringDecodeEntities()
+     */
+    cur = buf;
+    while (*cur != 0) { /* non input consuming */
+	if ((*cur == '%') || ((*cur == '&') && (cur[1] != '#'))) {
+	    xmlChar *name;
+	    xmlChar tmp = *cur;
+
+	    cur++;
+	    name = xmlParseStringName(ctxt, &cur);
+            if ((name == NULL) || (*cur != ';')) {
+		ctxt->errNo = XML_ERR_ENTITY_CHAR_ERROR;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+	    "EntityValue: '%c' forbidden except for entities references\n",
+	                             tmp);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    if ((ctxt->inSubset == 1) && (tmp == '%')) {
+		ctxt->errNo = XML_ERR_ENTITY_PE_INTERNAL;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+	    "EntityValue: PEReferences forbidden in internal subset\n",
+	                             tmp);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    if (name != NULL)
+		xmlFree(name);
+	}
+	cur++;
+    }
+
+    /*
+     * Then PEReference entities are substituted.
+     */
+    if (c != stop) {
+	ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "EntityValue: \" expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	xmlFree(buf);
+    } else {
+	NEXT;
+	/*
+	 * NOTE: 4.4.7 Bypassed
+	 * When a general entity reference appears in the EntityValue in
+	 * an entity declaration, it is bypassed and left as is.
+	 * so XML_SUBSTITUTE_REF is not set here.
+	 */
+	ret = xmlStringDecodeEntities(ctxt, buf, XML_SUBSTITUTE_PEREF,
+				      0, 0, 0);
+	if (orig != NULL) 
+	    *orig = buf;
+	else
+	    xmlFree(buf);
+    }
+    
+    return(ret);
+}
+
+/**
+ * xmlParseAttValue:
+ * @ctxt:  an XML parser context
+ *
+ * parse a value for an attribute
+ * Note: the parser won't do substitution of entities here, this
+ * will be handled later in xmlStringGetNodeList
+ *
+ * [10] AttValue ::= '"' ([^<&"] | Reference)* '"' |
+ *                   "'" ([^<&'] | Reference)* "'"
+ *
+ * 3.3.3 Attribute-Value Normalization:
+ * Before the value of an attribute is passed to the application or
+ * checked for validity, the XML processor must normalize it as follows: 
+ * - a character reference is processed by appending the referenced
+ *   character to the attribute value
+ * - an entity reference is processed by recursively processing the
+ *   replacement text of the entity 
+ * - a whitespace character (#x20, #xD, #xA, #x9) is processed by
+ *   appending #x20 to the normalized value, except that only a single
+ *   #x20 is appended for a "#xD#xA" sequence that is part of an external
+ *   parsed entity or the literal entity value of an internal parsed entity 
+ * - other characters are processed by appending them to the normalized value 
+ * If the declared value is not CDATA, then the XML processor must further
+ * process the normalized attribute value by discarding any leading and
+ * trailing space (#x20) characters, and by replacing sequences of space
+ * (#x20) characters by a single space (#x20) character.  
+ * All attributes for which no declaration has been read should be treated
+ * by a non-validating parser as if declared CDATA.
+ *
+ * Returns the AttValue parsed or NULL. The value has to be freed by the caller.
+ */
+
+xmlChar *
+xmlParseAttValue(xmlParserCtxtPtr ctxt) {
+    xmlChar limit = 0;
+    xmlChar *buf = NULL;
+    int len = 0;
+    int buf_size = 0;
+    int c, l;
+    xmlChar *current = NULL;
+    xmlEntityPtr ent;
+
+
+    SHRINK;
+    if (NXT(0) == '"') {
+	ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
+	limit = '"';
+        NEXT;
+    } else if (NXT(0) == '\'') {
+	limit = '\'';
+	ctxt->instate = XML_PARSER_ATTRIBUTE_VALUE;
+        NEXT;
+    } else {
+	ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "AttValue: \" or ' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+    
+    /*
+     * allocate a translation buffer.
+     */
+    buf_size = XML_PARSER_BUFFER_SIZE;
+    buf = (xmlChar *) xmlMalloc(buf_size * sizeof(xmlChar));
+    if (buf == NULL) {
+	perror("xmlParseAttValue: malloc failed");
+	return(NULL);
+    }
+
+    /*
+     * Ok loop until we reach one of the ending char or a size limit.
+     */
+    c = CUR_CHAR(l);
+    while (((NXT(0) != limit) && /* checked */
+	   (c != '<')) || (ctxt->token != 0)) {
+	if (c == 0) break;
+	if (ctxt->token == '&') {
+	    /*
+	     * The reparsing will be done in xmlStringGetNodeList()
+	     * called by the attribute() function in SAX.c
+	     */
+	    static xmlChar buffer[6] = "&#38;";
+
+	    if (len > buf_size - 10) {
+		growBuffer(buf);
+	    }
+	    current = &buffer[0];
+	    while (*current != 0) { /* non input consuming */
+		buf[len++] = *current++;
+	    }
+	    ctxt->token = 0;
+	} else if (c == '&') {
+	    if (NXT(1) == '#') {
+		int val = xmlParseCharRef(ctxt);
+		if (val == '&') {
+		    /*
+		     * The reparsing will be done in xmlStringGetNodeList()
+		     * called by the attribute() function in SAX.c
+		     */
+		    static xmlChar buffer[6] = "&#38;";
+
+		    if (len > buf_size - 10) {
+			growBuffer(buf);
+		    }
+		    current = &buffer[0];
+		    while (*current != 0) { /* non input consuming */
+			buf[len++] = *current++;
+		    }
+		} else {
+		    len += xmlCopyChar(0, &buf[len], val);
+		}
+	    } else {
+		ent = xmlParseEntityRef(ctxt);
+		if ((ent != NULL) && 
+		    (ctxt->replaceEntities != 0)) {
+		    xmlChar *rep;
+
+		    if (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) {
+			rep = xmlStringDecodeEntities(ctxt, ent->content,
+						      XML_SUBSTITUTE_REF, 0, 0, 0);
+			if (rep != NULL) {
+			    current = rep;
+			    while (*current != 0) { /* non input consuming */
+				buf[len++] = *current++;
+				if (len > buf_size - 10) {
+				    growBuffer(buf);
+				}
+			    }
+			    xmlFree(rep);
+			}
+		    } else {
+			if (ent->content != NULL)
+			    buf[len++] = ent->content[0];
+		    }
+		} else if (ent != NULL) {
+		    int i = xmlStrlen(ent->name);
+		    const xmlChar *cur = ent->name;
+
+		    /*
+		     * This may look absurd but is needed to detect
+		     * entities problems
+		     */
+		    if ((ent->etype != XML_INTERNAL_PREDEFINED_ENTITY) &&
+			(ent->content != NULL)) {
+			xmlChar *rep;
+			rep = xmlStringDecodeEntities(ctxt, ent->content,
+						      XML_SUBSTITUTE_REF, 0, 0, 0);
+			if (rep != NULL)
+			    xmlFree(rep);
+		    }
+
+		    /*
+		     * Just output the reference
+		     */
+		    buf[len++] = '&';
+		    if (len > buf_size - i - 10) {
+			growBuffer(buf);
+		    }
+		    for (;i > 0;i--)
+			buf[len++] = *cur++;
+		    buf[len++] = ';';
+		}
+	    }
+	} else {
+	    if ((c == 0x20) || (c == 0xD) || (c == 0xA) || (c == 0x9)) {
+		COPY_BUF(l,buf,len,0x20);
+		if (len > buf_size - 10) {
+		    growBuffer(buf);
+		}
+	    } else {
+		COPY_BUF(l,buf,len,c);
+		if (len > buf_size - 10) {
+		    growBuffer(buf);
+		}
+	    }
+	    NEXTL(l);
+	}
+	GROW;
+	c = CUR_CHAR(l);
+    }
+    buf[len++] = 0;
+    if (RAW == '<') {
+	ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	       "Unescaped '<' not allowed in attributes values\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else if (RAW != limit) {
+	ctxt->errNo = XML_ERR_ATTRIBUTE_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "AttValue: ' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else
+	NEXT;
+    return(buf);
+}
+
+/**
+ * xmlParseSystemLiteral:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML Literal
+ *
+ * [11] SystemLiteral ::= ('"' [^"]* '"') | ("'" [^']* "'")
+ *
+ * Returns the SystemLiteral parsed or NULL
+ */
+
+xmlChar *
+xmlParseSystemLiteral(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = XML_PARSER_BUFFER_SIZE;
+    int cur, l;
+    xmlChar stop;
+    int state = ctxt->instate;
+    int count = 0;
+
+    SHRINK;
+    if (RAW == '"') {
+        NEXT;
+	stop = '"';
+    } else if (RAW == '\'') {
+        NEXT;
+	stop = '\'';
+    } else {
+	ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "SystemLiteral \" or ' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+    
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	return(NULL);
+    }
+    ctxt->instate = XML_PARSER_SYSTEM_LITERAL;
+    cur = CUR_CHAR(l);
+    while ((IS_CHAR(cur)) && (cur != stop)) { /* checked */
+	if (len + 5 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		ctxt->instate = (xmlParserInputState) state;
+		return(NULL);
+	    }
+	}
+	count++;
+	if (count > 50) {
+	    GROW;
+	    count = 0;
+	}
+	COPY_BUF(l,buf,len,cur);
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+	if (cur == 0) {
+	    GROW;
+	    SHRINK;
+	    cur = CUR_CHAR(l);
+	}
+    }
+    buf[len] = 0;
+    ctxt->instate = (xmlParserInputState) state;
+    if (!IS_CHAR(cur)) {
+	ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Unfinished SystemLiteral\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else {
+	NEXT;
+    }
+    return(buf);
+}
+
+/**
+ * xmlParsePubidLiteral:
+ * @ctxt:  an XML parser context
+ *
+ * parse an XML public literal
+ *
+ * [12] PubidLiteral ::= '"' PubidChar* '"' | "'" (PubidChar - "'")* "'"
+ *
+ * Returns the PubidLiteral parsed or NULL.
+ */
+
+xmlChar *
+xmlParsePubidLiteral(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = XML_PARSER_BUFFER_SIZE;
+    xmlChar cur;
+    xmlChar stop;
+    int count = 0;
+
+    SHRINK;
+    if (RAW == '"') {
+        NEXT;
+	stop = '"';
+    } else if (RAW == '\'') {
+        NEXT;
+	stop = '\'';
+    } else {
+	ctxt->errNo = XML_ERR_LITERAL_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "SystemLiteral \" or ' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	return(NULL);
+    }
+    cur = CUR;
+    while ((IS_PUBIDCHAR(cur)) && (cur != stop)) { /* checked */
+	if (len + 1 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		return(NULL);
+	    }
+	}
+	buf[len++] = cur;
+	count++;
+	if (count > 50) {
+	    GROW;
+	    count = 0;
+	}
+	NEXT;
+	cur = CUR;
+	if (cur == 0) {
+	    GROW;
+	    SHRINK;
+	    cur = CUR;
+	}
+    }
+    buf[len] = 0;
+    if (cur != stop) {
+	ctxt->errNo = XML_ERR_LITERAL_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Unfinished PubidLiteral\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else {
+	NEXT;
+    }
+    return(buf);
+}
+
+/**
+ * xmlParseCharData:
+ * @ctxt:  an XML parser context
+ * @cdata:  int indicating whether we are within a CDATA section
+ *
+ * parse a CharData section.
+ * if we are within a CDATA section ']]>' marks an end of section.
+ *
+ * The right angle bracket (>) may be represented using the string "&gt;",
+ * and must, for compatibility, be escaped using "&gt;" or a character
+ * reference when it appears in the string "]]>" in content, when that
+ * string is not marking the end of a CDATA section. 
+ *
+ * [14] CharData ::= [^<&]* - ([^<&]* ']]>' [^<&]*)
+ */
+
+void
+xmlParseCharData(xmlParserCtxtPtr ctxt, int cdata) {
+    xmlChar buf[XML_PARSER_BIG_BUFFER_SIZE + 5];
+    int nbchar = 0;
+    int cur, l;
+    int count = 0;
+
+    SHRINK;
+    GROW;
+    cur = CUR_CHAR(l);
+    while (((cur != '<') || (ctxt->token == '<')) && /* checked */
+           ((cur != '&') || (ctxt->token == '&')) && 
+	    (IS_CHAR(cur))) /* test also done in xmlCurrentChar() */ {
+	if ((cur == ']') && (NXT(1) == ']') &&
+	    (NXT(2) == '>')) {
+	    if (cdata) break;
+	    else {
+		ctxt->errNo = XML_ERR_MISPLACED_CDATA_END;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		       "Sequence ']]>' not allowed in content\n");
+		/* Should this be relaxed ??? I see a "must here */
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	}
+	COPY_BUF(l,buf,nbchar,cur);
+	if (nbchar >= XML_PARSER_BIG_BUFFER_SIZE) {
+	    /*
+	     * Ok the segment is to be consumed as chars.
+	     */
+	    if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+		if (areBlanks(ctxt, buf, nbchar)) {
+		    if (ctxt->sax->ignorableWhitespace != NULL)
+			ctxt->sax->ignorableWhitespace(ctxt->userData,
+			                               buf, nbchar);
+		} else {
+		    if (ctxt->sax->characters != NULL)
+			ctxt->sax->characters(ctxt->userData, buf, nbchar);
+		}
+	    }
+	    nbchar = 0;
+	}
+	count++;
+	if (count > 50) {
+	    GROW;
+	    count = 0;
+	}
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+    }
+    if (nbchar != 0) {
+	/*
+	 * Ok the segment is to be consumed as chars.
+	 */
+	if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+	    if (areBlanks(ctxt, buf, nbchar)) {
+		if (ctxt->sax->ignorableWhitespace != NULL)
+		    ctxt->sax->ignorableWhitespace(ctxt->userData, buf, nbchar);
+	    } else {
+		if (ctxt->sax->characters != NULL)
+		    ctxt->sax->characters(ctxt->userData, buf, nbchar);
+	    }
+	}
+    }
+}
+
+/**
+ * xmlParseExternalID:
+ * @ctxt:  an XML parser context
+ * @publicID:  a xmlChar** receiving PubidLiteral
+ * @strict: indicate whether we should restrict parsing to only
+ *          production [75], see NOTE below
+ *
+ * Parse an External ID or a Public ID
+ *
+ * NOTE: Productions [75] and [83] interract badly since [75] can generate
+ *       'PUBLIC' S PubidLiteral S SystemLiteral
+ *
+ * [75] ExternalID ::= 'SYSTEM' S SystemLiteral
+ *                   | 'PUBLIC' S PubidLiteral S SystemLiteral
+ *
+ * [83] PublicID ::= 'PUBLIC' S PubidLiteral
+ *
+ * Returns the function returns SystemLiteral and in the second
+ *                case publicID receives PubidLiteral, is strict is off
+ *                it is possible to return NULL and have publicID set.
+ */
+
+xmlChar *
+xmlParseExternalID(xmlParserCtxtPtr ctxt, xmlChar **publicID, int strict) {
+    xmlChar *URI = NULL;
+
+    SHRINK;
+    if ((RAW == 'S') && (NXT(1) == 'Y') &&
+         (NXT(2) == 'S') && (NXT(3) == 'T') &&
+	 (NXT(4) == 'E') && (NXT(5) == 'M')) {
+        SKIP(6);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Space required after 'SYSTEM'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        SKIP_BLANKS;
+	URI = xmlParseSystemLiteral(ctxt);
+	if (URI == NULL) {
+	    ctxt->errNo = XML_ERR_URI_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+	          "xmlParseExternalID: SYSTEM, no URI\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+        }
+    } else if ((RAW == 'P') && (NXT(1) == 'U') &&
+	       (NXT(2) == 'B') && (NXT(3) == 'L') &&
+	       (NXT(4) == 'I') && (NXT(5) == 'C')) {
+        SKIP(6);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Space required after 'PUBLIC'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        SKIP_BLANKS;
+	*publicID = xmlParsePubidLiteral(ctxt);
+	if (*publicID == NULL) {
+	    ctxt->errNo = XML_ERR_PUBID_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	          "xmlParseExternalID: PUBLIC, no Public Identifier\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	if (strict) {
+	    /*
+	     * We don't handle [83] so "S SystemLiteral" is required.
+	     */
+	    if (!IS_BLANK(CUR)) {
+		ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+			"Space required after the Public Identifier\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	} else {
+	    /*
+	     * We handle [83] so we return immediately, if 
+	     * "S SystemLiteral" is not detected. From a purely parsing
+	     * point of view that's a nice mess.
+	     */
+	    const xmlChar *ptr;
+	    GROW;
+
+	    ptr = CUR_PTR;
+	    if (!IS_BLANK(*ptr)) return(NULL);
+	    
+	    while (IS_BLANK(*ptr)) ptr++; /* TODO: dangerous, fix ! */
+	    if ((*ptr != '\'') && (*ptr != '"')) return(NULL);
+	}
+        SKIP_BLANKS;
+	URI = xmlParseSystemLiteral(ctxt);
+	if (URI == NULL) {
+	    ctxt->errNo = XML_ERR_URI_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	           "xmlParseExternalID: PUBLIC, no URI\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+        }
+    }
+    return(URI);
+}
+
+/**
+ * xmlParseComment:
+ * @ctxt:  an XML parser context
+ *
+ * Skip an XML (SGML) comment <!-- .... -->
+ *  The spec says that "For compatibility, the string "--" (double-hyphen)
+ *  must not occur within comments. "
+ *
+ * [15] Comment ::= '<!--' ((Char - '-') | ('-' (Char - '-')))* '-->'
+ */
+void
+xmlParseComment(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len;
+    int size = XML_PARSER_BUFFER_SIZE;
+    int q, ql;
+    int r, rl;
+    int cur, l;
+    xmlParserInputState state;
+    xmlParserInputPtr input = ctxt->input;
+    int count = 0;
+
+    /*
+     * Check that there is a comment right here.
+     */
+    if ((RAW != '<') || (NXT(1) != '!') ||
+        (NXT(2) != '-') || (NXT(3) != '-')) return;
+
+    state = ctxt->instate;
+    ctxt->instate = XML_PARSER_COMMENT;
+    SHRINK;
+    SKIP(4);
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	ctxt->instate = state;
+	return;
+    }
+    q = CUR_CHAR(ql);
+    NEXTL(ql);
+    r = CUR_CHAR(rl);
+    NEXTL(rl);
+    cur = CUR_CHAR(l);
+    len = 0;
+    while (IS_CHAR(cur) && /* checked */
+           ((cur != '>') ||
+	    (r != '-') || (q != '-'))) {
+	if ((r == '-') && (q == '-') && (len > 1)) {
+	    ctxt->errNo = XML_ERR_HYPHEN_IN_COMMENT;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+	       "Comment must not contain '--' (double-hyphen)`\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	if (len + 5 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		ctxt->instate = state;
+		return;
+	    }
+	}
+	COPY_BUF(ql,buf,len,q);
+	q = r;
+	ql = rl;
+	r = cur;
+	rl = l;
+
+	count++;
+	if (count > 50) {
+	    GROW;
+	    count = 0;
+	}
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+	if (cur == 0) {
+	    SHRINK;
+	    GROW;
+	    cur = CUR_CHAR(l);
+	}
+    }
+    buf[len] = 0;
+    if (!IS_CHAR(cur)) {
+	ctxt->errNo = XML_ERR_COMMENT_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "Comment not terminated \n<!--%.50s\n", buf);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	xmlFree(buf);
+    } else {
+	if (input != ctxt->input) {
+	    ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+"Comment doesn't start and stop in the same entity\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        NEXT;
+	if ((ctxt->sax != NULL) && (ctxt->sax->comment != NULL) &&
+	    (!ctxt->disableSAX))
+	    ctxt->sax->comment(ctxt->userData, buf);
+	xmlFree(buf);
+    }
+    ctxt->instate = state;
+}
+
+/**
+ * xmlParsePITarget:
+ * @ctxt:  an XML parser context
+ * 
+ * parse the name of a PI
+ *
+ * [17] PITarget ::= Name - (('X' | 'x') ('M' | 'm') ('L' | 'l'))
+ *
+ * Returns the PITarget name or NULL
+ */
+
+xmlChar *
+xmlParsePITarget(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+
+    name = xmlParseName(ctxt);
+    if ((name != NULL) &&
+        ((name[0] == 'x') || (name[0] == 'X')) &&
+        ((name[1] == 'm') || (name[1] == 'M')) &&
+        ((name[2] == 'l') || (name[2] == 'L'))) {
+	int i;
+	if ((name[0] == 'x') && (name[1] == 'm') &&
+	    (name[2] == 'l') && (name[3] == 0)) {
+	    ctxt->errNo = XML_ERR_RESERVED_XML_NAME;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		 "XML declaration allowed only at the start of the document\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(name);
+	} else if (name[3] == 0) {
+	    ctxt->errNo = XML_ERR_RESERVED_XML_NAME;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, "Invalid PI name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(name);
+	}
+	for (i = 0;;i++) {
+	    if (xmlW3CPIs[i] == NULL) break;
+	    if (xmlStrEqual(name, (const xmlChar *)xmlW3CPIs[i]))
+	        return(name);
+	}
+	if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL)) {
+	    ctxt->errNo = XML_ERR_RESERVED_XML_NAME;
+	    ctxt->sax->warning(ctxt->userData,
+	         "xmlParsePItarget: invalid name prefix 'xml'\n");
+	}
+    }
+    return(name);
+}
+
+/**
+ * xmlParsePI:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML Processing Instruction.
+ *
+ * [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
+ *
+ * The processing is transfered to SAX once parsed.
+ */
+
+void
+xmlParsePI(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = XML_PARSER_BUFFER_SIZE;
+    int cur, l;
+    xmlChar *target;
+    xmlParserInputState state;
+    int count = 0;
+
+    if ((RAW == '<') && (NXT(1) == '?')) {
+	xmlParserInputPtr input = ctxt->input;
+	state = ctxt->instate;
+        ctxt->instate = XML_PARSER_PI;
+	/*
+	 * this is a Processing Instruction.
+	 */
+	SKIP(2);
+	SHRINK;
+
+	/*
+	 * Parse the target name and check for special support like
+	 * namespace.
+	 */
+        target = xmlParsePITarget(ctxt);
+	if (target != NULL) {
+	    if ((RAW == '?') && (NXT(1) == '>')) {
+		if (input != ctxt->input) {
+		    ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+    "PI declaration doesn't start and stop in the same entity\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		SKIP(2);
+
+		/*
+		 * SAX: PI detected.
+		 */
+		if ((ctxt->sax) && (!ctxt->disableSAX) &&
+		    (ctxt->sax->processingInstruction != NULL))
+		    ctxt->sax->processingInstruction(ctxt->userData,
+		                                     target, NULL);
+		ctxt->instate = state;
+		xmlFree(target);
+		return;
+	    }
+	    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"malloc of %d byte failed\n", size);
+		ctxt->instate = state;
+		return;
+	    }
+	    cur = CUR;
+	    if (!IS_BLANK(cur)) {
+		ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "xmlParsePI: PI %s space expected\n", target);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+            SKIP_BLANKS;
+	    cur = CUR_CHAR(l);
+	    while (IS_CHAR(cur) && /* checked */
+		   ((cur != '?') || (NXT(1) != '>'))) {
+		if (len + 5 >= size) {
+		    size *= 2;
+		    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+		    if (buf == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"realloc of %d byte failed\n", size);
+			ctxt->instate = state;
+			return;
+		    }
+		}
+		count++;
+		if (count > 50) {
+		    GROW;
+		    count = 0;
+		}
+		COPY_BUF(l,buf,len,cur);
+		NEXTL(l);
+		cur = CUR_CHAR(l);
+		if (cur == 0) {
+		    SHRINK;
+		    GROW;
+		    cur = CUR_CHAR(l);
+		}
+	    }
+	    buf[len] = 0;
+	    if (cur != '?') {
+		ctxt->errNo = XML_ERR_PI_NOT_FINISHED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "xmlParsePI: PI %s never end ...\n", target);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else {
+		if (input != ctxt->input) {
+		    ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+    "PI declaration doesn't start and stop in the same entity\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		SKIP(2);
+
+		/*
+		 * SAX: PI detected.
+		 */
+		if ((ctxt->sax) && (!ctxt->disableSAX) &&
+		    (ctxt->sax->processingInstruction != NULL))
+		    ctxt->sax->processingInstruction(ctxt->userData,
+		                                     target, buf);
+	    }
+	    xmlFree(buf);
+	    xmlFree(target);
+	} else {
+	    ctxt->errNo = XML_ERR_PI_NOT_STARTED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		       "xmlParsePI : no target name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	ctxt->instate = state;
+    }
+}
+
+/**
+ * xmlParseNotationDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse a notation declaration
+ *
+ * [82] NotationDecl ::= '<!NOTATION' S Name S (ExternalID |  PublicID) S? '>'
+ *
+ * Hence there is actually 3 choices:
+ *     'PUBLIC' S PubidLiteral
+ *     'PUBLIC' S PubidLiteral S SystemLiteral
+ * and 'SYSTEM' S SystemLiteral
+ *
+ * See the NOTE on xmlParseExternalID().
+ */
+
+void
+xmlParseNotationDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *Pubid;
+    xmlChar *Systemid;
+    
+    if ((RAW == '<') && (NXT(1) == '!') &&
+        (NXT(2) == 'N') && (NXT(3) == 'O') &&
+        (NXT(4) == 'T') && (NXT(5) == 'A') &&
+        (NXT(6) == 'T') && (NXT(7) == 'I') &&
+        (NXT(8) == 'O') && (NXT(9) == 'N')) {
+	xmlParserInputPtr input = ctxt->input;
+	SHRINK;
+	SKIP(10);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		                 "Space required after '<!NOTATION'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	}
+	SKIP_BLANKS;
+
+        name = xmlParseName(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "NOTATION: Name expected here\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	}
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		     "Space required after the NOTATION name'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	}
+	SKIP_BLANKS;
+
+	/*
+	 * Parse the IDs.
+	 */
+	Systemid = xmlParseExternalID(ctxt, &Pubid, 0);
+	SKIP_BLANKS;
+
+	if (RAW == '>') {
+	    if (input != ctxt->input) {
+		ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+"Notation declaration doesn't start and stop in the same entity\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    NEXT;
+	    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+		(ctxt->sax->notationDecl != NULL))
+		ctxt->sax->notationDecl(ctxt->userData, name, Pubid, Systemid);
+	} else {
+	    ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		       "'>' required to close NOTATION declaration\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	xmlFree(name);
+	if (Systemid != NULL) xmlFree(Systemid);
+	if (Pubid != NULL) xmlFree(Pubid);
+    }
+}
+
+/**
+ * xmlParseEntityDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse <!ENTITY declarations
+ *
+ * [70] EntityDecl ::= GEDecl | PEDecl
+ *
+ * [71] GEDecl ::= '<!ENTITY' S Name S EntityDef S? '>'
+ *
+ * [72] PEDecl ::= '<!ENTITY' S '%' S Name S PEDef S? '>'
+ *
+ * [73] EntityDef ::= EntityValue | (ExternalID NDataDecl?)
+ *
+ * [74] PEDef ::= EntityValue | ExternalID
+ *
+ * [76] NDataDecl ::= S 'NDATA' S Name
+ *
+ * [ VC: Notation Declared ]
+ * The Name must match the declared name of a notation.
+ */
+
+void
+xmlParseEntityDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *name = NULL;
+    xmlChar *value = NULL;
+    xmlChar *URI = NULL, *literal = NULL;
+    xmlChar *ndata = NULL;
+    int isParameter = 0;
+    xmlChar *orig = NULL;
+    
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '!') &&
+        (NXT(2) == 'E') && (NXT(3) == 'N') &&
+        (NXT(4) == 'T') && (NXT(5) == 'I') &&
+        (NXT(6) == 'T') && (NXT(7) == 'Y')) {
+	xmlParserInputPtr input = ctxt->input;
+	ctxt->instate = XML_PARSER_ENTITY_DECL;
+	SHRINK;
+	SKIP(8);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		                 "Space required after '<!ENTITY'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	SKIP_BLANKS;
+
+	if (RAW == '%') {
+	    NEXT;
+	    if (!IS_BLANK(CUR)) {
+		ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "Space required after '%'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    SKIP_BLANKS;
+	    isParameter = 1;
+	}
+
+        name = xmlParseName(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "xmlParseEntityDecl: no name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+            return;
+	}
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		     "Space required after the entity name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        SKIP_BLANKS;
+
+	/*
+	 * handle the various case of definitions...
+	 */
+	if (isParameter) {
+	    if ((RAW == '"') || (RAW == '\'')) {
+	        value = xmlParseEntityValue(ctxt, &orig);
+		if (value) {
+		    if ((ctxt->sax != NULL) &&
+			(!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL))
+			ctxt->sax->entityDecl(ctxt->userData, name,
+		                    XML_INTERNAL_PARAMETER_ENTITY,
+				    NULL, NULL, value);
+		}
+	    } else {
+	        URI = xmlParseExternalID(ctxt, &literal, 1);
+		if ((URI == NULL) && (literal == NULL)) {
+		    ctxt->errNo = XML_ERR_VALUE_REQUIRED;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			    "Entity value required\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		if (URI) {
+		    xmlURIPtr uri;
+
+		    uri = xmlParseURI((const char *) URI);
+		    if (uri == NULL) {
+			ctxt->errNo = XML_ERR_INVALID_URI;
+			if ((ctxt->sax != NULL) &&
+			    (!ctxt->disableSAX) &&
+			    (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				        "Invalid URI: %s\n", URI);
+			ctxt->wellFormed = 0;
+		    } else {
+			if (uri->fragment != NULL) {
+			    ctxt->errNo = XML_ERR_URI_FRAGMENT;
+			    if ((ctxt->sax != NULL) &&
+				(!ctxt->disableSAX) &&
+				(ctxt->sax->error != NULL))
+				ctxt->sax->error(ctxt->userData,
+					    "Fragment not allowed: %s\n", URI);
+			    ctxt->wellFormed = 0;
+			} else {
+			    if ((ctxt->sax != NULL) &&
+				(!ctxt->disableSAX) &&
+				(ctxt->sax->entityDecl != NULL))
+				ctxt->sax->entityDecl(ctxt->userData, name,
+					    XML_EXTERNAL_PARAMETER_ENTITY,
+					    literal, URI, NULL);
+			}
+			xmlFreeURI(uri);
+		    }
+		}
+	    }
+	} else {
+	    if ((RAW == '"') || (RAW == '\'')) {
+	        value = xmlParseEntityValue(ctxt, &orig);
+		if ((ctxt->sax != NULL) &&
+		    (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL))
+		    ctxt->sax->entityDecl(ctxt->userData, name,
+				XML_INTERNAL_GENERAL_ENTITY,
+				NULL, NULL, value);
+	    } else {
+	        URI = xmlParseExternalID(ctxt, &literal, 1);
+		if ((URI == NULL) && (literal == NULL)) {
+		    ctxt->errNo = XML_ERR_VALUE_REQUIRED;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			    "Entity value required\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		if (URI) {
+		    xmlURIPtr uri;
+
+		    uri = xmlParseURI((const char *)URI);
+		    if (uri == NULL) {
+			ctxt->errNo = XML_ERR_INVALID_URI;
+			if ((ctxt->sax != NULL) &&
+			    (!ctxt->disableSAX) &&
+			    (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				        "Invalid URI: %s\n", URI);
+			ctxt->wellFormed = 0;
+		    } else {
+			if (uri->fragment != NULL) {
+			    ctxt->errNo = XML_ERR_URI_FRAGMENT;
+			    if ((ctxt->sax != NULL) &&
+				(!ctxt->disableSAX) &&
+				(ctxt->sax->error != NULL))
+				ctxt->sax->error(ctxt->userData,
+					    "Fragment not allowed: %s\n", URI);
+			    ctxt->wellFormed = 0;
+			}
+			xmlFreeURI(uri);
+		    }
+		}
+		if ((RAW != '>') && (!IS_BLANK(CUR))) {
+		    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			    "Space required before 'NDATA'\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		SKIP_BLANKS;
+		if ((RAW == 'N') && (NXT(1) == 'D') &&
+		    (NXT(2) == 'A') && (NXT(3) == 'T') &&
+		    (NXT(4) == 'A')) {
+		    SKIP(5);
+		    if (!IS_BLANK(CUR)) {
+			ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+			        "Space required after 'NDATA'\n");
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    }
+		    SKIP_BLANKS;
+		    ndata = xmlParseName(ctxt);
+		    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+		        (ctxt->sax->unparsedEntityDecl != NULL))
+			ctxt->sax->unparsedEntityDecl(ctxt->userData, name,
+				    literal, URI, ndata);
+		} else {
+		    if ((ctxt->sax != NULL) &&
+		        (!ctxt->disableSAX) && (ctxt->sax->entityDecl != NULL))
+			ctxt->sax->entityDecl(ctxt->userData, name,
+				    XML_EXTERNAL_GENERAL_PARSED_ENTITY,
+				    literal, URI, NULL);
+		}
+	    }
+	}
+	SKIP_BLANKS;
+	if (RAW != '>') {
+	    ctxt->errNo = XML_ERR_ENTITY_NOT_FINISHED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	            "xmlParseEntityDecl: entity %s not terminated\n", name);
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    if (input != ctxt->input) {
+		ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+"Entity declaration doesn't start and stop in the same entity\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    NEXT;
+	}
+	if (orig != NULL) {
+	    /*
+	     * Ugly mechanism to save the raw entity value.
+	     */
+	    xmlEntityPtr cur = NULL;
+
+	    if (isParameter) {
+	        if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->getParameterEntity != NULL))
+		    cur = ctxt->sax->getParameterEntity(ctxt->userData, name);
+	    } else {
+	        if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->getEntity != NULL))
+		    cur = ctxt->sax->getEntity(ctxt->userData, name);
+	    }
+            if (cur != NULL) {
+	        if (cur->orig != NULL)
+		    xmlFree(orig);
+		else
+		    cur->orig = orig;
+	    } else
+		xmlFree(orig);
+	}
+	if (name != NULL) xmlFree(name);
+	if (value != NULL) xmlFree(value);
+	if (URI != NULL) xmlFree(URI);
+	if (literal != NULL) xmlFree(literal);
+	if (ndata != NULL) xmlFree(ndata);
+    }
+}
+
+/**
+ * xmlParseDefaultDecl:
+ * @ctxt:  an XML parser context
+ * @value:  Receive a possible fixed default value for the attribute
+ *
+ * Parse an attribute default declaration
+ *
+ * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED' | (('#FIXED' S)? AttValue)
+ *
+ * [ VC: Required Attribute ]
+ * if the default declaration is the keyword #REQUIRED, then the
+ * attribute must be specified for all elements of the type in the
+ * attribute-list declaration.
+ *
+ * [ VC: Attribute Default Legal ]
+ * The declared default value must meet the lexical constraints of
+ * the declared attribute type c.f. xmlValidateAttributeDecl()
+ *
+ * [ VC: Fixed Attribute Default ]
+ * if an attribute has a default value declared with the #FIXED
+ * keyword, instances of that attribute must match the default value. 
+ *
+ * [ WFC: No < in Attribute Values ]
+ * handled in xmlParseAttValue()
+ *
+ * returns: XML_ATTRIBUTE_NONE, XML_ATTRIBUTE_REQUIRED, XML_ATTRIBUTE_IMPLIED
+ *          or XML_ATTRIBUTE_FIXED. 
+ */
+
+int
+xmlParseDefaultDecl(xmlParserCtxtPtr ctxt, xmlChar **value) {
+    int val;
+    xmlChar *ret;
+
+    *value = NULL;
+    if ((RAW == '#') && (NXT(1) == 'R') &&
+        (NXT(2) == 'E') && (NXT(3) == 'Q') &&
+        (NXT(4) == 'U') && (NXT(5) == 'I') &&
+        (NXT(6) == 'R') && (NXT(7) == 'E') &&
+        (NXT(8) == 'D')) {
+	SKIP(9);
+	return(XML_ATTRIBUTE_REQUIRED);
+    }
+    if ((RAW == '#') && (NXT(1) == 'I') &&
+        (NXT(2) == 'M') && (NXT(3) == 'P') &&
+        (NXT(4) == 'L') && (NXT(5) == 'I') &&
+        (NXT(6) == 'E') && (NXT(7) == 'D')) {
+	SKIP(8);
+	return(XML_ATTRIBUTE_IMPLIED);
+    }
+    val = XML_ATTRIBUTE_NONE;
+    if ((RAW == '#') && (NXT(1) == 'F') &&
+        (NXT(2) == 'I') && (NXT(3) == 'X') &&
+        (NXT(4) == 'E') && (NXT(5) == 'D')) {
+	SKIP(6);
+	val = XML_ATTRIBUTE_FIXED;
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "Space required after '#FIXED'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	SKIP_BLANKS;
+    }
+    ret = xmlParseAttValue(ctxt);
+    ctxt->instate = XML_PARSER_DTD;
+    if (ret == NULL) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	       "Attribute default value declaration error\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else
+        *value = ret;
+    return(val);
+}
+
+/**
+ * xmlParseNotationType:
+ * @ctxt:  an XML parser context
+ *
+ * parse an Notation attribute type.
+ *
+ * Note: the leading 'NOTATION' S part has already being parsed...
+ *
+ * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
+ *
+ * [ VC: Notation Attributes ]
+ * Values of this type must match one of the notation names included
+ * in the declaration; all notation names in the declaration must be declared. 
+ *
+ * Returns: the notation attribute tree built while parsing
+ */
+
+xmlEnumerationPtr
+xmlParseNotationType(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlEnumerationPtr ret = NULL, last = NULL, cur;
+
+    if (RAW != '(') {
+	ctxt->errNo = XML_ERR_NOTATION_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "'(' required to start 'NOTATION'\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+    SHRINK;
+    do {
+        NEXT;
+	SKIP_BLANKS;
+        name = xmlParseName(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		                 "Name expected in NOTATION declaration\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(ret);
+	}
+	cur = xmlCreateEnumeration(name);
+	xmlFree(name);
+	if (cur == NULL) return(ret);
+	if (last == NULL) ret = last = cur;
+	else {
+	    last->next = cur;
+	    last = cur;
+	}
+	SKIP_BLANKS;
+    } while (RAW == '|');
+    if (RAW != ')') {
+	ctxt->errNo = XML_ERR_NOTATION_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "')' required to finish NOTATION declaration\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	if ((last != NULL) && (last != ret))
+	    xmlFreeEnumeration(last);
+	return(ret);
+    }
+    NEXT;
+    return(ret);
+}
+
+/**
+ * xmlParseEnumerationType:
+ * @ctxt:  an XML parser context
+ *
+ * parse an Enumeration attribute type.
+ *
+ * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
+ *
+ * [ VC: Enumeration ]
+ * Values of this type must match one of the Nmtoken tokens in
+ * the declaration
+ *
+ * Returns: the enumeration attribute tree built while parsing
+ */
+
+xmlEnumerationPtr
+xmlParseEnumerationType(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlEnumerationPtr ret = NULL, last = NULL, cur;
+
+    if (RAW != '(') {
+	ctxt->errNo = XML_ERR_ATTLIST_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "'(' required to start ATTLIST enumeration\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(NULL);
+    }
+    SHRINK;
+    do {
+        NEXT;
+	SKIP_BLANKS;
+        name = xmlParseNmtoken(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NMTOKEN_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		                 "NmToken expected in ATTLIST enumeration\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(ret);
+	}
+	cur = xmlCreateEnumeration(name);
+	xmlFree(name);
+	if (cur == NULL) return(ret);
+	if (last == NULL) ret = last = cur;
+	else {
+	    last->next = cur;
+	    last = cur;
+	}
+	SKIP_BLANKS;
+    } while (RAW == '|');
+    if (RAW != ')') {
+	ctxt->errNo = XML_ERR_ATTLIST_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "')' required to finish ATTLIST enumeration\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(ret);
+    }
+    NEXT;
+    return(ret);
+}
+
+/**
+ * xmlParseEnumeratedType:
+ * @ctxt:  an XML parser context
+ * @tree:  the enumeration tree built while parsing
+ *
+ * parse an Enumerated attribute type.
+ *
+ * [57] EnumeratedType ::= NotationType | Enumeration
+ *
+ * [58] NotationType ::= 'NOTATION' S '(' S? Name (S? '|' S? Name)* S? ')'
+ *
+ *
+ * Returns: XML_ATTRIBUTE_ENUMERATION or XML_ATTRIBUTE_NOTATION
+ */
+
+int
+xmlParseEnumeratedType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
+    if ((RAW == 'N') && (NXT(1) == 'O') &&
+        (NXT(2) == 'T') && (NXT(3) == 'A') &&
+        (NXT(4) == 'T') && (NXT(5) == 'I') &&
+	(NXT(6) == 'O') && (NXT(7) == 'N')) {
+	SKIP(8);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "Space required after 'NOTATION'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(0);
+	}
+        SKIP_BLANKS;
+	*tree = xmlParseNotationType(ctxt);
+	if (*tree == NULL) return(0);
+	return(XML_ATTRIBUTE_NOTATION);
+    }
+    *tree = xmlParseEnumerationType(ctxt);
+    if (*tree == NULL) return(0);
+    return(XML_ATTRIBUTE_ENUMERATION);
+}
+
+/**
+ * xmlParseAttributeType:
+ * @ctxt:  an XML parser context
+ * @tree:  the enumeration tree built while parsing
+ *
+ * parse the Attribute list def for an element
+ *
+ * [54] AttType ::= StringType | TokenizedType | EnumeratedType
+ *
+ * [55] StringType ::= 'CDATA'
+ *
+ * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY' |
+ *                        'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
+ *
+ * Validity constraints for attribute values syntax are checked in
+ * xmlValidateAttributeValue()
+ *
+ * [ VC: ID ]
+ * Values of type ID must match the Name production. A name must not
+ * appear more than once in an XML document as a value of this type;
+ * i.e., ID values must uniquely identify the elements which bear them.
+ *
+ * [ VC: One ID per Element Type ]
+ * No element type may have more than one ID attribute specified.
+ *
+ * [ VC: ID Attribute Default ]
+ * An ID attribute must have a declared default of #IMPLIED or #REQUIRED.
+ *
+ * [ VC: IDREF ]
+ * Values of type IDREF must match the Name production, and values
+ * of type IDREFS must match Names; each IDREF Name must match the value
+ * of an ID attribute on some element in the XML document; i.e. IDREF
+ * values must match the value of some ID attribute.
+ *
+ * [ VC: Entity Name ]
+ * Values of type ENTITY must match the Name production, values
+ * of type ENTITIES must match Names; each Entity Name must match the
+ * name of an unparsed entity declared in the DTD.  
+ *
+ * [ VC: Name Token ]
+ * Values of type NMTOKEN must match the Nmtoken production; values
+ * of type NMTOKENS must match Nmtokens. 
+ *
+ * Returns the attribute type
+ */
+int 
+xmlParseAttributeType(xmlParserCtxtPtr ctxt, xmlEnumerationPtr *tree) {
+    SHRINK;
+    if ((RAW == 'C') && (NXT(1) == 'D') &&
+        (NXT(2) == 'A') && (NXT(3) == 'T') &&
+        (NXT(4) == 'A')) {
+	SKIP(5);
+	return(XML_ATTRIBUTE_CDATA);
+     } else if ((RAW == 'I') && (NXT(1) == 'D') &&
+        (NXT(2) == 'R') && (NXT(3) == 'E') &&
+        (NXT(4) == 'F') && (NXT(5) == 'S')) {
+	SKIP(6);
+	return(XML_ATTRIBUTE_IDREFS);
+     } else if ((RAW == 'I') && (NXT(1) == 'D') &&
+        (NXT(2) == 'R') && (NXT(3) == 'E') &&
+        (NXT(4) == 'F')) {
+	SKIP(5);
+	return(XML_ATTRIBUTE_IDREF);
+     } else if ((RAW == 'I') && (NXT(1) == 'D')) {
+        SKIP(2);
+	return(XML_ATTRIBUTE_ID);
+     } else if ((RAW == 'E') && (NXT(1) == 'N') &&
+        (NXT(2) == 'T') && (NXT(3) == 'I') &&
+        (NXT(4) == 'T') && (NXT(5) == 'Y')) {
+	SKIP(6);
+	return(XML_ATTRIBUTE_ENTITY);
+     } else if ((RAW == 'E') && (NXT(1) == 'N') &&
+        (NXT(2) == 'T') && (NXT(3) == 'I') &&
+        (NXT(4) == 'T') && (NXT(5) == 'I') &&
+        (NXT(6) == 'E') && (NXT(7) == 'S')) {
+	SKIP(8);
+	return(XML_ATTRIBUTE_ENTITIES);
+     } else if ((RAW == 'N') && (NXT(1) == 'M') &&
+        (NXT(2) == 'T') && (NXT(3) == 'O') &&
+        (NXT(4) == 'K') && (NXT(5) == 'E') &&
+        (NXT(6) == 'N') && (NXT(7) == 'S')) {
+	SKIP(8);
+	return(XML_ATTRIBUTE_NMTOKENS);
+     } else if ((RAW == 'N') && (NXT(1) == 'M') &&
+        (NXT(2) == 'T') && (NXT(3) == 'O') &&
+        (NXT(4) == 'K') && (NXT(5) == 'E') &&
+        (NXT(6) == 'N')) {
+	SKIP(7);
+	return(XML_ATTRIBUTE_NMTOKEN);
+     }
+     return(xmlParseEnumeratedType(ctxt, tree));
+}
+
+/**
+ * xmlParseAttributeListDecl:
+ * @ctxt:  an XML parser context
+ *
+ * : parse the Attribute list def for an element
+ *
+ * [52] AttlistDecl ::= '<!ATTLIST' S Name AttDef* S? '>'
+ *
+ * [53] AttDef ::= S Name S AttType S DefaultDecl
+ *
+ */
+void
+xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *elemName;
+    xmlChar *attrName;
+    xmlEnumerationPtr tree;
+
+    if ((RAW == '<') && (NXT(1) == '!') &&
+        (NXT(2) == 'A') && (NXT(3) == 'T') &&
+        (NXT(4) == 'T') && (NXT(5) == 'L') &&
+        (NXT(6) == 'I') && (NXT(7) == 'S') &&
+        (NXT(8) == 'T')) {
+	xmlParserInputPtr input = ctxt->input;
+
+	SKIP(9);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "Space required after '<!ATTLIST'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        SKIP_BLANKS;
+        elemName = xmlParseName(ctxt);
+	if (elemName == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "ATTLIST: no name for Element\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	}
+	SKIP_BLANKS;
+	GROW;
+	while (RAW != '>') {
+	    const xmlChar *check = CUR_PTR;
+	    int type;
+	    int def;
+	    xmlChar *defaultValue = NULL;
+
+	    GROW;
+            tree = NULL;
+	    attrName = xmlParseName(ctxt);
+	    if (attrName == NULL) {
+		ctxt->errNo = XML_ERR_NAME_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "ATTLIST: no name for Attribute\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		break;
+	    }
+	    GROW;
+	    if (!IS_BLANK(CUR)) {
+		ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		        "Space required after the attribute name\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+                if (attrName != NULL)
+		    xmlFree(attrName);
+                if (defaultValue != NULL)
+		    xmlFree(defaultValue);
+		break;
+	    }
+	    SKIP_BLANKS;
+
+	    type = xmlParseAttributeType(ctxt, &tree);
+	    if (type <= 0) {
+                if (attrName != NULL)
+		    xmlFree(attrName);
+                if (defaultValue != NULL)
+		    xmlFree(defaultValue);
+	        break;
+	    }
+
+	    GROW;
+	    if (!IS_BLANK(CUR)) {
+		ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		        "Space required after the attribute type\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+                if (attrName != NULL)
+		    xmlFree(attrName);
+                if (defaultValue != NULL)
+		    xmlFree(defaultValue);
+	        if (tree != NULL)
+		    xmlFreeEnumeration(tree);
+		break;
+	    }
+	    SKIP_BLANKS;
+
+	    def = xmlParseDefaultDecl(ctxt, &defaultValue);
+	    if (def <= 0) {
+                if (attrName != NULL)
+		    xmlFree(attrName);
+                if (defaultValue != NULL)
+		    xmlFree(defaultValue);
+	        if (tree != NULL)
+		    xmlFreeEnumeration(tree);
+	        break;
+	    }
+
+	    GROW;
+            if (RAW != '>') {
+		if (!IS_BLANK(CUR)) {
+		    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+			"Space required after the attribute default value\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    if (attrName != NULL)
+			xmlFree(attrName);
+		    if (defaultValue != NULL)
+			xmlFree(defaultValue);
+		    if (tree != NULL)
+			xmlFreeEnumeration(tree);
+		    break;
+		}
+		SKIP_BLANKS;
+	    }
+	    if (check == CUR_PTR) {
+		ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+	        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		    "xmlParseAttributeListDecl: detected internal error\n");
+		if (attrName != NULL)
+		    xmlFree(attrName);
+		if (defaultValue != NULL)
+		    xmlFree(defaultValue);
+	        if (tree != NULL)
+		    xmlFreeEnumeration(tree);
+		break;
+	    }
+	    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+		(ctxt->sax->attributeDecl != NULL))
+		ctxt->sax->attributeDecl(ctxt->userData, elemName, attrName,
+	                        type, def, defaultValue, tree);
+	    if (attrName != NULL)
+		xmlFree(attrName);
+	    if (defaultValue != NULL)
+	        xmlFree(defaultValue);
+	    GROW;
+	}
+	if (RAW == '>') {
+	    if (input != ctxt->input) {
+		ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+"Attribute list declaration doesn't start and stop in the same entity\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    NEXT;
+	}
+
+	xmlFree(elemName);
+    }
+}
+
+/**
+ * xmlParseElementMixedContentDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse the declaration for a Mixed Element content
+ * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
+ * 
+ * [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' |
+ *                '(' S? '#PCDATA' S? ')'
+ *
+ * [ VC: Proper Group/PE Nesting ] applies to [51] too (see [49])
+ *
+ * [ VC: No Duplicate Types ]
+ * The same name must not appear more than once in a single
+ * mixed-content declaration. 
+ *
+ * returns: the list of the xmlElementContentPtr describing the element choices
+ */
+xmlElementContentPtr
+xmlParseElementMixedContentDecl(xmlParserCtxtPtr ctxt) {
+    xmlElementContentPtr ret = NULL, cur = NULL, n;
+    xmlChar *elem = NULL;
+
+    GROW;
+    if ((RAW == '#') && (NXT(1) == 'P') &&
+        (NXT(2) == 'C') && (NXT(3) == 'D') &&
+        (NXT(4) == 'A') && (NXT(5) == 'T') &&
+        (NXT(6) == 'A')) {
+	SKIP(7);
+	SKIP_BLANKS;
+	SHRINK;
+	if (RAW == ')') {
+	    ctxt->entity = ctxt->input;
+	    NEXT;
+	    ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
+	    if (RAW == '*') {
+		ret->ocur = XML_ELEMENT_CONTENT_MULT;
+		NEXT;
+	    }
+	    return(ret);
+	}
+	if ((RAW == '(') || (RAW == '|')) {
+	    ret = cur = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_PCDATA);
+	    if (ret == NULL) return(NULL);
+	}
+	while (RAW == '|') {
+	    NEXT;
+	    if (elem == NULL) {
+	        ret = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
+		if (ret == NULL) return(NULL);
+		ret->c1 = cur;
+		cur = ret;
+	    } else {
+	        n = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
+		if (n == NULL) return(NULL);
+		n->c1 = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
+	        cur->c2 = n;
+		cur = n;
+		xmlFree(elem);
+	    }
+	    SKIP_BLANKS;
+	    elem = xmlParseName(ctxt);
+	    if (elem == NULL) {
+		ctxt->errNo = XML_ERR_NAME_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+			"xmlParseElementMixedContentDecl : Name expected\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		xmlFreeElementContent(cur);
+		return(NULL);
+	    }
+	    SKIP_BLANKS;
+	    GROW;
+	}
+	if ((RAW == ')') && (NXT(1) == '*')) {
+	    if (elem != NULL) {
+		cur->c2 = xmlNewElementContent(elem,
+		                               XML_ELEMENT_CONTENT_ELEMENT);
+	        xmlFree(elem);
+            }
+	    ret->ocur = XML_ELEMENT_CONTENT_MULT;
+	    ctxt->entity = ctxt->input;
+	    SKIP(2);
+	} else {
+	    if (elem != NULL) xmlFree(elem);
+	    xmlFreeElementContent(ret);
+	    ctxt->errNo = XML_ERR_MIXED_NOT_STARTED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		    "xmlParseElementMixedContentDecl : '|' or ')*' expected\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(NULL);
+	}
+
+    } else {
+	ctxt->errNo = XML_ERR_PCDATA_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+		"xmlParseElementMixedContentDecl : '#PCDATA' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    return(ret);
+}
+
+/**
+ * xmlParseElementChildrenContentDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse the declaration for a Mixed Element content
+ * The leading '(' and spaces have been skipped in xmlParseElementContentDecl
+ * 
+ *
+ * [47] children ::= (choice | seq) ('?' | '*' | '+')?
+ *
+ * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
+ *
+ * [49] choice ::= '(' S? cp ( S? '|' S? cp )* S? ')'
+ *
+ * [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
+ *
+ * [ VC: Proper Group/PE Nesting ] applies to [49] and [50]
+ * TODO Parameter-entity replacement text must be properly nested
+ *	with parenthetized groups. That is to say, if either of the
+ *	opening or closing parentheses in a choice, seq, or Mixed
+ *	construct is contained in the replacement text for a parameter
+ *	entity, both must be contained in the same replacement text. For
+ *	interoperability, if a parameter-entity reference appears in a
+ *	choice, seq, or Mixed construct, its replacement text should not
+ *	be empty, and neither the first nor last non-blank character of
+ *	the replacement text should be a connector (| or ,).
+ *
+ * returns: the tree of xmlElementContentPtr describing the element 
+ *          hierarchy.
+ */
+xmlElementContentPtr
+#ifdef VMS
+xmlParseElementChildrenContentD
+#else
+xmlParseElementChildrenContentDecl
+#endif
+(xmlParserCtxtPtr ctxt) {
+    xmlElementContentPtr ret = NULL, cur = NULL, last = NULL, op = NULL;
+    xmlChar *elem;
+    xmlChar type = 0;
+
+    SKIP_BLANKS;
+    GROW;
+    if (RAW == '(') {
+        /* Recurse on first child */
+	NEXT;
+	SKIP_BLANKS;
+        cur = ret = xmlParseElementChildrenContentDecl(ctxt);
+	SKIP_BLANKS;
+	GROW;
+    } else {
+	elem = xmlParseName(ctxt);
+	if (elem == NULL) {
+	    ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		"xmlParseElementChildrenContentDecl : Name or '(' expected\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(NULL);
+	}
+        cur = ret = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
+	GROW;
+	if (RAW == '?') {
+	    cur->ocur = XML_ELEMENT_CONTENT_OPT;
+	    NEXT;
+	} else if (RAW == '*') {
+	    cur->ocur = XML_ELEMENT_CONTENT_MULT;
+	    NEXT;
+	} else if (RAW == '+') {
+	    cur->ocur = XML_ELEMENT_CONTENT_PLUS;
+	    NEXT;
+	} else {
+	    cur->ocur = XML_ELEMENT_CONTENT_ONCE;
+	}
+	xmlFree(elem);
+	GROW;
+    }
+    SKIP_BLANKS;
+    SHRINK;
+    while (RAW != ')') {
+        /*
+	 * Each loop we parse one separator and one element.
+	 */
+        if (RAW == ',') {
+	    if (type == 0) type = CUR;
+
+	    /*
+	     * Detect "Name | Name , Name" error
+	     */
+	    else if (type != CUR) {
+		ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		    "xmlParseElementChildrenContentDecl : '%c' expected\n",
+		    type);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		if ((op != NULL) && (op != ret))
+		    xmlFreeElementContent(op);
+		if ((last != NULL) && (last != ret) &&
+		    (last != ret->c1) && (last != ret->c2))
+		    xmlFreeElementContent(last);
+		if (ret != NULL)
+		    xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    NEXT;
+
+	    op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_SEQ);
+	    if (op == NULL) {
+	        xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    if (last == NULL) {
+		op->c1 = ret;
+		ret = cur = op;
+	    } else {
+	        cur->c2 = op;
+		op->c1 = last;
+		cur =op;
+		last = NULL;
+	    }
+	} else if (RAW == '|') {
+	    if (type == 0) type = CUR;
+
+	    /*
+	     * Detect "Name , Name | Name" error
+	     */
+	    else if (type != CUR) {
+		ctxt->errNo = XML_ERR_SEPARATOR_REQUIRED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		    "xmlParseElementChildrenContentDecl : '%c' expected\n",
+		    type);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		if ((op != NULL) && (op != ret) && (op != last))
+		    xmlFreeElementContent(op);
+		if ((last != NULL) && (last != ret) &&
+		    (last != ret->c1) && (last != ret->c2))
+		    xmlFreeElementContent(last);
+		if (ret != NULL)
+		    xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    NEXT;
+
+	    op = xmlNewElementContent(NULL, XML_ELEMENT_CONTENT_OR);
+	    if (op == NULL) {
+		if ((op != NULL) && (op != ret))
+		    xmlFreeElementContent(op);
+		if ((last != NULL) && (last != ret) &&
+		    (last != ret->c1) && (last != ret->c2))
+		    xmlFreeElementContent(last);
+		if (ret != NULL)
+		    xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    if (last == NULL) {
+		op->c1 = ret;
+		ret = cur = op;
+	    } else {
+	        cur->c2 = op;
+		op->c1 = last;
+		cur =op;
+		last = NULL;
+	    }
+	} else {
+	    ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_FINISHED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+	    "xmlParseElementChildrenContentDecl : ',' '|' or ')' expected\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    if ((op != NULL) && (op != ret))
+		xmlFreeElementContent(op);
+	    if ((last != NULL) && (last != ret) &&
+		(last != ret->c1) && (last != ret->c2))
+		xmlFreeElementContent(last);
+	    if (ret != NULL)
+		xmlFreeElementContent(ret);
+	    return(NULL);
+	}
+	GROW;
+	SKIP_BLANKS;
+	GROW;
+	if (RAW == '(') {
+	    /* Recurse on second child */
+	    NEXT;
+	    SKIP_BLANKS;
+	    last = xmlParseElementChildrenContentDecl(ctxt);
+	    SKIP_BLANKS;
+	} else {
+	    elem = xmlParseName(ctxt);
+	    if (elem == NULL) {
+		ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		"xmlParseElementChildrenContentDecl : Name or '(' expected\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		if ((op != NULL) && (op != ret))
+		    xmlFreeElementContent(op);
+		if ((last != NULL) && (last != ret) &&
+		    (last != ret->c1) && (last != ret->c2))
+		    xmlFreeElementContent(last);
+		if (ret != NULL)
+		    xmlFreeElementContent(ret);
+		return(NULL);
+	    }
+	    last = xmlNewElementContent(elem, XML_ELEMENT_CONTENT_ELEMENT);
+	    xmlFree(elem);
+	    if (RAW == '?') {
+		last->ocur = XML_ELEMENT_CONTENT_OPT;
+		NEXT;
+	    } else if (RAW == '*') {
+		last->ocur = XML_ELEMENT_CONTENT_MULT;
+		NEXT;
+	    } else if (RAW == '+') {
+		last->ocur = XML_ELEMENT_CONTENT_PLUS;
+		NEXT;
+	    } else {
+		last->ocur = XML_ELEMENT_CONTENT_ONCE;
+	    }
+	}
+	SKIP_BLANKS;
+	GROW;
+    }
+    if ((cur != NULL) && (last != NULL)) {
+        cur->c2 = last;
+    }
+    ctxt->entity = ctxt->input;
+    NEXT;
+    if (RAW == '?') {
+        ret->ocur = XML_ELEMENT_CONTENT_OPT;
+	NEXT;
+    } else if (RAW == '*') {
+        ret->ocur = XML_ELEMENT_CONTENT_MULT;
+	NEXT;
+    } else if (RAW == '+') {
+        ret->ocur = XML_ELEMENT_CONTENT_PLUS;
+	NEXT;
+    }
+    return(ret);
+}
+
+/**
+ * xmlParseElementContentDecl:
+ * @ctxt:  an XML parser context
+ * @name:  the name of the element being defined.
+ * @result:  the Element Content pointer will be stored here if any
+ *
+ * parse the declaration for an Element content either Mixed or Children,
+ * the cases EMPTY and ANY are handled directly in xmlParseElementDecl
+ * 
+ * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
+ *
+ * returns: the type of element content XML_ELEMENT_TYPE_xxx
+ */
+
+int
+xmlParseElementContentDecl(xmlParserCtxtPtr ctxt, xmlChar *name,
+                           xmlElementContentPtr *result) {
+
+    xmlElementContentPtr tree = NULL;
+    xmlParserInputPtr input = ctxt->input;
+    int res;
+
+    *result = NULL;
+
+    if (RAW != '(') {
+	ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+		"xmlParseElementContentDecl : '(' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return(-1);
+    }
+    NEXT;
+    GROW;
+    SKIP_BLANKS;
+    if ((RAW == '#') && (NXT(1) == 'P') &&
+        (NXT(2) == 'C') && (NXT(3) == 'D') &&
+        (NXT(4) == 'A') && (NXT(5) == 'T') &&
+        (NXT(6) == 'A')) {
+        tree = xmlParseElementMixedContentDecl(ctxt);
+	res = XML_ELEMENT_TYPE_MIXED;
+    } else {
+        tree = xmlParseElementChildrenContentDecl(ctxt);
+	res = XML_ELEMENT_TYPE_ELEMENT;
+    }
+    if ((ctxt->entity != NULL) && (input != ctxt->entity)) {
+	ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+"Element content declaration doesn't start and stop in the same entity\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    SKIP_BLANKS;
+    *result = tree;
+    return(res);
+}
+
+/**
+ * xmlParseElementDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse an Element declaration.
+ *
+ * [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
+ *
+ * [ VC: Unique Element Type Declaration ]
+ * No element type may be declared more than once
+ *
+ * Returns the type of the element, or -1 in case of error
+ */
+int
+xmlParseElementDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    int ret = -1;
+    xmlElementContentPtr content  = NULL;
+
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '!') &&
+        (NXT(2) == 'E') && (NXT(3) == 'L') &&
+        (NXT(4) == 'E') && (NXT(5) == 'M') &&
+        (NXT(6) == 'E') && (NXT(7) == 'N') &&
+        (NXT(8) == 'T')) {
+	xmlParserInputPtr input = ctxt->input;
+
+	SKIP(9);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		    "Space required after 'ELEMENT'\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        SKIP_BLANKS;
+        name = xmlParseName(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		   "xmlParseElementDecl: no name for Element\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(-1);
+	}
+	while ((RAW == 0) && (ctxt->inputNr > 1))
+	    xmlPopInput(ctxt);
+	if (!IS_BLANK(CUR)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		    "Space required after the element name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+        SKIP_BLANKS;
+	if ((RAW == 'E') && (NXT(1) == 'M') &&
+	    (NXT(2) == 'P') && (NXT(3) == 'T') &&
+	    (NXT(4) == 'Y')) {
+	    SKIP(5);
+	    /*
+	     * Element must always be empty.
+	     */
+	    ret = XML_ELEMENT_TYPE_EMPTY;
+	} else if ((RAW == 'A') && (NXT(1) == 'N') &&
+	           (NXT(2) == 'Y')) {
+	    SKIP(3);
+	    /*
+	     * Element is a generic container.
+	     */
+	    ret = XML_ELEMENT_TYPE_ANY;
+	} else if (RAW == '(') {
+	    ret = xmlParseElementContentDecl(ctxt, name, &content);
+	} else {
+	    /*
+	     * [ WFC: PEs in Internal Subset ] error handling.
+	     */
+	    if ((RAW == '%') && (ctxt->external == 0) &&
+	        (ctxt->inputNr == 1)) {
+		ctxt->errNo = XML_ERR_PEREF_IN_INT_SUBSET;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+	  "PEReference: forbidden within markup decl in internal subset\n");
+	    } else {
+		ctxt->errNo = XML_ERR_ELEMCONTENT_NOT_STARTED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		      "xmlParseElementDecl: 'EMPTY', 'ANY' or '(' expected\n");
+            }
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    if (name != NULL) xmlFree(name);
+	    return(-1);
+	}
+
+	SKIP_BLANKS;
+	/*
+	 * Pop-up of finished entities.
+	 */
+	while ((RAW == 0) && (ctxt->inputNr > 1))
+	    xmlPopInput(ctxt);
+	SKIP_BLANKS;
+
+	if (RAW != '>') {
+	    ctxt->errNo = XML_ERR_GT_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	          "xmlParseElementDecl: expected '>' at the end\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    if (input != ctxt->input) {
+		ctxt->errNo = XML_ERR_ENTITY_BOUNDARY;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+"Element declaration doesn't start and stop in the same entity\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+		
+	    NEXT;
+	    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+		(ctxt->sax->elementDecl != NULL))
+	        ctxt->sax->elementDecl(ctxt->userData, name, ret,
+		                       content);
+	}
+	if (content != NULL) {
+	    xmlFreeElementContent(content);
+	}
+	if (name != NULL) {
+	    xmlFree(name);
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlParseMarkupDecl:
+ * @ctxt:  an XML parser context
+ * 
+ * parse Markup declarations
+ *
+ * [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl |
+ *                     NotationDecl | PI | Comment
+ *
+ * [ VC: Proper Declaration/PE Nesting ]
+ * Parameter-entity replacement text must be properly nested with
+ * markup declarations. That is to say, if either the first character
+ * or the last character of a markup declaration (markupdecl above) is
+ * contained in the replacement text for a parameter-entity reference,
+ * both must be contained in the same replacement text.
+ *
+ * [ WFC: PEs in Internal Subset ]
+ * In the internal DTD subset, parameter-entity references can occur
+ * only where markup declarations can occur, not within markup declarations.
+ * (This does not apply to references that occur in external parameter
+ * entities or to the external subset.) 
+ */
+void
+xmlParseMarkupDecl(xmlParserCtxtPtr ctxt) {
+    GROW;
+    xmlParseElementDecl(ctxt);
+    xmlParseAttributeListDecl(ctxt);
+    xmlParseEntityDecl(ctxt);
+    xmlParseNotationDecl(ctxt);
+    xmlParsePI(ctxt);
+    xmlParseComment(ctxt);
+    /*
+     * This is only for internal subset. On external entities,
+     * the replacement is done before parsing stage
+     */
+    if ((ctxt->external == 0) && (ctxt->inputNr == 1))
+	xmlParsePEReference(ctxt);
+    ctxt->instate = XML_PARSER_DTD;
+}
+
+/**
+ * xmlParseTextDecl:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML declaration header for external entities
+ *
+ * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
+ *
+ * Question: Seems that EncodingDecl is mandatory ? Is that a typo ?
+ */
+
+void
+xmlParseTextDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *version;
+
+    /*
+     * We know that '<?xml' is here.
+     */
+    if ((RAW == '<') && (NXT(1) == '?') &&
+	(NXT(2) == 'x') && (NXT(3) == 'm') &&
+	(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+	SKIP(5);
+    } else {
+	ctxt->errNo = XML_ERR_XMLDECL_NOT_STARTED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "Text declaration '<?xml' required\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+
+	return;
+    }
+
+    if (!IS_BLANK(CUR)) {
+	ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "Space needed after '<?xml'\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    SKIP_BLANKS;
+
+    /*
+     * We may have the VersionInfo here.
+     */
+    version = xmlParseVersionInfo(ctxt);
+    if (version == NULL)
+	version = xmlCharStrdup(XML_DEFAULT_VERSION);
+    ctxt->input->version = version;
+
+    /*
+     * We must have the encoding declaration
+     */
+    if (!IS_BLANK(CUR)) {
+	ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Space needed here\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    xmlParseEncodingDecl(ctxt);
+    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	/*
+	 * The XML REC instructs us to stop parsing right here
+	 */
+        return;
+    }
+
+    SKIP_BLANKS;
+    if ((RAW == '?') && (NXT(1) == '>')) {
+        SKIP(2);
+    } else if (RAW == '>') {
+        /* Deprecated old WD ... */
+	ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "XML declaration must end-up with '?>'\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	NEXT;
+    } else {
+	ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "parsing XML declaration: '?>' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	MOVETO_ENDTAG(CUR_PTR);
+	NEXT;
+    }
+}
+
+/*
+ * xmlParseConditionalSections
+ * @ctxt:  an XML parser context
+ *
+ * [61] conditionalSect ::= includeSect | ignoreSect 
+ * [62] includeSect ::= '<![' S? 'INCLUDE' S? '[' extSubsetDecl ']]>' 
+ * [63] ignoreSect ::= '<![' S? 'IGNORE' S? '[' ignoreSectContents* ']]>'
+ * [64] ignoreSectContents ::= Ignore ('<![' ignoreSectContents ']]>' Ignore)*
+ * [65] Ignore ::= Char* - (Char* ('<![' | ']]>') Char*)
+ */
+
+void
+xmlParseConditionalSections(xmlParserCtxtPtr ctxt) {
+    SKIP(3);
+    SKIP_BLANKS;
+    if ((RAW == 'I') && (NXT(1) == 'N') && (NXT(2) == 'C') &&
+        (NXT(3) == 'L') && (NXT(4) == 'U') && (NXT(5) == 'D') &&
+        (NXT(6) == 'E')) {
+	SKIP(7);
+	SKIP_BLANKS;
+	if (RAW != '[') {
+	    ctxt->errNo = XML_ERR_CONDSEC_INVALID;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+	    "XML conditional section '[' expected\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    NEXT;
+	}
+	if (xmlParserDebugEntities) {
+	    if ((ctxt->input != NULL) && (ctxt->input->filename))
+		xmlGenericError(xmlGenericErrorContext,
+			"%s(%d): ", ctxt->input->filename,
+			ctxt->input->line);
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Entering INCLUDE Conditional Section\n");
+	}
+
+	while ((RAW != 0) && ((RAW != ']') || (NXT(1) != ']') ||
+	       (NXT(2) != '>'))) {
+	    const xmlChar *check = CUR_PTR;
+	    int cons = ctxt->input->consumed;
+	    int tok = ctxt->token;
+
+	    if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
+		xmlParseConditionalSections(ctxt);
+	    } else if (IS_BLANK(CUR)) {
+		NEXT;
+	    } else if (RAW == '%') {
+		xmlParsePEReference(ctxt);
+	    } else
+		xmlParseMarkupDecl(ctxt);
+
+	    /*
+	     * Pop-up of finished entities.
+	     */
+	    while ((RAW == 0) && (ctxt->inputNr > 1))
+		xmlPopInput(ctxt);
+
+	    if ((CUR_PTR == check) && (cons == ctxt->input->consumed) &&
+		(tok == ctxt->token)) {
+		ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+			"Content error in the external subset\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		break;
+	    }
+	}
+	if (xmlParserDebugEntities) {
+	    if ((ctxt->input != NULL) && (ctxt->input->filename))
+		xmlGenericError(xmlGenericErrorContext,
+			"%s(%d): ", ctxt->input->filename,
+			ctxt->input->line);
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Leaving INCLUDE Conditional Section\n");
+	}
+
+    } else if ((RAW == 'I') && (NXT(1) == 'G') && (NXT(2) == 'N') &&
+            (NXT(3) == 'O') && (NXT(4) == 'R') && (NXT(5) == 'E')) {
+	int state;
+	int instate;
+	int depth = 0;
+
+	SKIP(6);
+	SKIP_BLANKS;
+	if (RAW != '[') {
+	    ctxt->errNo = XML_ERR_CONDSEC_INVALID;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+	    "XML conditional section '[' expected\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    NEXT;
+	}
+	if (xmlParserDebugEntities) {
+	    if ((ctxt->input != NULL) && (ctxt->input->filename))
+		xmlGenericError(xmlGenericErrorContext,
+			"%s(%d): ", ctxt->input->filename,
+			ctxt->input->line);
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Entering IGNORE Conditional Section\n");
+	}
+
+	/*
+	 * Parse up to the end of the conditionnal section
+	 * But disable SAX event generating DTD building in the meantime
+	 */
+	state = ctxt->disableSAX;
+	instate = ctxt->instate;
+	ctxt->disableSAX = 1;
+	ctxt->instate = XML_PARSER_IGNORE;
+
+	while (depth >= 0) {
+	  if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
+	    depth++;
+	    SKIP(3);
+	    continue;
+	  }
+	  if ((RAW == ']') && (NXT(1) == ']') && (NXT(2) == '>')) {
+	    if (--depth >= 0) SKIP(3);
+	    continue;
+	  }
+	  NEXT;
+	  continue;
+	}
+
+	ctxt->disableSAX = state;
+	ctxt->instate = instate;
+
+	if (xmlParserDebugEntities) {
+	    if ((ctxt->input != NULL) && (ctxt->input->filename))
+		xmlGenericError(xmlGenericErrorContext,
+			"%s(%d): ", ctxt->input->filename,
+			ctxt->input->line);
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Leaving IGNORE Conditional Section\n");
+	}
+
+    } else {
+	ctxt->errNo = XML_ERR_CONDSEC_INVALID;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	"XML conditional section INCLUDE or IGNORE keyword expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    if (RAW == 0)
+        SHRINK;
+
+    if (RAW == 0) {
+	ctxt->errNo = XML_ERR_CONDSEC_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	        "XML conditional section not closed\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else {
+        SKIP(3);
+    }
+}
+
+/**
+ * xmlParseExternalSubset:
+ * @ctxt:  an XML parser context
+ * @ExternalID: the external identifier
+ * @SystemID: the system identifier (or URL)
+ * 
+ * parse Markup declarations from an external subset
+ *
+ * [30] extSubset ::= textDecl? extSubsetDecl
+ *
+ * [31] extSubsetDecl ::= (markupdecl | conditionalSect | PEReference | S) *
+ */
+void
+xmlParseExternalSubset(xmlParserCtxtPtr ctxt, const xmlChar *ExternalID,
+                       const xmlChar *SystemID) {
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '?') &&
+        (NXT(2) == 'x') && (NXT(3) == 'm') &&
+	(NXT(4) == 'l')) {
+	xmlParseTextDecl(ctxt);
+	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	    /*
+	     * The XML REC instructs us to stop parsing right here
+	     */
+	    ctxt->instate = XML_PARSER_EOF;
+	    return;
+	}
+    }
+    if (ctxt->myDoc == NULL) {
+        ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
+    }
+    if ((ctxt->myDoc != NULL) && (ctxt->myDoc->intSubset == NULL))
+        xmlCreateIntSubset(ctxt->myDoc, NULL, ExternalID, SystemID);
+
+    ctxt->instate = XML_PARSER_DTD;
+    ctxt->external = 1;
+    while (((RAW == '<') && (NXT(1) == '?')) ||
+           ((RAW == '<') && (NXT(1) == '!')) ||
+           IS_BLANK(CUR)) {
+	const xmlChar *check = CUR_PTR;
+	int cons = ctxt->input->consumed;
+	int tok = ctxt->token;
+
+	GROW;
+        if ((RAW == '<') && (NXT(1) == '!') && (NXT(2) == '[')) {
+	    xmlParseConditionalSections(ctxt);
+	} else if (IS_BLANK(CUR)) {
+	    NEXT;
+	} else if (RAW == '%') {
+            xmlParsePEReference(ctxt);
+	} else
+	    xmlParseMarkupDecl(ctxt);
+
+	/*
+	 * Pop-up of finished entities.
+	 */
+	while ((RAW == 0) && (ctxt->inputNr > 1))
+	    xmlPopInput(ctxt);
+
+	if ((CUR_PTR == check) && (cons == ctxt->input->consumed) &&
+	    (tok == ctxt->token)) {
+	    ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Content error in the external subset\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    break;
+	}
+    }
+    
+    if (RAW != 0) {
+	ctxt->errNo = XML_ERR_EXT_SUBSET_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	        "Extra content at the end of the document\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+}
+
+/**
+ * xmlParseReference:
+ * @ctxt:  an XML parser context
+ * 
+ * parse and handle entity references in content, depending on the SAX
+ * interface, this may end-up in a call to character() if this is a
+ * CharRef, a predefined entity, if there is no reference() callback.
+ * or if the parser was asked to switch to that mode.
+ *
+ * [67] Reference ::= EntityRef | CharRef
+ */
+void
+xmlParseReference(xmlParserCtxtPtr ctxt) {
+    xmlEntityPtr ent;
+    xmlChar *val;
+    if (RAW != '&') return;
+
+    if (NXT(1) == '#') {
+	int i = 0;
+	xmlChar out[10];
+	int hex = NXT(2);
+	int val = xmlParseCharRef(ctxt);
+	
+	if (ctxt->charset != XML_CHAR_ENCODING_UTF8) {
+	    /*
+	     * So we are using non-UTF-8 buffers
+	     * Check that the char fit on 8bits, if not
+	     * generate a CharRef.
+	     */
+	    if (val <= 0xFF) {
+		out[0] = val;
+		out[1] = 0;
+		if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) &&
+		    (!ctxt->disableSAX))
+		    ctxt->sax->characters(ctxt->userData, out, 1);
+	    } else {
+		if ((hex == 'x') || (hex == 'X'))
+		    sprintf((char *)out, "#x%X", val);
+		else
+		    sprintf((char *)out, "#%d", val);
+		if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
+		    (!ctxt->disableSAX))
+		    ctxt->sax->reference(ctxt->userData, out);
+	    }
+	} else {
+	    /*
+	     * Just encode the value in UTF-8
+	     */
+	    COPY_BUF(0 ,out, i, val);
+	    out[i] = 0;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) &&
+		(!ctxt->disableSAX))
+		ctxt->sax->characters(ctxt->userData, out, i);
+	}
+    } else {
+	ent = xmlParseEntityRef(ctxt);
+	if (ent == NULL) return;
+	if ((ent->name != NULL) && 
+	    (ent->etype != XML_INTERNAL_PREDEFINED_ENTITY)) {
+	    xmlNodePtr list = NULL;
+	    int ret;
+
+
+	    /*
+	     * The first reference to the entity trigger a parsing phase
+	     * where the ent->children is filled with the result from
+	     * the parsing.
+	     */
+	    if (ent->children == NULL) {
+		xmlChar *value;
+		value = ent->content;
+
+		/*
+		 * Check that this entity is well formed
+		 */
+		if ((value != NULL) &&
+		    (value[1] == 0) && (value[0] == '<') &&
+		    (xmlStrEqual(ent->name, BAD_CAST "lt"))) {
+		    /*
+		     * DONE: get definite answer on this !!!
+		     * Lots of entity decls are used to declare a single
+		     * char 
+		     *    <!ENTITY lt     "<">
+		     * Which seems to be valid since
+		     * 2.4: The ampersand character (&) and the left angle
+		     * bracket (<) may appear in their literal form only
+		     * when used ... They are also legal within the literal
+		     * entity value of an internal entity declaration;i
+		     * see "4.3.2 Well-Formed Parsed Entities". 
+		     * IMHO 2.4 and 4.3.2 are directly in contradiction.
+		     * Looking at the OASIS test suite and James Clark 
+		     * tests, this is broken. However the XML REC uses
+		     * it. Is the XML REC not well-formed ????
+		     * This is a hack to avoid this problem
+		     *
+		     * ANSWER: since lt gt amp .. are already defined,
+		     *   this is a redefinition and hence the fact that the
+		     *   contentis not well balanced is not a Wf error, this
+		     *   is lousy but acceptable.
+		     */
+		    list = xmlNewDocText(ctxt->myDoc, value);
+		    if (list != NULL) {
+			if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) &&
+			    (ent->children == NULL)) {
+			    ent->children = list;
+			    ent->last = list;
+			    list->parent = (xmlNodePtr) ent;
+			} else {
+			    xmlFreeNodeList(list);
+			}
+		    } else if (list != NULL) {
+			xmlFreeNodeList(list);
+		    }
+		} else {
+		    /*
+		     * 4.3.2: An internal general parsed entity is well-formed
+		     * if its replacement text matches the production labeled
+		     * content.
+		     */
+		    if (ent->etype == XML_INTERNAL_GENERAL_ENTITY) {
+			ctxt->depth++;
+			ret = xmlParseBalancedChunkMemory(ctxt->myDoc,
+				           ctxt->sax, NULL, ctxt->depth,
+					   value, &list);
+			ctxt->depth--;
+		    } else if (ent->etype ==
+			       XML_EXTERNAL_GENERAL_PARSED_ENTITY) {
+			ctxt->depth++;
+			ret = xmlParseExternalEntity(ctxt->myDoc,
+				   ctxt->sax, NULL, ctxt->depth,
+				   ent->URI, ent->ExternalID, &list);
+			ctxt->depth--;
+		    } else {
+			ret = -1;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				"Internal: invalid entity type\n");
+		    }
+		    if (ret == XML_ERR_ENTITY_LOOP) {
+			ctxt->errNo = XML_ERR_ENTITY_LOOP;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				"Detected entity reference loop\n");
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    } else if ((ret == 0) && (list != NULL)) {
+			if ((ent->etype == XML_INTERNAL_GENERAL_ENTITY) &&
+			    (ent->children == NULL)) {
+			    ent->children = list;
+			    while (list != NULL) {
+				list->parent = (xmlNodePtr) ent;
+				if (list->next == NULL)
+				    ent->last = list;
+				list = list->next;
+			    }
+			} else {
+			    xmlFreeNodeList(list);
+			}
+		    } else if (ret > 0) {
+			ctxt->errNo = ret;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+				"Entity value required\n");
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    } else if (list != NULL) {
+			xmlFreeNodeList(list);
+		    }
+		}
+	    }
+	    if ((ctxt->sax != NULL) && (ctxt->sax->reference != NULL) &&
+		(ctxt->replaceEntities == 0) && (!ctxt->disableSAX)) {
+		/*
+		 * Create a node.
+		 */
+		ctxt->sax->reference(ctxt->userData, ent->name);
+		return;
+	    } else if (ctxt->replaceEntities) {
+		if ((ctxt->node != NULL) && (ent->children != NULL)) {
+		    /*
+		     * Seems we are generating the DOM content, do
+		     * a simple tree copy
+		     */
+		    xmlNodePtr new;
+		    new = xmlCopyNodeList(ent->children);
+		    
+		    xmlAddChildList(ctxt->node, new);
+		    /*
+		     * This is to avoid a nasty side effect, see
+		     * characters() in SAX.c
+		     */
+		    ctxt->nodemem = 0;
+		    ctxt->nodelen = 0;
+		    return;
+		} else {
+		    /*
+		     * Probably running in SAX mode
+		     */
+		    xmlParserInputPtr input;
+
+		    input = xmlNewEntityInputStream(ctxt, ent);
+		    xmlPushInput(ctxt, input);
+		    if ((ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY) &&
+			(RAW == '<') && (NXT(1) == '?') &&
+			(NXT(2) == 'x') && (NXT(3) == 'm') &&
+			(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+			xmlParseTextDecl(ctxt);
+			if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+			    /*
+			     * The XML REC instructs us to stop parsing right here
+			     */
+			    ctxt->instate = XML_PARSER_EOF;
+			    return;
+			}
+			if (input->standalone == 1) {
+			    ctxt->errNo = XML_ERR_EXT_ENTITY_STANDALONE;
+			    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+				ctxt->sax->error(ctxt->userData,
+				"external parsed entities cannot be standalone\n");
+			    ctxt->wellFormed = 0;
+			    ctxt->disableSAX = 1;
+			}
+		    }
+		    return;
+		}
+	    }
+	} else {
+	    val = ent->content;
+	    if (val == NULL) return;
+	    /*
+	     * inline the entity.
+	     */
+	    if ((ctxt->sax != NULL) && (ctxt->sax->characters != NULL) &&
+		(!ctxt->disableSAX))
+		ctxt->sax->characters(ctxt->userData, val, xmlStrlen(val));
+	}
+    }
+}
+
+/**
+ * xmlParseEntityRef:
+ * @ctxt:  an XML parser context
+ *
+ * parse ENTITY references declarations
+ *
+ * [68] EntityRef ::= '&' Name ';'
+ *
+ * [ WFC: Entity Declared ]
+ * In a document without any DTD, a document with only an internal DTD
+ * subset which contains no parameter entity references, or a document
+ * with "standalone='yes'", the Name given in the entity reference
+ * must match that in an entity declaration, except that well-formed
+ * documents need not declare any of the following entities: amp, lt,
+ * gt, apos, quot.  The declaration of a parameter entity must precede
+ * any reference to it.  Similarly, the declaration of a general entity
+ * must precede any reference to it which appears in a default value in an
+ * attribute-list declaration. Note that if entities are declared in the
+ * external subset or in external parameter entities, a non-validating
+ * processor is not obligated to read and process their declarations;
+ * for such documents, the rule that an entity must be declared is a
+ * well-formedness constraint only if standalone='yes'.
+ *
+ * [ WFC: Parsed Entity ]
+ * An entity reference must not contain the name of an unparsed entity
+ *
+ * Returns the xmlEntityPtr if found, or NULL otherwise.
+ */
+xmlEntityPtr
+xmlParseEntityRef(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlEntityPtr ent = NULL;
+
+    GROW;
+    
+    if (RAW == '&') {
+        NEXT;
+        name = xmlParseName(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlParseEntityRef: no name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    if (RAW == ';') {
+	        NEXT;
+		/*
+		 * Ask first SAX for entity resolution, otherwise try the
+		 * predefined set.
+		 */
+		if (ctxt->sax != NULL) {
+		    if (ctxt->sax->getEntity != NULL)
+			ent = ctxt->sax->getEntity(ctxt->userData, name);
+		    if (ent == NULL)
+		        ent = xmlGetPredefinedEntity(name);
+		}
+		/*
+		 * [ WFC: Entity Declared ]
+		 * In a document without any DTD, a document with only an
+		 * internal DTD subset which contains no parameter entity
+		 * references, or a document with "standalone='yes'", the
+		 * Name given in the entity reference must match that in an
+		 * entity declaration, except that well-formed documents
+		 * need not declare any of the following entities: amp, lt,
+		 * gt, apos, quot.
+		 * The declaration of a parameter entity must precede any
+		 * reference to it.
+		 * Similarly, the declaration of a general entity must
+		 * precede any reference to it which appears in a default
+		 * value in an attribute-list declaration. Note that if
+		 * entities are declared in the external subset or in
+		 * external parameter entities, a non-validating processor
+		 * is not obligated to read and process their declarations;
+		 * for such documents, the rule that an entity must be
+		 * declared is a well-formedness constraint only if
+		 * standalone='yes'. 
+		 */
+		if (ent == NULL) {
+		    if ((ctxt->standalone == 1) ||
+		        ((ctxt->hasExternalSubset == 0) &&
+			 (ctxt->hasPErefs == 0))) {
+			ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData, 
+				 "Entity '%s' not defined\n", name);
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    } else {
+			ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
+			if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			    ctxt->sax->warning(ctxt->userData, 
+				 "Entity '%s' not defined\n", name);
+		    }
+		}
+
+		/*
+		 * [ WFC: Parsed Entity ]
+		 * An entity reference must not contain the name of an
+		 * unparsed entity
+		 */
+		else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
+		    ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+			     "Entity reference to unparsed entity %s\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+
+		/*
+		 * [ WFC: No External Entity References ]
+		 * Attribute values cannot contain direct or indirect
+		 * entity references to external entities.
+		 */
+		else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
+		         (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
+		    ctxt->errNo = XML_ERR_ENTITY_IS_EXTERNAL;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+		     "Attribute references external entity '%s'\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		/*
+		 * [ WFC: No < in Attribute Values ]
+		 * The replacement text of any entity referred to directly or
+		 * indirectly in an attribute value (other than "&lt;") must
+		 * not contain a <. 
+		 */
+		else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
+		         (ent != NULL) &&
+			 (!xmlStrEqual(ent->name, BAD_CAST "lt")) &&
+		         (ent->content != NULL) &&
+			 (xmlStrchr(ent->content, '<'))) {
+		    ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+	 "'<' in entity '%s' is not allowed in attributes values\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+
+		/*
+		 * Internal check, no parameter entities here ...
+		 */
+		else {
+		    switch (ent->etype) {
+			case XML_INTERNAL_PARAMETER_ENTITY:
+			case XML_EXTERNAL_PARAMETER_ENTITY:
+			ctxt->errNo = XML_ERR_ENTITY_IS_PARAMETER;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData, 
+		     "Attempt to reference the parameter entity '%s'\n", name);
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+			break;
+			default:
+			break;
+		    }
+		}
+
+		/*
+		 * [ WFC: No Recursion ]
+		 * A parsed entity must not contain a recursive reference
+		 * to itself, either directly or indirectly. 
+		 * Done somewhere else
+		 */
+
+	    } else {
+		ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "xmlParseEntityRef: expecting ';'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    xmlFree(name);
+	}
+    }
+    return(ent);
+}
+
+/**
+ * xmlParseStringEntityRef:
+ * @ctxt:  an XML parser context
+ * @str:  a pointer to an index in the string
+ *
+ * parse ENTITY references declarations, but this version parses it from
+ * a string value.
+ *
+ * [68] EntityRef ::= '&' Name ';'
+ *
+ * [ WFC: Entity Declared ]
+ * In a document without any DTD, a document with only an internal DTD
+ * subset which contains no parameter entity references, or a document
+ * with "standalone='yes'", the Name given in the entity reference
+ * must match that in an entity declaration, except that well-formed
+ * documents need not declare any of the following entities: amp, lt,
+ * gt, apos, quot.  The declaration of a parameter entity must precede
+ * any reference to it.  Similarly, the declaration of a general entity
+ * must precede any reference to it which appears in a default value in an
+ * attribute-list declaration. Note that if entities are declared in the
+ * external subset or in external parameter entities, a non-validating
+ * processor is not obligated to read and process their declarations;
+ * for such documents, the rule that an entity must be declared is a
+ * well-formedness constraint only if standalone='yes'.
+ *
+ * [ WFC: Parsed Entity ]
+ * An entity reference must not contain the name of an unparsed entity
+ *
+ * Returns the xmlEntityPtr if found, or NULL otherwise. The str pointer
+ * is updated to the current location in the string.
+ */
+xmlEntityPtr
+xmlParseStringEntityRef(xmlParserCtxtPtr ctxt, const xmlChar ** str) {
+    xmlChar *name;
+    const xmlChar *ptr;
+    xmlChar cur;
+    xmlEntityPtr ent = NULL;
+
+    if ((str == NULL) || (*str == NULL))
+        return(NULL);
+    ptr = *str;
+    cur = *ptr;
+    if (cur == '&') {
+        ptr++;
+	cur = *ptr;
+        name = xmlParseStringName(ctxt, &ptr);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlParseEntityRef: no name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    if (*ptr == ';') {
+	        ptr++;
+		/*
+		 * Ask first SAX for entity resolution, otherwise try the
+		 * predefined set.
+		 */
+		if (ctxt->sax != NULL) {
+		    if (ctxt->sax->getEntity != NULL)
+			ent = ctxt->sax->getEntity(ctxt->userData, name);
+		    if (ent == NULL)
+		        ent = xmlGetPredefinedEntity(name);
+		}
+		/*
+		 * [ WFC: Entity Declared ]
+		 * In a document without any DTD, a document with only an
+		 * internal DTD subset which contains no parameter entity
+		 * references, or a document with "standalone='yes'", the
+		 * Name given in the entity reference must match that in an
+		 * entity declaration, except that well-formed documents
+		 * need not declare any of the following entities: amp, lt,
+		 * gt, apos, quot.
+		 * The declaration of a parameter entity must precede any
+		 * reference to it.
+		 * Similarly, the declaration of a general entity must
+		 * precede any reference to it which appears in a default
+		 * value in an attribute-list declaration. Note that if
+		 * entities are declared in the external subset or in
+		 * external parameter entities, a non-validating processor
+		 * is not obligated to read and process their declarations;
+		 * for such documents, the rule that an entity must be
+		 * declared is a well-formedness constraint only if
+		 * standalone='yes'. 
+		 */
+		if (ent == NULL) {
+		    if ((ctxt->standalone == 1) ||
+		        ((ctxt->hasExternalSubset == 0) &&
+			 (ctxt->hasPErefs == 0))) {
+			ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData, 
+				 "Entity '%s' not defined\n", name);
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    } else {
+			ctxt->errNo = XML_WAR_UNDECLARED_ENTITY;
+			if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			    ctxt->sax->warning(ctxt->userData, 
+				 "Entity '%s' not defined\n", name);
+		    }
+		}
+
+		/*
+		 * [ WFC: Parsed Entity ]
+		 * An entity reference must not contain the name of an
+		 * unparsed entity
+		 */
+		else if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
+		    ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+			     "Entity reference to unparsed entity %s\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+
+		/*
+		 * [ WFC: No External Entity References ]
+		 * Attribute values cannot contain direct or indirect
+		 * entity references to external entities.
+		 */
+		else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
+		         (ent->etype == XML_EXTERNAL_GENERAL_PARSED_ENTITY)) {
+		    ctxt->errNo = XML_ERR_ENTITY_IS_EXTERNAL;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+		     "Attribute references external entity '%s'\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+		/*
+		 * [ WFC: No < in Attribute Values ]
+		 * The replacement text of any entity referred to directly or
+		 * indirectly in an attribute value (other than "&lt;") must
+		 * not contain a <. 
+		 */
+		else if ((ctxt->instate == XML_PARSER_ATTRIBUTE_VALUE) &&
+		         (ent != NULL) &&
+			 (!xmlStrEqual(ent->name, BAD_CAST "lt")) &&
+		         (ent->content != NULL) &&
+			 (xmlStrchr(ent->content, '<'))) {
+		    ctxt->errNo = XML_ERR_LT_IN_ATTRIBUTE;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, 
+	 "'<' in entity '%s' is not allowed in attributes values\n", name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		}
+
+		/*
+		 * Internal check, no parameter entities here ...
+		 */
+		else {
+		    switch (ent->etype) {
+			case XML_INTERNAL_PARAMETER_ENTITY:
+			case XML_EXTERNAL_PARAMETER_ENTITY:
+			ctxt->errNo = XML_ERR_ENTITY_IS_PARAMETER;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData, 
+		     "Attempt to reference the parameter entity '%s'\n", name);
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+			break;
+			default:
+			break;
+		    }
+		}
+
+		/*
+		 * [ WFC: No Recursion ]
+		 * A parsed entity must not contain a recursive reference
+		 * to itself, either directly or indirectly. 
+		 * Done somewhwere else
+		 */
+
+	    } else {
+		ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "xmlParseEntityRef: expecting ';'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    xmlFree(name);
+	}
+    }
+    *str = ptr;
+    return(ent);
+}
+
+/**
+ * xmlParsePEReference:
+ * @ctxt:  an XML parser context
+ *
+ * parse PEReference declarations
+ * The entity content is handled directly by pushing it's content as
+ * a new input stream.
+ *
+ * [69] PEReference ::= '%' Name ';'
+ *
+ * [ WFC: No Recursion ]
+ * A parsed entity must not contain a recursive
+ * reference to itself, either directly or indirectly. 
+ *
+ * [ WFC: Entity Declared ]
+ * In a document without any DTD, a document with only an internal DTD
+ * subset which contains no parameter entity references, or a document
+ * with "standalone='yes'", ...  ... The declaration of a parameter
+ * entity must precede any reference to it...
+ *
+ * [ VC: Entity Declared ]
+ * In a document with an external subset or external parameter entities
+ * with "standalone='no'", ...  ... The declaration of a parameter entity
+ * must precede any reference to it...
+ *
+ * [ WFC: In DTD ]
+ * Parameter-entity references may only appear in the DTD.
+ * NOTE: misleading but this is handled.
+ */
+void
+xmlParsePEReference(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlEntityPtr entity = NULL;
+    xmlParserInputPtr input;
+
+    if (RAW == '%') {
+        NEXT;
+        name = xmlParseName(ctxt);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlParsePEReference: no name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    if (RAW == ';') {
+	        NEXT;
+		if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->getParameterEntity != NULL))
+		    entity = ctxt->sax->getParameterEntity(ctxt->userData,
+		                                           name);
+		if (entity == NULL) {
+		    /*
+		     * [ WFC: Entity Declared ]
+		     * In a document without any DTD, a document with only an
+		     * internal DTD subset which contains no parameter entity
+		     * references, or a document with "standalone='yes'", ...
+		     * ... The declaration of a parameter entity must precede
+		     * any reference to it...
+		     */
+		    if ((ctxt->standalone == 1) ||
+			((ctxt->hasExternalSubset == 0) &&
+			 (ctxt->hasPErefs == 0))) {
+			ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
+			if ((!ctxt->disableSAX) &&
+			    (ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+			     "PEReference: %%%s; not found\n", name);
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    } else {
+			/*
+			 * [ VC: Entity Declared ]
+			 * In a document with an external subset or external
+			 * parameter entities with "standalone='no'", ...
+			 * ... The declaration of a parameter entity must precede
+			 * any reference to it...
+			 */
+			if ((!ctxt->disableSAX) &&
+			    (ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			    ctxt->sax->warning(ctxt->userData,
+			     "PEReference: %%%s; not found\n", name);
+			ctxt->valid = 0;
+		    }
+		} else {
+		    /*
+		     * Internal checking in case the entity quest barfed
+		     */
+		    if ((entity->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
+		        (entity->etype != XML_EXTERNAL_PARAMETER_ENTITY)) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			    ctxt->sax->warning(ctxt->userData,
+			 "Internal: %%%s; is not a parameter entity\n", name);
+		    } else {
+			/*
+			 * TODO !!!
+			 * handle the extra spaces added before and after
+			 * c.f. http://www.w3.org/TR/REC-xml#as-PE
+			 */
+			input = xmlNewEntityInputStream(ctxt, entity);
+			xmlPushInput(ctxt, input);
+			if ((entity->etype == XML_EXTERNAL_PARAMETER_ENTITY) &&
+			    (RAW == '<') && (NXT(1) == '?') &&
+			    (NXT(2) == 'x') && (NXT(3) == 'm') &&
+			    (NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+			    xmlParseTextDecl(ctxt);
+			    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+				/*
+				 * The XML REC instructs us to stop parsing
+				 * right here
+				 */
+				ctxt->instate = XML_PARSER_EOF;
+				xmlFree(name);
+				return;
+			    }
+			}
+			if (ctxt->token == 0)
+			    ctxt->token = ' ';
+		    }
+		}
+		ctxt->hasPErefs = 1;
+	    } else {
+		ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "xmlParsePEReference: expecting ';'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    xmlFree(name);
+	}
+    }
+}
+
+/**
+ * xmlParseStringPEReference:
+ * @ctxt:  an XML parser context
+ * @str:  a pointer to an index in the string
+ *
+ * parse PEReference declarations
+ *
+ * [69] PEReference ::= '%' Name ';'
+ *
+ * [ WFC: No Recursion ]
+ * A parsed entity must not contain a recursive
+ * reference to itself, either directly or indirectly. 
+ *
+ * [ WFC: Entity Declared ]
+ * In a document without any DTD, a document with only an internal DTD
+ * subset which contains no parameter entity references, or a document
+ * with "standalone='yes'", ...  ... The declaration of a parameter
+ * entity must precede any reference to it...
+ *
+ * [ VC: Entity Declared ]
+ * In a document with an external subset or external parameter entities
+ * with "standalone='no'", ...  ... The declaration of a parameter entity
+ * must precede any reference to it...
+ *
+ * [ WFC: In DTD ]
+ * Parameter-entity references may only appear in the DTD.
+ * NOTE: misleading but this is handled.
+ *
+ * Returns the string of the entity content.
+ *         str is updated to the current value of the index
+ */
+xmlEntityPtr
+xmlParseStringPEReference(xmlParserCtxtPtr ctxt, const xmlChar **str) {
+    const xmlChar *ptr;
+    xmlChar cur;
+    xmlChar *name;
+    xmlEntityPtr entity = NULL;
+
+    if ((str == NULL) || (*str == NULL)) return(NULL);
+    ptr = *str;
+    cur = *ptr;
+    if (cur == '%') {
+        ptr++;
+	cur = *ptr;
+        name = xmlParseStringName(ctxt, &ptr);
+	if (name == NULL) {
+	    ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlParseStringPEReference: no name\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} else {
+	    cur = *ptr;
+	    if (cur == ';') {
+		ptr++;
+		cur = *ptr;
+		if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->getParameterEntity != NULL))
+		    entity = ctxt->sax->getParameterEntity(ctxt->userData,
+		                                           name);
+		if (entity == NULL) {
+		    /*
+		     * [ WFC: Entity Declared ]
+		     * In a document without any DTD, a document with only an
+		     * internal DTD subset which contains no parameter entity
+		     * references, or a document with "standalone='yes'", ...
+		     * ... The declaration of a parameter entity must precede
+		     * any reference to it...
+		     */
+		    if ((ctxt->standalone == 1) ||
+			((ctxt->hasExternalSubset == 0) &&
+			 (ctxt->hasPErefs == 0))) {
+			ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
+			if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			    ctxt->sax->error(ctxt->userData,
+			     "PEReference: %%%s; not found\n", name);
+			ctxt->wellFormed = 0;
+			ctxt->disableSAX = 1;
+		    } else {
+			/*
+			 * [ VC: Entity Declared ]
+			 * In a document with an external subset or external
+			 * parameter entities with "standalone='no'", ...
+			 * ... The declaration of a parameter entity must
+			 * precede any reference to it...
+			 */
+			if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			    ctxt->sax->warning(ctxt->userData,
+			     "PEReference: %%%s; not found\n", name);
+			ctxt->valid = 0;
+		    }
+		} else {
+		    /*
+		     * Internal checking in case the entity quest barfed
+		     */
+		    if ((entity->etype != XML_INTERNAL_PARAMETER_ENTITY) &&
+		        (entity->etype != XML_EXTERNAL_PARAMETER_ENTITY)) {
+			if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+			    ctxt->sax->warning(ctxt->userData,
+			 "Internal: %%%s; is not a parameter entity\n", name);
+		    }
+		}
+		ctxt->hasPErefs = 1;
+	    } else {
+		ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "xmlParseStringPEReference: expecting ';'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    xmlFree(name);
+	}
+    }
+    *str = ptr;
+    return(entity);
+}
+
+/**
+ * xmlParseDocTypeDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse a DOCTYPE declaration
+ *
+ * [28] doctypedecl ::= '<!DOCTYPE' S Name (S ExternalID)? S? 
+ *                      ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
+ *
+ * [ VC: Root Element Type ]
+ * The Name in the document type declaration must match the element
+ * type of the root element. 
+ */
+
+void
+xmlParseDocTypeDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *name = NULL;
+    xmlChar *ExternalID = NULL;
+    xmlChar *URI = NULL;
+
+    /*
+     * We know that '<!DOCTYPE' has been detected.
+     */
+    SKIP(9);
+
+    SKIP_BLANKS;
+
+    /*
+     * Parse the DOCTYPE name.
+     */
+    name = xmlParseName(ctxt);
+    if (name == NULL) {
+	ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	        "xmlParseDocTypeDecl : no DOCTYPE name !\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    ctxt->intSubName = name;
+
+    SKIP_BLANKS;
+
+    /*
+     * Check for SystemID and ExternalID
+     */
+    URI = xmlParseExternalID(ctxt, &ExternalID, 1);
+
+    if ((URI != NULL) || (ExternalID != NULL)) {
+        ctxt->hasExternalSubset = 1;
+    }
+    ctxt->extSubURI = URI;
+    ctxt->extSubSystem = ExternalID;
+
+    SKIP_BLANKS;
+
+    /*
+     * Create and update the internal subset.
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->internalSubset != NULL) &&
+	(!ctxt->disableSAX))
+	ctxt->sax->internalSubset(ctxt->userData, name, ExternalID, URI);
+
+    /*
+     * Is there any internal subset declarations ?
+     * they are handled separately in xmlParseInternalSubset()
+     */
+    if (RAW == '[')
+	return;
+
+    /*
+     * We should be at the end of the DOCTYPE declaration.
+     */
+    if (RAW != '>') {
+	ctxt->errNo = XML_ERR_DOCTYPE_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    NEXT;
+}
+
+/**
+ * xmlParseInternalsubset:
+ * @ctxt:  an XML parser context
+ *
+ * parse the internal subset declaration
+ *
+ * [28 end] ('[' (markupdecl | PEReference | S)* ']' S?)? '>'
+ */
+
+void
+xmlParseInternalSubset(xmlParserCtxtPtr ctxt) {
+    /*
+     * Is there any DTD definition ?
+     */
+    if (RAW == '[') {
+        ctxt->instate = XML_PARSER_DTD;
+        NEXT;
+	/*
+	 * Parse the succession of Markup declarations and 
+	 * PEReferences.
+	 * Subsequence (markupdecl | PEReference | S)*
+	 */
+	while (RAW != ']') {
+	    const xmlChar *check = CUR_PTR;
+	    int cons = ctxt->input->consumed;
+
+	    SKIP_BLANKS;
+	    xmlParseMarkupDecl(ctxt);
+	    xmlParsePEReference(ctxt);
+
+	    /*
+	     * Pop-up of finished entities.
+	     */
+	    while ((RAW == 0) && (ctxt->inputNr > 1))
+		xmlPopInput(ctxt);
+
+	    if ((CUR_PTR == check) && (cons == ctxt->input->consumed)) {
+		ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+	     "xmlParseInternalSubset: error detected in Markup declaration\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		break;
+	    }
+	}
+	if (RAW == ']') { 
+	    NEXT;
+	    SKIP_BLANKS;
+	}
+    }
+
+    /*
+     * We should be at the end of the DOCTYPE declaration.
+     */
+    if (RAW != '>') {
+	ctxt->errNo = XML_ERR_DOCTYPE_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "DOCTYPE unproperly terminated\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    NEXT;
+}
+
+/**
+ * xmlParseAttribute:
+ * @ctxt:  an XML parser context
+ * @value:  a xmlChar ** used to store the value of the attribute
+ *
+ * parse an attribute
+ *
+ * [41] Attribute ::= Name Eq AttValue
+ *
+ * [ WFC: No External Entity References ]
+ * Attribute values cannot contain direct or indirect entity references
+ * to external entities.
+ *
+ * [ WFC: No < in Attribute Values ]
+ * The replacement text of any entity referred to directly or indirectly in
+ * an attribute value (other than "&lt;") must not contain a <. 
+ * 
+ * [ VC: Attribute Value Type ]
+ * The attribute must have been declared; the value must be of the type
+ * declared for it.
+ *
+ * [25] Eq ::= S? '=' S?
+ *
+ * With namespace:
+ *
+ * [NS 11] Attribute ::= QName Eq AttValue
+ *
+ * Also the case QName == xmlns:??? is handled independently as a namespace
+ * definition.
+ *
+ * Returns the attribute name, and the value in *value.
+ */
+
+xmlChar *
+xmlParseAttribute(xmlParserCtxtPtr ctxt, xmlChar **value) {
+    xmlChar *name, *val;
+
+    *value = NULL;
+    name = xmlParseName(ctxt);
+    if (name == NULL) {
+	ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "error parsing attribute name\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+        return(NULL);
+    }
+
+    /*
+     * read the value
+     */
+    SKIP_BLANKS;
+    if (RAW == '=') {
+        NEXT;
+	SKIP_BLANKS;
+	val = xmlParseAttValue(ctxt);
+	ctxt->instate = XML_PARSER_CONTENT;
+    } else {
+	ctxt->errNo = XML_ERR_ATTRIBUTE_WITHOUT_VALUE;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	       "Specification mandate value for attribute %s\n", name);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	xmlFree(name);
+	return(NULL);
+    }
+
+    /*
+     * Check that xml:lang conforms to the specification
+     * No more registered as an error, just generate a warning now
+     * since this was deprecated in XML second edition
+     */
+    if ((ctxt->pedantic) && (xmlStrEqual(name, BAD_CAST "xml:lang"))) {
+	if (!xmlCheckLanguageID(val)) {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+		ctxt->sax->warning(ctxt->userData,
+		   "Malformed value for xml:lang : %s\n", val);
+	}
+    }
+
+    /*
+     * Check that xml:space conforms to the specification
+     */
+    if (xmlStrEqual(name, BAD_CAST "xml:space")) {
+	if (xmlStrEqual(val, BAD_CAST "default"))
+	    *(ctxt->space) = 0;
+	else if (xmlStrEqual(val, BAD_CAST "preserve"))
+	    *(ctxt->space) = 1;
+	else {
+	    ctxt->errNo = XML_ERR_ATTRIBUTE_WITHOUT_VALUE;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+"Invalid value for xml:space : \"%s\", \"default\" or \"preserve\" expected\n",
+                                 val);
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+    }
+
+    *value = val;
+    return(name);
+}
+
+/**
+ * xmlParseStartTag:
+ * @ctxt:  an XML parser context
+ * 
+ * parse a start of tag either for rule element or
+ * EmptyElement. In both case we don't parse the tag closing chars.
+ *
+ * [40] STag ::= '<' Name (S Attribute)* S? '>'
+ *
+ * [ WFC: Unique Att Spec ]
+ * No attribute name may appear more than once in the same start-tag or
+ * empty-element tag. 
+ *
+ * [44] EmptyElemTag ::= '<' Name (S Attribute)* S? '/>'
+ *
+ * [ WFC: Unique Att Spec ]
+ * No attribute name may appear more than once in the same start-tag or
+ * empty-element tag. 
+ *
+ * With namespace:
+ *
+ * [NS 8] STag ::= '<' QName (S Attribute)* S? '>'
+ *
+ * [NS 10] EmptyElement ::= '<' QName (S Attribute)* S? '/>'
+ *
+ * Returns the element name parsed
+ */
+
+xmlChar *
+xmlParseStartTag(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *attname;
+    xmlChar *attvalue;
+    const xmlChar **atts = NULL;
+    int nbatts = 0;
+    int maxatts = 0;
+    int i;
+
+    if (RAW != '<') return(NULL);
+    NEXT;
+
+    name = xmlParseName(ctxt);
+    if (name == NULL) {
+	ctxt->errNo = XML_ERR_NAME_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	     "xmlParseStartTag: invalid element name\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+        return(NULL);
+    }
+
+    /*
+     * Now parse the attributes, it ends up with the ending
+     *
+     * (S Attribute)* S?
+     */
+    SKIP_BLANKS;
+    GROW;
+
+    while ((IS_CHAR(RAW)) &&
+           (RAW != '>') && 
+	   ((RAW != '/') || (NXT(1) != '>'))) {
+	const xmlChar *q = CUR_PTR;
+	int cons = ctxt->input->consumed;
+
+	attname = xmlParseAttribute(ctxt, &attvalue);
+        if ((attname != NULL) && (attvalue != NULL)) {
+	    /*
+	     * [ WFC: Unique Att Spec ]
+	     * No attribute name may appear more than once in the same
+	     * start-tag or empty-element tag. 
+	     */
+	    for (i = 0; i < nbatts;i += 2) {
+	        if (xmlStrEqual(atts[i], attname)) {
+		    ctxt->errNo = XML_ERR_ATTRIBUTE_REDEFINED;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			        "Attribute %s redefined\n",
+			                 attname);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    xmlFree(attname);
+		    xmlFree(attvalue);
+		    goto failed;
+		}
+	    }
+
+	    /*
+	     * Add the pair to atts
+	     */
+	    if (atts == NULL) {
+	        maxatts = 10;
+	        atts = (const xmlChar **) xmlMalloc(maxatts * sizeof(xmlChar *));
+		if (atts == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "malloc of %ld byte failed\n",
+			    maxatts * (long)sizeof(xmlChar *));
+		    return(NULL);
+		}
+	    } else if (nbatts + 4 > maxatts) {
+	        maxatts *= 2;
+	        atts = (const xmlChar **) xmlRealloc((void *) atts,
+						     maxatts * sizeof(xmlChar *));
+		if (atts == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "realloc of %ld byte failed\n",
+			    maxatts * (long)sizeof(xmlChar *));
+		    return(NULL);
+		}
+	    }
+	    atts[nbatts++] = attname;
+	    atts[nbatts++] = attvalue;
+	    atts[nbatts] = NULL;
+	    atts[nbatts + 1] = NULL;
+	} else {
+	    if (attname != NULL)
+		xmlFree(attname);
+	    if (attvalue != NULL)
+		xmlFree(attvalue);
+	}
+
+failed:     
+
+	if ((RAW == '>') || (((RAW == '/') && (NXT(1) == '>'))))
+	    break;
+	if (!IS_BLANK(RAW)) {
+	    ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "attributes construct error\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	SKIP_BLANKS;
+        if ((cons == ctxt->input->consumed) && (q == CUR_PTR)) {
+	    ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+	         "xmlParseStartTag: problem parsing attributes\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    break;
+	}
+        GROW;
+    }
+
+    /*
+     * SAX: Start of Element !
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->startElement != NULL) &&
+	(!ctxt->disableSAX))
+        ctxt->sax->startElement(ctxt->userData, name, atts);
+
+    if (atts != NULL) {
+        for (i = 0;i < nbatts;i++) xmlFree((xmlChar *) atts[i]);
+	xmlFree((void *) atts);
+    }
+    return(name);
+}
+
+/**
+ * xmlParseEndTag:
+ * @ctxt:  an XML parser context
+ *
+ * parse an end of tag
+ *
+ * [42] ETag ::= '</' Name S? '>'
+ *
+ * With namespace
+ *
+ * [NS 9] ETag ::= '</' QName S? '>'
+ */
+
+void
+xmlParseEndTag(xmlParserCtxtPtr ctxt) {
+    xmlChar *name;
+    xmlChar *oldname;
+
+    GROW;
+    if ((RAW != '<') || (NXT(1) != '/')) {
+	ctxt->errNo = XML_ERR_LTSLASH_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "xmlParseEndTag: '</' not found\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	return;
+    }
+    SKIP(2);
+
+    name = xmlParseName(ctxt);
+
+    /*
+     * We should definitely be at the ending "S? '>'" part
+     */
+    GROW;
+    SKIP_BLANKS;
+    if ((!IS_CHAR(RAW)) || (RAW != '>')) {
+	ctxt->errNo = XML_ERR_GT_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "End tag : expected '>'\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else
+	NEXT;
+
+    /*
+     * [ WFC: Element Type Match ]
+     * The Name in an element's end-tag must match the element type in the
+     * start-tag. 
+     *
+     */
+    if ((name == NULL) || (ctxt->name == NULL) ||
+        (!xmlStrEqual(name, ctxt->name))) {
+	ctxt->errNo = XML_ERR_TAG_NAME_MISMATCH;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
+	    if ((name != NULL) && (ctxt->name != NULL)) {
+		ctxt->sax->error(ctxt->userData,
+		     "Opening and ending tag mismatch: %s and %s\n",
+		                 ctxt->name, name);
+            } else if (ctxt->name != NULL) {
+		ctxt->sax->error(ctxt->userData,
+		     "Ending tag eror for: %s\n", ctxt->name);
+	    } else {
+		ctxt->sax->error(ctxt->userData,
+		     "Ending tag error: internal error ???\n");
+	    }
+
+	}     
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    /*
+     * SAX: End of Tag
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) &&
+	(!ctxt->disableSAX))
+        ctxt->sax->endElement(ctxt->userData, name);
+
+    if (name != NULL)
+	xmlFree(name);
+    oldname = namePop(ctxt);
+    spacePop(ctxt);
+    if (oldname != NULL) {
+#ifdef DEBUG_STACK
+	xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+	xmlFree(oldname);
+    }
+    return;
+}
+
+/**
+ * xmlParseCDSect:
+ * @ctxt:  an XML parser context
+ * 
+ * Parse escaped pure raw content.
+ *
+ * [18] CDSect ::= CDStart CData CDEnd
+ *
+ * [19] CDStart ::= '<![CDATA['
+ *
+ * [20] Data ::= (Char* - (Char* ']]>' Char*))
+ *
+ * [21] CDEnd ::= ']]>'
+ */
+void
+xmlParseCDSect(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = XML_PARSER_BUFFER_SIZE;
+    int r, rl;
+    int	s, sl;
+    int cur, l;
+    int count = 0;
+
+    if ((NXT(0) == '<') && (NXT(1) == '!') &&
+	(NXT(2) == '[') && (NXT(3) == 'C') &&
+	(NXT(4) == 'D') && (NXT(5) == 'A') &&
+	(NXT(6) == 'T') && (NXT(7) == 'A') &&
+	(NXT(8) == '[')) {
+	SKIP(9);
+    } else
+        return;
+
+    ctxt->instate = XML_PARSER_CDATA_SECTION;
+    r = CUR_CHAR(rl);
+    if (!IS_CHAR(r)) {
+	ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "CData section not finished\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	ctxt->instate = XML_PARSER_CONTENT;
+        return;
+    }
+    NEXTL(rl);
+    s = CUR_CHAR(sl);
+    if (!IS_CHAR(s)) {
+	ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "CData section not finished\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	ctxt->instate = XML_PARSER_CONTENT;
+        return;
+    }
+    NEXTL(sl);
+    cur = CUR_CHAR(l);
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	return;
+    }
+    while (IS_CHAR(cur) &&
+           ((r != ']') || (s != ']') || (cur != '>'))) {
+	if (len + 5 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		return;
+	    }
+	}
+	COPY_BUF(rl,buf,len,r);
+	r = s;
+	rl = sl;
+	s = cur;
+	sl = l;
+	count++;
+	if (count > 50) {
+	    GROW;
+	    count = 0;
+	}
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+    }
+    buf[len] = 0;
+    ctxt->instate = XML_PARSER_CONTENT;
+    if (cur != '>') {
+	ctxt->errNo = XML_ERR_CDATA_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "CData section not finished\n%.50s\n", buf);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	xmlFree(buf);
+        return;
+    }
+    NEXTL(l);
+
+    /*
+     * Ok the buffer is to be consumed as cdata.
+     */
+    if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+	if (ctxt->sax->cdataBlock != NULL)
+	    ctxt->sax->cdataBlock(ctxt->userData, buf, len);
+    }
+    xmlFree(buf);
+}
+
+/**
+ * xmlParseContent:
+ * @ctxt:  an XML parser context
+ *
+ * Parse a content:
+ *
+ * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ */
+
+void
+xmlParseContent(xmlParserCtxtPtr ctxt) {
+    GROW;
+    while (((RAW != 0) || (ctxt->token != 0)) &&
+	   ((RAW != '<') || (NXT(1) != '/'))) {
+	const xmlChar *test = CUR_PTR;
+	int cons = ctxt->input->consumed;
+	xmlChar tok = ctxt->token;
+
+	/*
+	 * Handle  possible processed charrefs.
+	 */
+	if (ctxt->token != 0) {
+	    xmlParseCharData(ctxt, 0);
+	}
+	/*
+	 * First case : a Processing Instruction.
+	 */
+	else if ((RAW == '<') && (NXT(1) == '?')) {
+	    xmlParsePI(ctxt);
+	}
+
+	/*
+	 * Second case : a CDSection
+	 */
+	else if ((RAW == '<') && (NXT(1) == '!') &&
+	    (NXT(2) == '[') && (NXT(3) == 'C') &&
+	    (NXT(4) == 'D') && (NXT(5) == 'A') &&
+	    (NXT(6) == 'T') && (NXT(7) == 'A') &&
+	    (NXT(8) == '[')) {
+	    xmlParseCDSect(ctxt);
+	}
+
+	/*
+	 * Third case :  a comment
+	 */
+	else if ((RAW == '<') && (NXT(1) == '!') &&
+		 (NXT(2) == '-') && (NXT(3) == '-')) {
+	    xmlParseComment(ctxt);
+	    ctxt->instate = XML_PARSER_CONTENT;
+	}
+
+	/*
+	 * Fourth case :  a sub-element.
+	 */
+	else if (RAW == '<') {
+	    xmlParseElement(ctxt);
+	}
+
+	/*
+	 * Fifth case : a reference. If if has not been resolved,
+	 *    parsing returns it's Name, create the node 
+	 */
+
+	else if (RAW == '&') {
+	    xmlParseReference(ctxt);
+	}
+
+	/*
+	 * Last case, text. Note that References are handled directly.
+	 */
+	else {
+	    xmlParseCharData(ctxt, 0);
+	}
+
+	GROW;
+	/*
+	 * Pop-up of finished entities.
+	 */
+	while ((RAW == 0) && (ctxt->inputNr > 1))
+	    xmlPopInput(ctxt);
+	SHRINK;
+
+	if ((cons == ctxt->input->consumed) && (test == CUR_PTR) &&
+	    (tok == ctxt->token)) {
+	    ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		     "detected an error in element content\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    ctxt->instate = XML_PARSER_EOF;
+            break;
+	}
+    }
+}
+
+/**
+ * xmlParseElement:
+ * @ctxt:  an XML parser context
+ *
+ * parse an XML element, this is highly recursive
+ *
+ * [39] element ::= EmptyElemTag | STag content ETag
+ *
+ * [ WFC: Element Type Match ]
+ * The Name in an element's end-tag must match the element type in the
+ * start-tag. 
+ *
+ * [ VC: Element Valid ]
+ * An element is valid if there is a declaration matching elementdecl
+ * where the Name matches the element type and one of the following holds:
+ *  - The declaration matches EMPTY and the element has no content.
+ *  - The declaration matches children and the sequence of child elements
+ *    belongs to the language generated by the regular expression in the
+ *    content model, with optional white space (characters matching the
+ *    nonterminal S) between each pair of child elements. 
+ *  - The declaration matches Mixed and the content consists of character
+ *    data and child elements whose types match names in the content model. 
+ *  - The declaration matches ANY, and the types of any child elements have
+ *    been declared.
+ */
+
+void
+xmlParseElement(xmlParserCtxtPtr ctxt) {
+    const xmlChar *openTag = CUR_PTR;
+    xmlChar *name;
+    xmlChar *oldname;
+    xmlParserNodeInfo node_info;
+    xmlNodePtr ret;
+
+    /* Capture start position */
+    if (ctxt->record_info) {
+        node_info.begin_pos = ctxt->input->consumed +
+                          (CUR_PTR - ctxt->input->base);
+	node_info.begin_line = ctxt->input->line;
+    }
+
+    if (ctxt->spaceNr == 0)
+	spacePush(ctxt, -1);
+    else
+	spacePush(ctxt, *ctxt->space);
+
+    name = xmlParseStartTag(ctxt);
+    if (name == NULL) {
+	spacePop(ctxt);
+        return;
+    }
+    namePush(ctxt, name);
+    ret = ctxt->node;
+
+    /*
+     * [ VC: Root Element Type ]
+     * The Name in the document type declaration must match the element
+     * type of the root element. 
+     */
+    if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
+        ctxt->node && (ctxt->node == ctxt->myDoc->children))
+        ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
+
+    /*
+     * Check for an Empty Element.
+     */
+    if ((RAW == '/') && (NXT(1) == '>')) {
+        SKIP(2);
+	if ((ctxt->sax != NULL) && (ctxt->sax->endElement != NULL) &&
+	    (!ctxt->disableSAX))
+	    ctxt->sax->endElement(ctxt->userData, name);
+	oldname = namePop(ctxt);
+	spacePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG_STACK
+	    xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+	    xmlFree(oldname);
+	}
+	if ( ret != NULL && ctxt->record_info ) {
+	   node_info.end_pos = ctxt->input->consumed +
+			      (CUR_PTR - ctxt->input->base);
+	   node_info.end_line = ctxt->input->line;
+	   node_info.node = ret;
+	   xmlParserAddNodeInfo(ctxt, &node_info);
+	}
+	return;
+    }
+    if (RAW == '>') {
+        NEXT;
+    } else {
+	ctxt->errNo = XML_ERR_GT_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "Couldn't find end of Start Tag\n%.30s\n",
+	                     openTag);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+
+	/*
+	 * end of parsing of this node.
+	 */
+	nodePop(ctxt);
+	oldname = namePop(ctxt);
+	spacePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG_STACK
+	    xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+	    xmlFree(oldname);
+	}
+
+	/*
+	 * Capture end position and add node
+	 */
+	if ( ret != NULL && ctxt->record_info ) {
+	   node_info.end_pos = ctxt->input->consumed +
+			      (CUR_PTR - ctxt->input->base);
+	   node_info.end_line = ctxt->input->line;
+	   node_info.node = ret;
+	   xmlParserAddNodeInfo(ctxt, &node_info);
+	}
+	return;
+    }
+
+    /*
+     * Parse the content of the element:
+     */
+    xmlParseContent(ctxt);
+    if (!IS_CHAR(RAW)) {
+	ctxt->errNo = XML_ERR_TAG_NOT_FINISED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	         "Premature end of data in tag %.30s\n", openTag);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+
+	/*
+	 * end of parsing of this node.
+	 */
+	nodePop(ctxt);
+	oldname = namePop(ctxt);
+	spacePop(ctxt);
+	if (oldname != NULL) {
+#ifdef DEBUG_STACK
+	    xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+	    xmlFree(oldname);
+	}
+	return;
+    }
+
+    /*
+     * parse the end of tag: '</' should be here.
+     */
+    xmlParseEndTag(ctxt);
+
+    /*
+     * Capture end position and add node
+     */
+    if ( ret != NULL && ctxt->record_info ) {
+       node_info.end_pos = ctxt->input->consumed +
+                          (CUR_PTR - ctxt->input->base);
+       node_info.end_line = ctxt->input->line;
+       node_info.node = ret;
+       xmlParserAddNodeInfo(ctxt, &node_info);
+    }
+}
+
+/**
+ * xmlParseVersionNum:
+ * @ctxt:  an XML parser context
+ *
+ * parse the XML version value.
+ *
+ * [26] VersionNum ::= ([a-zA-Z0-9_.:] | '-')+
+ *
+ * Returns the string giving the XML version number, or NULL
+ */
+xmlChar *
+xmlParseVersionNum(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = 10;
+    xmlChar cur;
+
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	return(NULL);
+    }
+    cur = CUR;
+    while (((cur >= 'a') && (cur <= 'z')) ||
+           ((cur >= 'A') && (cur <= 'Z')) ||
+           ((cur >= '0') && (cur <= '9')) ||
+           (cur == '_') || (cur == '.') ||
+	   (cur == ':') || (cur == '-')) {
+	if (len + 1 >= size) {
+	    size *= 2;
+	    buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+	    if (buf == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"realloc of %d byte failed\n", size);
+		return(NULL);
+	    }
+	}
+	buf[len++] = cur;
+	NEXT;
+	cur=CUR;
+    }
+    buf[len] = 0;
+    return(buf);
+}
+
+/**
+ * xmlParseVersionInfo:
+ * @ctxt:  an XML parser context
+ * 
+ * parse the XML version.
+ *
+ * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
+ * 
+ * [25] Eq ::= S? '=' S?
+ *
+ * Returns the version string, e.g. "1.0"
+ */
+
+xmlChar *
+xmlParseVersionInfo(xmlParserCtxtPtr ctxt) {
+    xmlChar *version = NULL;
+    const xmlChar *q;
+
+    if ((RAW == 'v') && (NXT(1) == 'e') &&
+        (NXT(2) == 'r') && (NXT(3) == 's') &&
+	(NXT(4) == 'i') && (NXT(5) == 'o') &&
+	(NXT(6) == 'n')) {
+	SKIP(7);
+	SKIP_BLANKS;
+	if (RAW != '=') {
+	    ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlParseVersionInfo : expected '='\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(NULL);
+        }
+	NEXT;
+	SKIP_BLANKS;
+	if (RAW == '"') {
+	    NEXT;
+	    q = CUR_PTR;
+	    version = xmlParseVersionNum(ctxt);
+	    if (RAW != '"') {
+		ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		                     "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else
+	        NEXT;
+	} else if (RAW == '\''){
+	    NEXT;
+	    q = CUR_PTR;
+	    version = xmlParseVersionNum(ctxt);
+	    if (RAW != '\'') {
+		ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else
+	        NEXT;
+	} else {
+	    ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		      "xmlParseVersionInfo : expected ' or \"\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+    }
+    return(version);
+}
+
+/**
+ * xmlParseEncName:
+ * @ctxt:  an XML parser context
+ *
+ * parse the XML encoding name
+ *
+ * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+ *
+ * Returns the encoding name value or NULL
+ */
+xmlChar *
+xmlParseEncName(xmlParserCtxtPtr ctxt) {
+    xmlChar *buf = NULL;
+    int len = 0;
+    int size = 10;
+    xmlChar cur;
+
+    cur = CUR;
+    if (((cur >= 'a') && (cur <= 'z')) ||
+        ((cur >= 'A') && (cur <= 'Z'))) {
+	buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+	if (buf == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc of %d byte failed\n", size);
+	    return(NULL);
+	}
+	
+	buf[len++] = cur;
+	NEXT;
+	cur = CUR;
+	while (((cur >= 'a') && (cur <= 'z')) ||
+	       ((cur >= 'A') && (cur <= 'Z')) ||
+	       ((cur >= '0') && (cur <= '9')) ||
+	       (cur == '.') || (cur == '_') ||
+	       (cur == '-')) {
+	    if (len + 1 >= size) {
+		size *= 2;
+		buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+		if (buf == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "realloc of %d byte failed\n", size);
+		    return(NULL);
+		}
+	    }
+	    buf[len++] = cur;
+	    NEXT;
+	    cur = CUR;
+	    if (cur == 0) {
+	        SHRINK;
+		GROW;
+		cur = CUR;
+	    }
+        }
+	buf[len] = 0;
+    } else {
+	ctxt->errNo = XML_ERR_ENCODING_NAME;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Invalid XML encoding name\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    return(buf);
+}
+
+/**
+ * xmlParseEncodingDecl:
+ * @ctxt:  an XML parser context
+ * 
+ * parse the XML encoding declaration
+ *
+ * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'")
+ *
+ * this setups the conversion filters.
+ *
+ * Returns the encoding value or NULL
+ */
+
+xmlChar *
+xmlParseEncodingDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *encoding = NULL;
+    const xmlChar *q;
+
+    SKIP_BLANKS;
+    if ((RAW == 'e') && (NXT(1) == 'n') &&
+        (NXT(2) == 'c') && (NXT(3) == 'o') &&
+	(NXT(4) == 'd') && (NXT(5) == 'i') &&
+	(NXT(6) == 'n') && (NXT(7) == 'g')) {
+	SKIP(8);
+	SKIP_BLANKS;
+	if (RAW != '=') {
+	    ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlParseEncodingDecl : expected '='\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(NULL);
+        }
+	NEXT;
+	SKIP_BLANKS;
+	if (RAW == '"') {
+	    NEXT;
+	    q = CUR_PTR;
+	    encoding = xmlParseEncName(ctxt);
+	    if (RAW != '"') {
+		ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		                     "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else
+	        NEXT;
+	} else if (RAW == '\''){
+	    NEXT;
+	    q = CUR_PTR;
+	    encoding = xmlParseEncName(ctxt);
+	    if (RAW != '\'') {
+		ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "String not closed\n%.50s\n", q);
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else
+	        NEXT;
+	} else if (RAW == '"'){
+	    ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		     "xmlParseEncodingDecl : expected ' or \"\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	if (encoding != NULL) {
+	    xmlCharEncoding enc;
+	    xmlCharEncodingHandlerPtr handler;
+
+	    if (ctxt->input->encoding != NULL)
+		xmlFree((xmlChar *) ctxt->input->encoding);
+	    ctxt->input->encoding = encoding;
+
+	    enc = xmlParseCharEncoding((const char *) encoding);
+	    /*
+	     * registered set of known encodings
+	     */
+	    if (enc != XML_CHAR_ENCODING_ERROR) {
+		xmlSwitchEncoding(ctxt, enc);
+		if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+		    xmlFree(encoding);
+		    return(NULL);
+		}
+	    } else {
+	        /*
+		 * fallback for unknown encodings
+		 */
+                handler = xmlFindCharEncodingHandler((const char *) encoding);
+		if (handler != NULL) {
+		    xmlSwitchToEncoding(ctxt, handler);
+		} else {
+		    ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			     "Unsupported encoding %s\n", encoding);
+		    return(NULL);
+		}
+	    }
+	}
+    }
+    return(encoding);
+}
+
+/**
+ * xmlParseSDDecl:
+ * @ctxt:  an XML parser context
+ *
+ * parse the XML standalone declaration
+ *
+ * [32] SDDecl ::= S 'standalone' Eq
+ *                 (("'" ('yes' | 'no') "'") | ('"' ('yes' | 'no')'"')) 
+ *
+ * [ VC: Standalone Document Declaration ]
+ * TODO The standalone document declaration must have the value "no"
+ * if any external markup declarations contain declarations of:
+ *  - attributes with default values, if elements to which these
+ *    attributes apply appear in the document without specifications
+ *    of values for these attributes, or
+ *  - entities (other than amp, lt, gt, apos, quot), if references
+ *    to those entities appear in the document, or
+ *  - attributes with values subject to normalization, where the
+ *    attribute appears in the document with a value which will change
+ *    as a result of normalization, or
+ *  - element types with element content, if white space occurs directly
+ *    within any instance of those types.
+ *
+ * Returns 1 if standalone, 0 otherwise
+ */
+
+int
+xmlParseSDDecl(xmlParserCtxtPtr ctxt) {
+    int standalone = -1;
+
+    SKIP_BLANKS;
+    if ((RAW == 's') && (NXT(1) == 't') &&
+        (NXT(2) == 'a') && (NXT(3) == 'n') &&
+	(NXT(4) == 'd') && (NXT(5) == 'a') &&
+	(NXT(6) == 'l') && (NXT(7) == 'o') &&
+	(NXT(8) == 'n') && (NXT(9) == 'e')) {
+	SKIP(10);
+        SKIP_BLANKS;
+	if (RAW != '=') {
+	    ctxt->errNo = XML_ERR_EQUAL_REQUIRED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		    "XML standalone declaration : expected '='\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return(standalone);
+        }
+	NEXT;
+	SKIP_BLANKS;
+        if (RAW == '\''){
+	    NEXT;
+	    if ((RAW == 'n') && (NXT(1) == 'o')) {
+	        standalone = 0;
+                SKIP(2);
+	    } else if ((RAW == 'y') && (NXT(1) == 'e') &&
+	               (NXT(2) == 's')) {
+	        standalone = 1;
+		SKIP(3);
+            } else {
+		ctxt->errNo = XML_ERR_STANDALONE_VALUE;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "standalone accepts only 'yes' or 'no'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    if (RAW != '\'') {
+		ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, "String not closed\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else
+	        NEXT;
+	} else if (RAW == '"'){
+	    NEXT;
+	    if ((RAW == 'n') && (NXT(1) == 'o')) {
+	        standalone = 0;
+		SKIP(2);
+	    } else if ((RAW == 'y') && (NXT(1) == 'e') &&
+	               (NXT(2) == 's')) {
+	        standalone = 1;
+                SKIP(3);
+            } else {
+		ctxt->errNo = XML_ERR_STANDALONE_VALUE;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		        "standalone accepts only 'yes' or 'no'\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }
+	    if (RAW != '"') {
+		ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, "String not closed\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    } else
+	        NEXT;
+	} else {
+	    ctxt->errNo = XML_ERR_STRING_NOT_STARTED;
+            if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "Standalone value not found\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+        }
+    }
+    return(standalone);
+}
+
+/**
+ * xmlParseXMLDecl:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML declaration header
+ *
+ * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
+ */
+
+void
+xmlParseXMLDecl(xmlParserCtxtPtr ctxt) {
+    xmlChar *version;
+
+    /*
+     * We know that '<?xml' is here.
+     */
+    SKIP(5);
+
+    if (!IS_BLANK(RAW)) {
+	ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Blank needed after '<?xml'\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    SKIP_BLANKS;
+
+    /*
+     * We should have the VersionInfo here.
+     */
+    version = xmlParseVersionInfo(ctxt);
+    if (version == NULL)
+	version = xmlCharStrdup(XML_DEFAULT_VERSION);
+    ctxt->version = xmlStrdup(version);
+    xmlFree(version);
+
+    /*
+     * We may have the encoding declaration
+     */
+    if (!IS_BLANK(RAW)) {
+        if ((RAW == '?') && (NXT(1) == '>')) {
+	    SKIP(2);
+	    return;
+	}
+	ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Blank needed here\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    xmlParseEncodingDecl(ctxt);
+    if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	/*
+	 * The XML REC instructs us to stop parsing right here
+	 */
+        return;
+    }
+
+    /*
+     * We may have the standalone status.
+     */
+    if ((ctxt->input->encoding != NULL) && (!IS_BLANK(RAW))) {
+        if ((RAW == '?') && (NXT(1) == '>')) {
+	    SKIP(2);
+	    return;
+	}
+	ctxt->errNo = XML_ERR_SPACE_REQUIRED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Blank needed here\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    SKIP_BLANKS;
+    ctxt->input->standalone = xmlParseSDDecl(ctxt);
+
+    SKIP_BLANKS;
+    if ((RAW == '?') && (NXT(1) == '>')) {
+        SKIP(2);
+    } else if (RAW == '>') {
+        /* Deprecated old WD ... */
+	ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	                     "XML declaration must end-up with '?>'\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	NEXT;
+    } else {
+	ctxt->errNo = XML_ERR_XMLDECL_NOT_FINISHED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	                     "parsing XML declaration: '?>' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	MOVETO_ENDTAG(CUR_PTR);
+	NEXT;
+    }
+}
+
+/**
+ * xmlParseMisc:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML Misc* optionnal field.
+ *
+ * [27] Misc ::= Comment | PI |  S
+ */
+
+void
+xmlParseMisc(xmlParserCtxtPtr ctxt) {
+    while (((RAW == '<') && (NXT(1) == '?')) ||
+           ((RAW == '<') && (NXT(1) == '!') &&
+	    (NXT(2) == '-') && (NXT(3) == '-')) ||
+           IS_BLANK(CUR)) {
+        if ((RAW == '<') && (NXT(1) == '?')) {
+	    xmlParsePI(ctxt);
+	} else if (IS_BLANK(CUR)) {
+	    NEXT;
+	} else
+	    xmlParseComment(ctxt);
+    }
+}
+
+/**
+ * xmlParseDocument:
+ * @ctxt:  an XML parser context
+ * 
+ * parse an XML document (and build a tree if using the standard SAX
+ * interface).
+ *
+ * [1] document ::= prolog element Misc*
+ *
+ * [22] prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
+ *
+ * Returns 0, -1 in case of error. the parser context is augmented
+ *                as a result of the parsing.
+ */
+
+int
+xmlParseDocument(xmlParserCtxtPtr ctxt) {
+    xmlChar start[4];
+    xmlCharEncoding enc;
+
+    xmlInitParser();
+
+    GROW;
+
+    /*
+     * SAX: beginning of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+        ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
+
+    /* 
+     * Get the 4 first bytes and decode the charset
+     * if enc != XML_CHAR_ENCODING_NONE
+     * plug some encoding conversion routines.
+     */
+    start[0] = RAW;
+    start[1] = NXT(1);
+    start[2] = NXT(2);
+    start[3] = NXT(3);
+    enc = xmlDetectCharEncoding(start, 4);
+    if (enc != XML_CHAR_ENCODING_NONE) {
+        xmlSwitchEncoding(ctxt, enc);
+    }
+
+
+    if (CUR == 0) {
+	ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Document is empty\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    /*
+     * Check for the XMLDecl in the Prolog.
+     */
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '?') &&
+        (NXT(2) == 'x') && (NXT(3) == 'm') &&
+	(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+
+	/*
+	 * Note that we will switch encoding on the fly.
+	 */
+	xmlParseXMLDecl(ctxt);
+	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	    /*
+	     * The XML REC instructs us to stop parsing right here
+	     */
+	    return(-1);
+	}
+	ctxt->standalone = ctxt->input->standalone;
+	SKIP_BLANKS;
+    } else {
+	ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
+    }
+    if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX))
+        ctxt->sax->startDocument(ctxt->userData);
+
+    /*
+     * The Misc part of the Prolog
+     */
+    GROW;
+    xmlParseMisc(ctxt);
+
+    /*
+     * Then possibly doc type declaration(s) and more Misc
+     * (doctypedecl Misc*)?
+     */
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '!') &&
+	(NXT(2) == 'D') && (NXT(3) == 'O') &&
+	(NXT(4) == 'C') && (NXT(5) == 'T') &&
+	(NXT(6) == 'Y') && (NXT(7) == 'P') &&
+	(NXT(8) == 'E')) {
+
+	ctxt->inSubset = 1;
+	xmlParseDocTypeDecl(ctxt);
+	if (RAW == '[') {
+	    ctxt->instate = XML_PARSER_DTD;
+	    xmlParseInternalSubset(ctxt);
+	}
+
+	/*
+	 * Create and update the external subset.
+	 */
+	ctxt->inSubset = 2;
+	if ((ctxt->sax != NULL) && (ctxt->sax->externalSubset != NULL) &&
+	    (!ctxt->disableSAX))
+	    ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName,
+	                              ctxt->extSubSystem, ctxt->extSubURI);
+	ctxt->inSubset = 0;
+
+
+	ctxt->instate = XML_PARSER_PROLOG;
+	xmlParseMisc(ctxt);
+    }
+
+    /*
+     * Time to start parsing the tree itself
+     */
+    GROW;
+    if (RAW != '<') {
+	ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		    "Start tag expected, '<' not found\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	ctxt->instate = XML_PARSER_EOF;
+    } else {
+	ctxt->instate = XML_PARSER_CONTENT;
+	xmlParseElement(ctxt);
+	ctxt->instate = XML_PARSER_EPILOG;
+
+
+	/*
+	 * The Misc part at the end
+	 */
+	xmlParseMisc(ctxt);
+
+	if (RAW != 0) {
+	    ctxt->errNo = XML_ERR_DOCUMENT_END;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Extra content at the end of the document\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	}
+	ctxt->instate = XML_PARSER_EOF;
+    }
+
+    /*
+     * SAX: end of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL) &&
+	(!ctxt->disableSAX))
+        ctxt->sax->endDocument(ctxt->userData);
+
+    if (! ctxt->wellFormed) return(-1);
+    return(0);
+}
+
+/**
+ * xmlParseExtParsedEnt:
+ * @ctxt:  an XML parser context
+ * 
+ * parse a genreral parsed entity
+ * An external general parsed entity is well-formed if it matches the
+ * production labeled extParsedEnt.
+ *
+ * [78] extParsedEnt ::= TextDecl? content
+ *
+ * Returns 0, -1 in case of error. the parser context is augmented
+ *                as a result of the parsing.
+ */
+
+int
+xmlParseExtParsedEnt(xmlParserCtxtPtr ctxt) {
+    xmlChar start[4];
+    xmlCharEncoding enc;
+
+    xmlDefaultSAXHandlerInit();
+
+    GROW;
+
+    /*
+     * SAX: beginning of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+        ctxt->sax->setDocumentLocator(ctxt->userData, &xmlDefaultSAXLocator);
+
+    /* 
+     * Get the 4 first bytes and decode the charset
+     * if enc != XML_CHAR_ENCODING_NONE
+     * plug some encoding conversion routines.
+     */
+    start[0] = RAW;
+    start[1] = NXT(1);
+    start[2] = NXT(2);
+    start[3] = NXT(3);
+    enc = xmlDetectCharEncoding(start, 4);
+    if (enc != XML_CHAR_ENCODING_NONE) {
+        xmlSwitchEncoding(ctxt, enc);
+    }
+
+
+    if (CUR == 0) {
+	ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Document is empty\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    /*
+     * Check for the XMLDecl in the Prolog.
+     */
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '?') &&
+        (NXT(2) == 'x') && (NXT(3) == 'm') &&
+	(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+
+	/*
+	 * Note that we will switch encoding on the fly.
+	 */
+	xmlParseXMLDecl(ctxt);
+	if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+	    /*
+	     * The XML REC instructs us to stop parsing right here
+	     */
+	    return(-1);
+	}
+	SKIP_BLANKS;
+    } else {
+	ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
+    }
+    if ((ctxt->sax) && (ctxt->sax->startDocument) && (!ctxt->disableSAX))
+        ctxt->sax->startDocument(ctxt->userData);
+
+    /*
+     * Doing validity checking on chunk doesn't make sense
+     */
+    ctxt->instate = XML_PARSER_CONTENT;
+    ctxt->validate = 0;
+    ctxt->loadsubset = 0;
+    ctxt->depth = 0;
+
+    xmlParseContent(ctxt);
+   
+    if ((RAW == '<') && (NXT(1) == '/')) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else if (RAW != 0) {
+	ctxt->errNo = XML_ERR_EXTRA_CONTENT;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"extra content at the end of well balanced chunk\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    /*
+     * SAX: end of the document processing.
+     */
+    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL) &&
+	(!ctxt->disableSAX))
+        ctxt->sax->endDocument(ctxt->userData);
+
+    if (! ctxt->wellFormed) return(-1);
+    return(0);
+}
+
+/************************************************************************
+ *									*
+ * 		Progressive parsing interfaces				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlParseLookupSequence:
+ * @ctxt:  an XML parser context
+ * @first:  the first char to lookup
+ * @next:  the next char to lookup or zero
+ * @third:  the next char to lookup or zero
+ *
+ * Try to find if a sequence (first, next, third) or  just (first next) or
+ * (first) is available in the input stream.
+ * This function has a side effect of (possibly) incrementing ctxt->checkIndex
+ * to avoid rescanning sequences of bytes, it DOES change the state of the
+ * parser, do not use liberally.
+ *
+ * Returns the index to the current parsing point if the full sequence
+ *      is available, -1 otherwise.
+ */
+int
+xmlParseLookupSequence(xmlParserCtxtPtr ctxt, xmlChar first,
+                       xmlChar next, xmlChar third) {
+    int base, len;
+    xmlParserInputPtr in;
+    const xmlChar *buf;
+
+    in = ctxt->input;
+    if (in == NULL) return(-1);
+    base = in->cur - in->base;
+    if (base < 0) return(-1);
+    if (ctxt->checkIndex > base)
+        base = ctxt->checkIndex;
+    if (in->buf == NULL) {
+	buf = in->base;
+	len = in->length;
+    } else {
+	buf = in->buf->buffer->content;
+	len = in->buf->buffer->use;
+    }
+    /* take into account the sequence length */
+    if (third) len -= 2;
+    else if (next) len --;
+    for (;base < len;base++) {
+        if (buf[base] == first) {
+	    if (third != 0) {
+		if ((buf[base + 1] != next) ||
+		    (buf[base + 2] != third)) continue;
+	    } else if (next != 0) {
+		if (buf[base + 1] != next) continue;
+	    }
+	    ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+	    if (next == 0)
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: lookup '%c' found at %d\n",
+			first, base);
+	    else if (third == 0)
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: lookup '%c%c' found at %d\n",
+			first, next, base);
+	    else 
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: lookup '%c%c%c' found at %d\n",
+			first, next, third, base);
+#endif
+	    return(base - (in->cur - in->base));
+	}
+    }
+    ctxt->checkIndex = base;
+#ifdef DEBUG_PUSH
+    if (next == 0)
+	xmlGenericError(xmlGenericErrorContext,
+		"PP: lookup '%c' failed\n", first);
+    else if (third == 0)
+	xmlGenericError(xmlGenericErrorContext,
+		"PP: lookup '%c%c' failed\n", first, next);
+    else	
+	xmlGenericError(xmlGenericErrorContext,
+		"PP: lookup '%c%c%c' failed\n", first, next, third);
+#endif
+    return(-1);
+}
+
+/**
+ * xmlParseTryOrFinish:
+ * @ctxt:  an XML parser context
+ * @terminate:  last chunk indicator
+ *
+ * Try to progress on parsing
+ *
+ * Returns zero if no parsing was possible
+ */
+int
+xmlParseTryOrFinish(xmlParserCtxtPtr ctxt, int terminate) {
+    int ret = 0;
+    int avail;
+    xmlChar cur, next;
+
+#ifdef DEBUG_PUSH
+    switch (ctxt->instate) {
+	case XML_PARSER_EOF:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try EOF\n"); break;
+	case XML_PARSER_START:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try START\n"); break;
+	case XML_PARSER_MISC:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try MISC\n");break;
+	case XML_PARSER_COMMENT:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try COMMENT\n");break;
+	case XML_PARSER_PROLOG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try PROLOG\n");break;
+	case XML_PARSER_START_TAG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try START_TAG\n");break;
+	case XML_PARSER_CONTENT:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try CONTENT\n");break;
+	case XML_PARSER_CDATA_SECTION:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try CDATA_SECTION\n");break;
+	case XML_PARSER_END_TAG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try END_TAG\n");break;
+	case XML_PARSER_ENTITY_DECL:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try ENTITY_DECL\n");break;
+	case XML_PARSER_ENTITY_VALUE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try ENTITY_VALUE\n");break;
+	case XML_PARSER_ATTRIBUTE_VALUE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try ATTRIBUTE_VALUE\n");break;
+	case XML_PARSER_DTD:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try DTD\n");break;
+	case XML_PARSER_EPILOG:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try EPILOG\n");break;
+	case XML_PARSER_PI:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PP: try PI\n");break;
+        case XML_PARSER_IGNORE:
+            xmlGenericError(xmlGenericErrorContext,
+		    "PP: try IGNORE\n");break;
+    }
+#endif
+
+    while (1) {
+	/*
+	 * Pop-up of finished entities.
+	 */
+	while ((RAW == 0) && (ctxt->inputNr > 1))
+	    xmlPopInput(ctxt);
+
+	if (ctxt->input ==NULL) break;
+	if (ctxt->input->buf == NULL)
+	    avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+	else
+	    avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base);
+        if (avail < 1)
+	    goto done;
+        switch (ctxt->instate) {
+            case XML_PARSER_EOF:
+	        /*
+		 * Document parsing is done !
+		 */
+	        goto done;
+            case XML_PARSER_START:
+	        /*
+		 * Very first chars read from the document flow.
+		 */
+		cur = ctxt->input->cur[0];
+		if (IS_BLANK(cur)) {
+		    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+			ctxt->sax->setDocumentLocator(ctxt->userData,
+						      &xmlDefaultSAXLocator);
+		    ctxt->errNo = XML_ERR_DOCUMENT_START;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+	    "Extra spaces at the beginning of the document are not allowed\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    SKIP_BLANKS;
+		    ret++;
+		    if (ctxt->input->buf == NULL)
+			avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+		    else
+			avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base);
+		}
+		if (avail < 2)
+		    goto done;
+
+		cur = ctxt->input->cur[0];
+		next = ctxt->input->cur[1];
+		if (cur == 0) {
+		    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+			ctxt->sax->setDocumentLocator(ctxt->userData,
+						      &xmlDefaultSAXLocator);
+		    ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData, "Document is empty\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering EOF\n");
+#endif
+		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL))
+			ctxt->sax->endDocument(ctxt->userData);
+		    goto done;
+		}
+	        if ((cur == '<') && (next == '?')) {
+		    /* PI or XML decl */
+		    if (avail < 5) return(ret);
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
+			return(ret);
+		    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+			ctxt->sax->setDocumentLocator(ctxt->userData,
+						      &xmlDefaultSAXLocator);
+		    if ((ctxt->input->cur[2] == 'x') &&
+			(ctxt->input->cur[3] == 'm') &&
+			(ctxt->input->cur[4] == 'l') &&
+			(IS_BLANK(ctxt->input->cur[5]))) {
+			ret += 5;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: Parsing XML Decl\n");
+#endif
+			xmlParseXMLDecl(ctxt);
+			if (ctxt->errNo == XML_ERR_UNSUPPORTED_ENCODING) {
+			    /*
+			     * The XML REC instructs us to stop parsing right
+			     * here
+			     */
+			    ctxt->instate = XML_PARSER_EOF;
+			    return(0);
+			}
+			ctxt->standalone = ctxt->input->standalone;
+			if ((ctxt->encoding == NULL) &&
+			    (ctxt->input->encoding != NULL))
+			    ctxt->encoding = xmlStrdup(ctxt->input->encoding);
+			if ((ctxt->sax) && (ctxt->sax->startDocument) &&
+			    (!ctxt->disableSAX))
+			    ctxt->sax->startDocument(ctxt->userData);
+			ctxt->instate = XML_PARSER_MISC;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: entering MISC\n");
+#endif
+		    } else {
+			ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
+			if ((ctxt->sax) && (ctxt->sax->startDocument) &&
+			    (!ctxt->disableSAX))
+			    ctxt->sax->startDocument(ctxt->userData);
+			ctxt->instate = XML_PARSER_MISC;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: entering MISC\n");
+#endif
+		    }
+		} else {
+		    if ((ctxt->sax) && (ctxt->sax->setDocumentLocator))
+			ctxt->sax->setDocumentLocator(ctxt->userData,
+						      &xmlDefaultSAXLocator);
+		    ctxt->version = xmlCharStrdup(XML_DEFAULT_VERSION);
+		    if ((ctxt->sax) && (ctxt->sax->startDocument) &&
+		        (!ctxt->disableSAX))
+			ctxt->sax->startDocument(ctxt->userData);
+		    ctxt->instate = XML_PARSER_MISC;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering MISC\n");
+#endif
+		}
+		break;
+            case XML_PARSER_MISC:
+		SKIP_BLANKS;
+		if (ctxt->input->buf == NULL)
+		    avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+		else
+		    avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base);
+		if (avail < 2)
+		    goto done;
+		cur = ctxt->input->cur[0];
+		next = ctxt->input->cur[1];
+	        if ((cur == '<') && (next == '?')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing PI\n");
+#endif
+		    xmlParsePI(ctxt);
+		} else if ((cur == '<') && (next == '!') &&
+		    (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing Comment\n");
+#endif
+		    xmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_MISC;
+		} else if ((cur == '<') && (next == '!') &&
+		    (ctxt->input->cur[2] == 'D') && (ctxt->input->cur[3] == 'O') &&
+		    (ctxt->input->cur[4] == 'C') && (ctxt->input->cur[5] == 'T') &&
+		    (ctxt->input->cur[6] == 'Y') && (ctxt->input->cur[7] == 'P') &&
+		    (ctxt->input->cur[8] == 'E')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing internal subset\n");
+#endif
+		    ctxt->inSubset = 1;
+		    xmlParseDocTypeDecl(ctxt);
+		    if (RAW == '[') {
+			ctxt->instate = XML_PARSER_DTD;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: entering DTD\n");
+#endif
+		    } else {
+			/*
+			 * Create and update the external subset.
+			 */
+			ctxt->inSubset = 2;
+			if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+			    (ctxt->sax->externalSubset != NULL))
+			    ctxt->sax->externalSubset(ctxt->userData,
+				    ctxt->intSubName, ctxt->extSubSystem,
+				    ctxt->extSubURI);
+			ctxt->inSubset = 0;
+			ctxt->instate = XML_PARSER_PROLOG;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: entering PROLOG\n");
+#endif
+		    }
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 9)) {
+		    goto done;
+		} else {
+		    ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering START_TAG\n");
+#endif
+		}
+		break;
+            case XML_PARSER_IGNORE:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == IGNORE");
+	        ctxt->instate = XML_PARSER_DTD;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering DTD\n");
+#endif
+	        break;
+            case XML_PARSER_PROLOG:
+		SKIP_BLANKS;
+		if (ctxt->input->buf == NULL)
+		    avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+		else
+		    avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base);
+		if (avail < 2) 
+		    goto done;
+		cur = ctxt->input->cur[0];
+		next = ctxt->input->cur[1];
+	        if ((cur == '<') && (next == '?')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing PI\n");
+#endif
+		    xmlParsePI(ctxt);
+		} else if ((cur == '<') && (next == '!') &&
+		    (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing Comment\n");
+#endif
+		    xmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_PROLOG;
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 4)) {
+		    goto done;
+		} else {
+		    ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering START_TAG\n");
+#endif
+		}
+		break;
+            case XML_PARSER_EPILOG:
+		SKIP_BLANKS;
+		if (ctxt->input->buf == NULL)
+		    avail = ctxt->input->length - (ctxt->input->cur - ctxt->input->base);
+		else
+		    avail = ctxt->input->buf->buffer->use - (ctxt->input->cur - ctxt->input->base);
+		if (avail < 2)
+		    goto done;
+		cur = ctxt->input->cur[0];
+		next = ctxt->input->cur[1];
+	        if ((cur == '<') && (next == '?')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing PI\n");
+#endif
+		    xmlParsePI(ctxt);
+		    ctxt->instate = XML_PARSER_EPILOG;
+		} else if ((cur == '<') && (next == '!') &&
+		    (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing Comment\n");
+#endif
+		    xmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_EPILOG;
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 4)) {
+		    goto done;
+		} else {
+		    ctxt->errNo = XML_ERR_DOCUMENT_END;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			    "Extra content at the end of the document\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering EOF\n");
+#endif
+		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL) &&
+			(!ctxt->disableSAX))
+			ctxt->sax->endDocument(ctxt->userData);
+		    goto done;
+		}
+		break;
+            case XML_PARSER_START_TAG: {
+	        xmlChar *name, *oldname;
+
+		if ((avail < 2) && (ctxt->inputNr == 1))
+		    goto done;
+		cur = ctxt->input->cur[0];
+	        if (cur != '<') {
+		    ctxt->errNo = XML_ERR_DOCUMENT_EMPTY;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+				"Start tag expect, '<' not found\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering EOF\n");
+#endif
+		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL) &&
+			(!ctxt->disableSAX))
+			ctxt->sax->endDocument(ctxt->userData);
+		    goto done;
+		}
+		if ((!terminate) &&
+		    (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+		    goto done;
+		if (ctxt->spaceNr == 0)
+		    spacePush(ctxt, -1);
+		else
+		    spacePush(ctxt, *ctxt->space);
+		name = xmlParseStartTag(ctxt);
+		if (name == NULL) {
+		    spacePop(ctxt);
+		    ctxt->instate = XML_PARSER_EOF;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering EOF\n");
+#endif
+		    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL) &&
+			(!ctxt->disableSAX))
+			ctxt->sax->endDocument(ctxt->userData);
+		    goto done;
+		}
+		namePush(ctxt, xmlStrdup(name));
+
+		/*
+		 * [ VC: Root Element Type ]
+		 * The Name in the document type declaration must match
+		 * the element type of the root element. 
+		 */
+		if (ctxt->validate && ctxt->wellFormed && ctxt->myDoc &&
+		    ctxt->node && (ctxt->node == ctxt->myDoc->children))
+		    ctxt->valid &= xmlValidateRoot(&ctxt->vctxt, ctxt->myDoc);
+
+		/*
+		 * Check for an Empty Element.
+		 */
+		if ((RAW == '/') && (NXT(1) == '>')) {
+		    SKIP(2);
+		    if ((ctxt->sax != NULL) &&
+			(ctxt->sax->endElement != NULL) && (!ctxt->disableSAX))
+			ctxt->sax->endElement(ctxt->userData, name);
+		    xmlFree(name);
+		    oldname = namePop(ctxt);
+		    spacePop(ctxt);
+		    if (oldname != NULL) {
+#ifdef DEBUG_STACK
+			xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+			xmlFree(oldname);
+		    }
+		    if (ctxt->name == NULL) {
+			ctxt->instate = XML_PARSER_EPILOG;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: entering EPILOG\n");
+#endif
+		    } else {
+			ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+			xmlGenericError(xmlGenericErrorContext,
+				"PP: entering CONTENT\n");
+#endif
+		    }
+		    break;
+		}
+		if (RAW == '>') {
+		    NEXT;
+		} else {
+		    ctxt->errNo = XML_ERR_GT_REQUIRED;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+					 "Couldn't find end of Start Tag %s\n",
+					 name);
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+
+		    /*
+		     * end of parsing of this node.
+		     */
+		    nodePop(ctxt);
+		    oldname = namePop(ctxt);
+		    spacePop(ctxt);
+		    if (oldname != NULL) {
+#ifdef DEBUG_STACK
+			xmlGenericError(xmlGenericErrorContext,"Close: popped %s\n", oldname);
+#endif
+			xmlFree(oldname);
+		    }
+		}
+		xmlFree(name);
+		ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering CONTENT\n");
+#endif
+                break;
+	    }
+            case XML_PARSER_CONTENT: {
+		const xmlChar *test;
+		int cons;
+		xmlChar tok;
+
+                /*
+		 * Handle preparsed entities and charRef
+		 */
+		if (ctxt->token != 0) {
+		    xmlChar cur[2] = { 0 , 0 } ;
+
+		    cur[0] = (xmlChar) ctxt->token;
+		    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+			(ctxt->sax->characters != NULL))
+			ctxt->sax->characters(ctxt->userData, cur, 1);
+		    ctxt->token = 0;
+		}
+		if ((avail < 2) && (ctxt->inputNr == 1))
+		    goto done;
+		cur = ctxt->input->cur[0];
+		next = ctxt->input->cur[1];
+
+		test = CUR_PTR;
+	        cons = ctxt->input->consumed;
+	        tok = ctxt->token;
+	        if ((cur == '<') && (next == '?')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '?', '>', 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing PI\n");
+#endif
+		    xmlParsePI(ctxt);
+		} else if ((cur == '<') && (next == '!') &&
+		           (ctxt->input->cur[2] == '-') && (ctxt->input->cur[3] == '-')) {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, '-', '-', '>') < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing Comment\n");
+#endif
+		    xmlParseComment(ctxt);
+		    ctxt->instate = XML_PARSER_CONTENT;
+		} else if ((cur == '<') && (ctxt->input->cur[1] == '!') &&
+		    (ctxt->input->cur[2] == '[') && (NXT(3) == 'C') &&
+		    (ctxt->input->cur[4] == 'D') && (NXT(5) == 'A') &&
+		    (ctxt->input->cur[6] == 'T') && (NXT(7) == 'A') &&
+		    (ctxt->input->cur[8] == '[')) {
+		    SKIP(9);
+		    ctxt->instate = XML_PARSER_CDATA_SECTION;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering CDATA_SECTION\n");
+#endif
+		    break;
+		} else if ((cur == '<') && (next == '!') &&
+		           (avail < 9)) {
+		    goto done;
+		} else if ((cur == '<') && (next == '/')) {
+		    ctxt->instate = XML_PARSER_END_TAG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering END_TAG\n");
+#endif
+		    break;
+		} else if (cur == '<') {
+		    ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering START_TAG\n");
+#endif
+		    break;
+		} else if (cur == '&') {
+		    if ((!terminate) &&
+		        (xmlParseLookupSequence(ctxt, ';', 0, 0) < 0))
+			goto done;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing Reference\n");
+#endif
+		    xmlParseReference(ctxt);
+		} else {
+		    /* TODO Avoid the extra copy, handle directly !!! */
+		    /*
+		     * Goal of the following test is:
+		     *  - minimize calls to the SAX 'character' callback
+		     *    when they are mergeable
+		     *  - handle an problem for isBlank when we only parse
+		     *    a sequence of blank chars and the next one is
+		     *    not available to check against '<' presence.
+		     *  - tries to homogenize the differences in SAX
+		     *    callbacks beween the push and pull versions
+		     *    of the parser.
+		     */
+		    if ((ctxt->inputNr == 1) &&
+		        (avail < XML_PARSER_BIG_BUFFER_SIZE)) {
+			if ((!terminate) &&
+			    (xmlParseLookupSequence(ctxt, '<', 0, 0) < 0))
+			    goto done;
+                    }
+		    ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: Parsing char data\n");
+#endif
+		    xmlParseCharData(ctxt, 0);
+		}
+		/*
+		 * Pop-up of finished entities.
+		 */
+		while ((RAW == 0) && (ctxt->inputNr > 1))
+		    xmlPopInput(ctxt);
+		if ((cons == ctxt->input->consumed) && (test == CUR_PTR) &&
+		    (tok == ctxt->token)) {
+		    ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+			     "detected an error in element content\n");
+		    ctxt->wellFormed = 0;
+		    ctxt->disableSAX = 1;
+		    ctxt->instate = XML_PARSER_EOF;
+		    break;
+		}
+		break;
+	    }
+            case XML_PARSER_CDATA_SECTION: {
+	        /*
+		 * The Push mode need to have the SAX callback for 
+		 * cdataBlock merge back contiguous callbacks.
+		 */
+		int base;
+
+		base = xmlParseLookupSequence(ctxt, ']', ']', '>');
+		if (base < 0) {
+		    if (avail >= XML_PARSER_BIG_BUFFER_SIZE + 2) {
+			if ((ctxt->sax != NULL) && (!ctxt->disableSAX)) {
+			    if (ctxt->sax->cdataBlock != NULL)
+				ctxt->sax->cdataBlock(ctxt->userData, ctxt->input->cur,
+					  XML_PARSER_BIG_BUFFER_SIZE);
+			}
+			SKIP(XML_PARSER_BIG_BUFFER_SIZE);
+			ctxt->checkIndex = 0;
+		    }
+		    goto done;
+		} else {
+		    if ((ctxt->sax != NULL) && (base > 0) &&
+			(!ctxt->disableSAX)) {
+			if (ctxt->sax->cdataBlock != NULL)
+			    ctxt->sax->cdataBlock(ctxt->userData,
+						  ctxt->input->cur, base);
+		    }
+		    SKIP(base + 3);
+		    ctxt->checkIndex = 0;
+		    ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering CONTENT\n");
+#endif
+		}
+		break;
+	    }
+            case XML_PARSER_END_TAG:
+		if (avail < 2)
+		    goto done;
+		if ((!terminate) &&
+		    (xmlParseLookupSequence(ctxt, '>', 0, 0) < 0))
+		    goto done;
+		xmlParseEndTag(ctxt);
+		if (ctxt->name == NULL) {
+		    ctxt->instate = XML_PARSER_EPILOG;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering EPILOG\n");
+#endif
+		} else {
+		    ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: entering CONTENT\n");
+#endif
+		}
+		break;
+            case XML_PARSER_DTD: {
+	        /*
+		 * Sorry but progressive parsing of the internal subset
+		 * is not expected to be supported. We first check that
+		 * the full content of the internal subset is available and
+		 * the parsing is launched only at that point.
+		 * Internal subset ends up with "']' S? '>'" in an unescaped
+		 * section and not in a ']]>' sequence which are conditional
+		 * sections (whoever argued to keep that crap in XML deserve
+		 * a place in hell !).
+		 */
+		int base, i;
+		xmlChar *buf;
+	        xmlChar quote = 0;
+
+		base = ctxt->input->cur - ctxt->input->base;
+		if (base < 0) return(0);
+		if (ctxt->checkIndex > base)
+		    base = ctxt->checkIndex;
+		buf = ctxt->input->buf->buffer->content;
+		for (;(unsigned int) base < ctxt->input->buf->buffer->use;
+		     base++) {
+		    if (quote != 0) {
+		        if (buf[base] == quote)
+			    quote = 0;
+			continue;    
+		    }
+		    if (buf[base] == '"') {
+		        quote = '"';
+			continue;
+		    }
+		    if (buf[base] == '\'') {
+		        quote = '\'';
+			continue;
+		    }
+		    if (buf[base] == ']') {
+		        if ((unsigned int) base +1 >=
+		            ctxt->input->buf->buffer->use)
+			    break;
+			if (buf[base + 1] == ']') {
+			    /* conditional crap, skip both ']' ! */
+			    base++;
+			    continue;
+			}
+		        for (i = 0;
+		     (unsigned int) base + i < ctxt->input->buf->buffer->use;
+		             i++) {
+			    if (buf[base + i] == '>')
+			        goto found_end_int_subset;
+			}
+		        break;
+		    }
+		}
+		/*
+		 * We didn't found the end of the Internal subset
+		 */
+		if (quote == 0) 
+		    ctxt->checkIndex = base;
+#ifdef DEBUG_PUSH
+		if (next == 0)
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PP: lookup of int subset end filed\n");
+#endif
+	        goto done;
+
+found_end_int_subset:
+		xmlParseInternalSubset(ctxt);
+		ctxt->inSubset = 2;
+		if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+		    (ctxt->sax->externalSubset != NULL))
+		    ctxt->sax->externalSubset(ctxt->userData, ctxt->intSubName,
+			    ctxt->extSubSystem, ctxt->extSubURI);
+		ctxt->inSubset = 0;
+		ctxt->instate = XML_PARSER_PROLOG;
+		ctxt->checkIndex = 0;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering PROLOG\n");
+#endif
+                break;
+	    }
+            case XML_PARSER_COMMENT:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == COMMENT\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_PI:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == PI\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering CONTENT\n");
+#endif
+		break;
+            case XML_PARSER_ENTITY_DECL:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == ENTITY_DECL\n");
+		ctxt->instate = XML_PARSER_DTD;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering DTD\n");
+#endif
+		break;
+            case XML_PARSER_ENTITY_VALUE:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == ENTITY_VALUE\n");
+		ctxt->instate = XML_PARSER_CONTENT;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering DTD\n");
+#endif
+		break;
+            case XML_PARSER_ATTRIBUTE_VALUE:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == ATTRIBUTE_VALUE\n");
+		ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering START_TAG\n");
+#endif
+		break;
+            case XML_PARSER_SYSTEM_LITERAL:
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: internal error, state == SYSTEM_LITERAL\n");
+		ctxt->instate = XML_PARSER_START_TAG;
+#ifdef DEBUG_PUSH
+		xmlGenericError(xmlGenericErrorContext,
+			"PP: entering START_TAG\n");
+#endif
+		break;
+	}
+    }
+done:    
+#ifdef DEBUG_PUSH
+    xmlGenericError(xmlGenericErrorContext, "PP: done %d\n", ret);
+#endif
+    return(ret);
+}
+
+/**
+ * xmlParseTry:
+ * @ctxt:  an XML parser context
+ *
+ * Try to progress on parsing
+ *
+ * Returns zero if no parsing was possible
+ */
+int
+xmlParseTry(xmlParserCtxtPtr ctxt) {
+    return(xmlParseTryOrFinish(ctxt, 0));
+}
+
+/**
+ * xmlParseChunk:
+ * @ctxt:  an XML parser context
+ * @chunk:  an char array
+ * @size:  the size in byte of the chunk
+ * @terminate:  last chunk indicator
+ *
+ * Parse a Chunk of memory
+ *
+ * Returns zero if no error, the xmlParserErrors otherwise.
+ */
+int
+xmlParseChunk(xmlParserCtxtPtr ctxt, const char *chunk, int size,
+              int terminate) {
+    if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
+        (ctxt->input->buf != NULL) && (ctxt->instate != XML_PARSER_EOF))  {
+	int base = ctxt->input->base - ctxt->input->buf->buffer->content;
+	int cur = ctxt->input->cur - ctxt->input->base;
+	
+	xmlParserInputBufferPush(ctxt->input->buf, size, chunk);	      
+	ctxt->input->base = ctxt->input->buf->buffer->content + base;
+	ctxt->input->cur = ctxt->input->base + cur;
+#ifdef DEBUG_PUSH
+	xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
+#endif
+
+	if ((terminate) || (ctxt->input->buf->buffer->use > 80))
+	    xmlParseTryOrFinish(ctxt, terminate);
+    } else if (ctxt->instate != XML_PARSER_EOF) {
+	if ((ctxt->input != NULL) && ctxt->input->buf != NULL) {
+	    xmlParserInputBufferPtr in = ctxt->input->buf;
+	    if ((in->encoder != NULL) && (in->buffer != NULL) &&
+		    (in->raw != NULL)) {
+		int nbchars;
+		    
+		nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
+		if (nbchars < 0) {
+		    xmlGenericError(xmlGenericErrorContext,
+				    "xmlParseChunk: encoder error\n");
+		    return(XML_ERR_INVALID_ENCODING);
+		}
+	    }
+	}
+    }
+    xmlParseTryOrFinish(ctxt, terminate);
+    if (terminate) {
+	/*
+	 * Check for termination
+	 */
+	if ((ctxt->instate != XML_PARSER_EOF) &&
+	    (ctxt->instate != XML_PARSER_EPILOG)) {
+	    ctxt->errNo = XML_ERR_DOCUMENT_END;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData,
+		    "Extra content at the end of the document\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	} 
+	if (ctxt->instate != XML_PARSER_EOF) {
+	    if ((ctxt->sax) && (ctxt->sax->endDocument != NULL) &&
+		(!ctxt->disableSAX))
+		ctxt->sax->endDocument(ctxt->userData);
+	}
+	ctxt->instate = XML_PARSER_EOF;
+    }
+    return((xmlParserErrors) ctxt->errNo);	      
+}
+
+/************************************************************************
+ *									*
+ * 		I/O front end functions to the parser			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlStopParser:
+ * @ctxt:  an XML parser context
+ *
+ * Blocks further parser processing
+ */
+void           
+xmlStopParser(xmlParserCtxtPtr ctxt) {
+    ctxt->instate = XML_PARSER_EOF;
+    if (ctxt->input != NULL)
+	ctxt->input->cur = BAD_CAST"";
+}
+
+/**
+ * xmlCreatePushParserCtxt:
+ * @sax:  a SAX handler
+ * @user_data:  The user data returned on SAX callbacks
+ * @chunk:  a pointer to an array of chars
+ * @size:  number of chars in the array
+ * @filename:  an optional file name or URI
+ *
+ * Create a parser context for using the XML parser in push mode
+ * To allow content encoding detection, @size should be >= 4
+ * The value of @filename is used for fetching external entities
+ * and error/warning reports.
+ *
+ * Returns the new parser context or NULL
+ */
+xmlParserCtxtPtr
+xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax, void *user_data, 
+                        const char *chunk, int size, const char *filename) {
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr inputStream;
+    xmlParserInputBufferPtr buf;
+    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
+
+    /*
+     * plug some encoding conversion routines
+     */
+    if ((chunk != NULL) && (size >= 4))
+	enc = xmlDetectCharEncoding((const xmlChar *) chunk, size);
+
+    buf = xmlAllocParserInputBuffer(enc);
+    if (buf == NULL) return(NULL);
+
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL) {
+	xmlFree(buf);
+	return(NULL);
+    }
+    if (sax != NULL) {
+	if (ctxt->sax != &xmlDefaultSAXHandler)
+	    xmlFree(ctxt->sax);
+	ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler));
+	if (ctxt->sax == NULL) {
+	    xmlFree(buf);
+	    xmlFree(ctxt);
+	    return(NULL);
+	}
+	memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler));
+	if (user_data != NULL)
+	    ctxt->userData = user_data;
+    }	
+    if (filename == NULL) {
+	ctxt->directory = NULL;
+    } else {
+        ctxt->directory = xmlParserGetDirectory(filename);
+    }
+
+    inputStream = xmlNewInputStream(ctxt);
+    if (inputStream == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+
+    if (filename == NULL)
+	inputStream->filename = NULL;
+    else
+	inputStream->filename = xmlMemStrdup(filename);
+    inputStream->buf = buf;
+    inputStream->base = inputStream->buf->buffer->content;
+    inputStream->cur = inputStream->buf->buffer->content;
+    if (enc != XML_CHAR_ENCODING_NONE) {
+        xmlSwitchEncoding(ctxt, enc);
+    }
+
+    inputPush(ctxt, inputStream);
+
+    if ((size > 0) && (chunk != NULL) && (ctxt->input != NULL) &&
+        (ctxt->input->buf != NULL))  {	      
+	xmlParserInputBufferPush(ctxt->input->buf, size, chunk);	      
+#ifdef DEBUG_PUSH
+	xmlGenericError(xmlGenericErrorContext, "PP: pushed %d\n", size);
+#endif
+    }
+
+    return(ctxt);
+}
+
+/**
+ * xmlCreateIOParserCtxt:
+ * @sax:  a SAX handler
+ * @user_data:  The user data returned on SAX callbacks
+ * @ioread:  an I/O read function
+ * @ioclose:  an I/O close function
+ * @ioctx:  an I/O handler
+ * @enc:  the charset encoding if known
+ *
+ * Create a parser context for using the XML parser with an existing
+ * I/O stream
+ *
+ * Returns the new parser context or NULL
+ */
+xmlParserCtxtPtr
+xmlCreateIOParserCtxt(xmlSAXHandlerPtr sax, void *user_data,
+	xmlInputReadCallback   ioread, xmlInputCloseCallback  ioclose,
+	void *ioctx, xmlCharEncoding enc) {
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr inputStream;
+    xmlParserInputBufferPtr buf;
+
+    buf = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx, enc);
+    if (buf == NULL) return(NULL);
+
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL) {
+	xmlFree(buf);
+	return(NULL);
+    }
+    if (sax != NULL) {
+	if (ctxt->sax != &xmlDefaultSAXHandler)
+	    xmlFree(ctxt->sax);
+	ctxt->sax = (xmlSAXHandlerPtr) xmlMalloc(sizeof(xmlSAXHandler));
+	if (ctxt->sax == NULL) {
+	    xmlFree(buf);
+	    xmlFree(ctxt);
+	    return(NULL);
+	}
+	memcpy(ctxt->sax, sax, sizeof(xmlSAXHandler));
+	if (user_data != NULL)
+	    ctxt->userData = user_data;
+    }	
+
+    inputStream = xmlNewIOInputStream(ctxt, buf, enc);
+    if (inputStream == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+    inputPush(ctxt, inputStream);
+
+    return(ctxt);
+}
+
+/************************************************************************
+ *									*
+ * 		Front ends when parsing a Dtd				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlIOParseDTD:
+ * @sax:  the SAX handler block or NULL
+ * @input:  an Input Buffer
+ * @enc:  the charset encoding if known
+ *
+ * Load and parse a DTD
+ * 
+ * Returns the resulting xmlDtdPtr or NULL in case of error.
+ * @input will be freed at parsing end.
+ */
+
+xmlDtdPtr
+xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input,
+	      xmlCharEncoding enc) {
+    xmlDtdPtr ret = NULL;
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr pinput = NULL;
+
+    if (input == NULL)
+	return(NULL);
+
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL) {
+	return(NULL);
+    }
+
+    /*
+     * Set-up the SAX context
+     */
+    if (sax != NULL) { 
+	if (ctxt->sax != NULL)
+	    xmlFree(ctxt->sax);
+        ctxt->sax = sax;
+        ctxt->userData = NULL;
+    }
+
+    /*
+     * generate a parser input from the I/O handler
+     */
+
+    pinput = xmlNewIOInputStream(ctxt, input, enc);
+    if (pinput == NULL) {
+        if (sax != NULL) ctxt->sax = NULL;
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+
+    /*
+     * plug some encoding conversion routines here.
+     */
+    xmlPushInput(ctxt, pinput);
+
+    pinput->filename = NULL;
+    pinput->line = 1;
+    pinput->col = 1;
+    pinput->base = ctxt->input->cur;
+    pinput->cur = ctxt->input->cur;
+    pinput->free = NULL;
+
+    /*
+     * let's parse that entity knowing it's an external subset.
+     */
+    ctxt->inSubset = 2;
+    ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
+    ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none",
+	                               BAD_CAST "none", BAD_CAST "none");
+    xmlParseExternalSubset(ctxt, BAD_CAST "none", BAD_CAST "none");
+
+    if (ctxt->myDoc != NULL) {
+	if (ctxt->wellFormed) {
+	    ret = ctxt->myDoc->extSubset;
+	    ctxt->myDoc->extSubset = NULL;
+	} else {
+	    ret = NULL;
+	}
+        xmlFreeDoc(ctxt->myDoc);
+        ctxt->myDoc = NULL;
+    }
+    if (sax != NULL) ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * xmlSAXParseDTD:
+ * @sax:  the SAX handler block
+ * @ExternalID:  a NAME* containing the External ID of the DTD
+ * @SystemID:  a NAME* containing the URL to the DTD
+ *
+ * Load and parse an external subset.
+ * 
+ * Returns the resulting xmlDtdPtr or NULL in case of error.
+ */
+
+xmlDtdPtr
+xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID,
+                          const xmlChar *SystemID) {
+    xmlDtdPtr ret = NULL;
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input = NULL;
+    xmlCharEncoding enc;
+
+    if ((ExternalID == NULL) && (SystemID == NULL)) return(NULL);
+
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL) {
+	return(NULL);
+    }
+
+    /*
+     * Set-up the SAX context
+     */
+    if (sax != NULL) { 
+	if (ctxt->sax != NULL)
+	    xmlFree(ctxt->sax);
+        ctxt->sax = sax;
+        ctxt->userData = NULL;
+    }
+
+    /*
+     * Ask the Entity resolver to load the damn thing
+     */
+
+    if ((ctxt->sax != NULL) && (ctxt->sax->resolveEntity != NULL))
+	input = ctxt->sax->resolveEntity(ctxt->userData, ExternalID, SystemID);
+    if (input == NULL) {
+        if (sax != NULL) ctxt->sax = NULL;
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+
+    /*
+     * plug some encoding conversion routines here.
+     */
+    xmlPushInput(ctxt, input);
+    enc = xmlDetectCharEncoding(ctxt->input->cur, 4);
+    xmlSwitchEncoding(ctxt, enc);
+
+    if (input->filename == NULL)
+	input->filename = (char *) xmlStrdup(SystemID);
+    input->line = 1;
+    input->col = 1;
+    input->base = ctxt->input->cur;
+    input->cur = ctxt->input->cur;
+    input->free = NULL;
+
+    /*
+     * let's parse that entity knowing it's an external subset.
+     */
+    ctxt->inSubset = 2;
+    ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
+    ctxt->myDoc->extSubset = xmlNewDtd(ctxt->myDoc, BAD_CAST "none",
+	                               ExternalID, SystemID);
+    xmlParseExternalSubset(ctxt, ExternalID, SystemID);
+
+    if (ctxt->myDoc != NULL) {
+	if (ctxt->wellFormed) {
+	    ret = ctxt->myDoc->extSubset;
+	    ctxt->myDoc->extSubset = NULL;
+	} else {
+	    ret = NULL;
+	}
+        xmlFreeDoc(ctxt->myDoc);
+        ctxt->myDoc = NULL;
+    }
+    if (sax != NULL) ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * xmlParseDTD:
+ * @ExternalID:  a NAME* containing the External ID of the DTD
+ * @SystemID:  a NAME* containing the URL to the DTD
+ *
+ * Load and parse an external subset.
+ * 
+ * Returns the resulting xmlDtdPtr or NULL in case of error.
+ */
+
+xmlDtdPtr
+xmlParseDTD(const xmlChar *ExternalID, const xmlChar *SystemID) {
+    return(xmlSAXParseDTD(NULL, ExternalID, SystemID));
+}
+
+/************************************************************************
+ *									*
+ * 		Front ends when parsing an Entity			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSAXParseBalancedChunk:
+ * @ctx:  an XML parser context (possibly NULL)
+ * @sax:  the SAX handler bloc (possibly NULL)
+ * @user_data:  The user data returned on SAX callbacks (possibly NULL)
+ * @input:  a parser input stream
+ * @enc:  the encoding
+ *
+ * Parse a well-balanced chunk of an XML document
+ * The user has to provide SAX callback block whose routines will be
+ * called by the parser
+ * The allowed sequence for the Well Balanced Chunk is the one defined by
+ * the content production in the XML grammar:
+ *
+ * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ *
+ * Returns 0 if the chunk is well balanced, -1 in case of args problem and
+ *    the error code otherwise
+ */
+
+int
+xmlSAXParseBalancedChunk(xmlParserCtxtPtr ctx, xmlSAXHandlerPtr sax,
+                         void *user_data, xmlParserInputPtr input,
+			 xmlCharEncoding enc) {
+    xmlParserCtxtPtr ctxt;
+    int ret;
+
+    if (input == NULL) return(-1);
+
+    if (ctx != NULL)
+        ctxt = ctx;
+    else {	
+	ctxt = xmlNewParserCtxt();
+	if (ctxt == NULL)
+	    return(-1);
+        if (sax == NULL)
+	    ctxt->myDoc = xmlNewDoc(BAD_CAST "1.0");
+    }	
+
+    /*
+     * Set-up the SAX context
+     */
+    if (sax != NULL) {
+	if (ctxt->sax != NULL)
+	    xmlFree(ctxt->sax);
+	ctxt->sax = sax;
+	ctxt->userData = user_data;
+    }
+
+    /*
+     * plug some encoding conversion routines here.
+     */
+    xmlPushInput(ctxt, input);
+    if (enc != XML_CHAR_ENCODING_NONE)
+	xmlSwitchEncoding(ctxt, enc);
+
+    /*
+     * let's parse that entity knowing it's an external subset.
+     */
+    xmlParseContent(ctxt);
+    ret = ctxt->errNo;
+
+    if (ctx == NULL) {
+	if (sax != NULL) 
+	    ctxt->sax = NULL;
+	else
+	    xmlFreeDoc(ctxt->myDoc);
+	xmlFreeParserCtxt(ctxt);
+    }
+    return(ret);
+}
+
+/**
+ * xmlParseCtxtExternalEntity:
+ * @ctx:  the existing parsing context
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @list:  the return value for the set of parsed nodes
+ *
+ * Parse an external general entity within an existing parsing context
+ * An external general parsed entity is well-formed if it matches the
+ * production labeled extParsedEnt.
+ *
+ * [78] extParsedEnt ::= TextDecl? content
+ *
+ * Returns 0 if the entity is well formed, -1 in case of args problem and
+ *    the parser error code otherwise
+ */
+
+int
+xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx, const xmlChar *URL,
+	               const xmlChar *ID, xmlNodePtr *list) {
+    xmlParserCtxtPtr ctxt;
+    xmlDocPtr newDoc;
+    xmlSAXHandlerPtr oldsax = NULL;
+    int ret = 0;
+
+    if (ctx->depth > 40) {
+	return(XML_ERR_ENTITY_LOOP);
+    }
+
+    if (list != NULL)
+        *list = NULL;
+    if ((URL == NULL) && (ID == NULL))
+	return(-1);
+    if (ctx->myDoc == NULL) /* @@ relax but check for dereferences */
+	return(-1);
+
+
+    ctxt = xmlCreateEntityParserCtxt(URL, ID, NULL);
+    if (ctxt == NULL) return(-1);
+    ctxt->userData = ctxt;
+    oldsax = ctxt->sax;
+    ctxt->sax = ctx->sax;
+    newDoc = xmlNewDoc(BAD_CAST "1.0");
+    if (newDoc == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(-1);
+    }
+    if (ctx->myDoc != NULL) {
+	newDoc->intSubset = ctx->myDoc->intSubset;
+	newDoc->extSubset = ctx->myDoc->extSubset;
+    }
+    if (ctx->myDoc->URL != NULL) {
+	newDoc->URL = xmlStrdup(ctx->myDoc->URL);
+    }
+    newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
+    if (newDoc->children == NULL) {
+	ctxt->sax = oldsax;
+	xmlFreeParserCtxt(ctxt);
+	newDoc->intSubset = NULL;
+	newDoc->extSubset = NULL;
+        xmlFreeDoc(newDoc);
+	return(-1);
+    }
+    nodePush(ctxt, newDoc->children);
+    if (ctx->myDoc == NULL) {
+	ctxt->myDoc = newDoc;
+    } else {
+	ctxt->myDoc = ctx->myDoc;
+	newDoc->children->doc = ctx->myDoc;
+    }
+
+    /*
+     * Parse a possible text declaration first
+     */
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '?') &&
+	(NXT(2) == 'x') && (NXT(3) == 'm') &&
+	(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+	xmlParseTextDecl(ctxt);
+    }
+
+    /*
+     * Doing validity checking on chunk doesn't make sense
+     */
+    ctxt->instate = XML_PARSER_CONTENT;
+    ctxt->validate = ctx->validate;
+    ctxt->loadsubset = ctx->loadsubset;
+    ctxt->depth = ctx->depth + 1;
+    ctxt->replaceEntities = ctx->replaceEntities;
+    if (ctxt->validate) {
+	ctxt->vctxt.error = ctx->vctxt.error;
+	ctxt->vctxt.warning = ctx->vctxt.warning;
+	/* Allocate the Node stack */
+	ctxt->vctxt.nodeTab = (xmlNodePtr *) xmlMalloc(4 * sizeof(xmlNodePtr));
+	if (ctxt->vctxt.nodeTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlParseCtxtExternalEntity: out of memory\n");
+	    ctxt->validate = 0;
+	    ctxt->vctxt.error = NULL;
+	    ctxt->vctxt.warning = NULL;
+	} else {
+	    ctxt->vctxt.nodeNr = 0;
+	    ctxt->vctxt.nodeMax = 4;
+	    ctxt->vctxt.node = NULL;
+	}
+    } else {
+	ctxt->vctxt.error = NULL;
+	ctxt->vctxt.warning = NULL;
+    }
+
+    xmlParseContent(ctxt);
+   
+    if ((RAW == '<') && (NXT(1) == '/')) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else if (RAW != 0) {
+	ctxt->errNo = XML_ERR_EXTRA_CONTENT;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"extra content at the end of well balanced chunk\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    if (ctxt->node != newDoc->children) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    if (!ctxt->wellFormed) {
+        if (ctxt->errNo == 0)
+	    ret = 1;
+	else
+	    ret = ctxt->errNo;
+    } else {
+	if (list != NULL) {
+	    xmlNodePtr cur;
+
+	    /*
+	     * Return the newly created nodeset after unlinking it from
+	     * they pseudo parent.
+	     */
+	    cur = newDoc->children->children;
+	    *list = cur;
+	    while (cur != NULL) {
+		cur->parent = NULL;
+		cur = cur->next;
+	    }
+            newDoc->children->children = NULL;
+	}
+	ret = 0;
+    }
+    ctxt->sax = oldsax;
+    xmlFreeParserCtxt(ctxt);
+    newDoc->intSubset = NULL;
+    newDoc->extSubset = NULL;
+    xmlFreeDoc(newDoc);
+    
+    return(ret);
+}
+
+/**
+ * xmlParseExternalEntity:
+ * @doc:  the document the chunk pertains to
+ * @sax:  the SAX handler bloc (possibly NULL)
+ * @user_data:  The user data returned on SAX callbacks (possibly NULL)
+ * @depth:  Used for loop detection, use 0
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @list:  the return value for the set of parsed nodes
+ *
+ * Parse an external general entity
+ * An external general parsed entity is well-formed if it matches the
+ * production labeled extParsedEnt.
+ *
+ * [78] extParsedEnt ::= TextDecl? content
+ *
+ * Returns 0 if the entity is well formed, -1 in case of args problem and
+ *    the parser error code otherwise
+ */
+
+int
+xmlParseExternalEntity(xmlDocPtr doc, xmlSAXHandlerPtr sax, void *user_data,
+	  int depth, const xmlChar *URL, const xmlChar *ID, xmlNodePtr *list) {
+    xmlParserCtxtPtr ctxt;
+    xmlDocPtr newDoc;
+    xmlSAXHandlerPtr oldsax = NULL;
+    int ret = 0;
+
+    if (depth > 40) {
+	return(XML_ERR_ENTITY_LOOP);
+    }
+
+
+
+    if (list != NULL)
+        *list = NULL;
+    if ((URL == NULL) && (ID == NULL))
+	return(-1);
+    if (doc == NULL) /* @@ relax but check for dereferences */
+	return(-1);
+
+
+    ctxt = xmlCreateEntityParserCtxt(URL, ID, NULL);
+    if (ctxt == NULL) return(-1);
+    ctxt->userData = ctxt;
+    if (sax != NULL) {
+	oldsax = ctxt->sax;
+        ctxt->sax = sax;
+	if (user_data != NULL)
+	    ctxt->userData = user_data;
+    }
+    newDoc = xmlNewDoc(BAD_CAST "1.0");
+    if (newDoc == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(-1);
+    }
+    if (doc != NULL) {
+	newDoc->intSubset = doc->intSubset;
+	newDoc->extSubset = doc->extSubset;
+    }
+    if (doc->URL != NULL) {
+	newDoc->URL = xmlStrdup(doc->URL);
+    }
+    newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
+    if (newDoc->children == NULL) {
+	if (sax != NULL)
+	    ctxt->sax = oldsax;
+	xmlFreeParserCtxt(ctxt);
+	newDoc->intSubset = NULL;
+	newDoc->extSubset = NULL;
+        xmlFreeDoc(newDoc);
+	return(-1);
+    }
+    nodePush(ctxt, newDoc->children);
+    if (doc == NULL) {
+	ctxt->myDoc = newDoc;
+    } else {
+	ctxt->myDoc = doc;
+	newDoc->children->doc = doc;
+    }
+
+    /*
+     * Parse a possible text declaration first
+     */
+    GROW;
+    if ((RAW == '<') && (NXT(1) == '?') &&
+	(NXT(2) == 'x') && (NXT(3) == 'm') &&
+	(NXT(4) == 'l') && (IS_BLANK(NXT(5)))) {
+	xmlParseTextDecl(ctxt);
+    }
+
+    /*
+     * Doing validity checking on chunk doesn't make sense
+     */
+    ctxt->instate = XML_PARSER_CONTENT;
+    ctxt->validate = 0;
+    ctxt->loadsubset = 0;
+    ctxt->depth = depth;
+
+    xmlParseContent(ctxt);
+   
+    if ((RAW == '<') && (NXT(1) == '/')) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else if (RAW != 0) {
+	ctxt->errNo = XML_ERR_EXTRA_CONTENT;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"extra content at the end of well balanced chunk\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    if (ctxt->node != newDoc->children) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    if (!ctxt->wellFormed) {
+        if (ctxt->errNo == 0)
+	    ret = 1;
+	else
+	    ret = ctxt->errNo;
+    } else {
+	if (list != NULL) {
+	    xmlNodePtr cur;
+
+	    /*
+	     * Return the newly created nodeset after unlinking it from
+	     * they pseudo parent.
+	     */
+	    cur = newDoc->children->children;
+	    *list = cur;
+	    while (cur != NULL) {
+		cur->parent = NULL;
+		cur = cur->next;
+	    }
+            newDoc->children->children = NULL;
+	}
+	ret = 0;
+    }
+    if (sax != NULL) 
+	ctxt->sax = oldsax;
+    xmlFreeParserCtxt(ctxt);
+    newDoc->intSubset = NULL;
+    newDoc->extSubset = NULL;
+    xmlFreeDoc(newDoc);
+    
+    return(ret);
+}
+
+/**
+ * xmlParseBalancedChunk:
+ * @doc:  the document the chunk pertains to
+ * @sax:  the SAX handler bloc (possibly NULL)
+ * @user_data:  The user data returned on SAX callbacks (possibly NULL)
+ * @depth:  Used for loop detection, use 0
+ * @string:  the input string in UTF8 or ISO-Latin (zero terminated)
+ * @list:  the return value for the set of parsed nodes
+ *
+ * Parse a well-balanced chunk of an XML document
+ * called by the parser
+ * The allowed sequence for the Well Balanced Chunk is the one defined by
+ * the content production in the XML grammar:
+ *
+ * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ *
+ * Returns 0 if the chunk is well balanced, -1 in case of args problem and
+ *    the parser error code otherwise
+ */
+
+int
+xmlParseBalancedChunkMemory(xmlDocPtr doc, xmlSAXHandlerPtr sax,
+     void *user_data, int depth, const xmlChar *string, xmlNodePtr *list) {
+    xmlParserCtxtPtr ctxt;
+    xmlDocPtr newDoc;
+    xmlSAXHandlerPtr oldsax = NULL;
+    int size;
+    int ret = 0;
+
+    if (depth > 40) {
+	return(XML_ERR_ENTITY_LOOP);
+    }
+
+
+    if (list != NULL)
+        *list = NULL;
+    if (string == NULL)
+        return(-1);
+
+    size = xmlStrlen(string);
+
+    ctxt = xmlCreateMemoryParserCtxt((char *) string, size);
+    if (ctxt == NULL) return(-1);
+    ctxt->userData = ctxt;
+    if (sax != NULL) {
+	oldsax = ctxt->sax;
+        ctxt->sax = sax;
+	if (user_data != NULL)
+	    ctxt->userData = user_data;
+    }
+    newDoc = xmlNewDoc(BAD_CAST "1.0");
+    if (newDoc == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(-1);
+    }
+    if (doc != NULL) {
+	newDoc->intSubset = doc->intSubset;
+	newDoc->extSubset = doc->extSubset;
+    }
+    newDoc->children = xmlNewDocNode(newDoc, NULL, BAD_CAST "pseudoroot", NULL);
+    if (newDoc->children == NULL) {
+	if (sax != NULL)
+	    ctxt->sax = oldsax;
+	xmlFreeParserCtxt(ctxt);
+	newDoc->intSubset = NULL;
+	newDoc->extSubset = NULL;
+        xmlFreeDoc(newDoc);
+	return(-1);
+    }
+    nodePush(ctxt, newDoc->children);
+    if (doc == NULL) {
+	ctxt->myDoc = newDoc;
+    } else {
+	ctxt->myDoc = doc;
+	newDoc->children->doc = doc;
+    }
+    ctxt->instate = XML_PARSER_CONTENT;
+    ctxt->depth = depth;
+
+    /*
+     * Doing validity checking on chunk doesn't make sense
+     */
+    ctxt->validate = 0;
+    ctxt->loadsubset = 0;
+
+    xmlParseContent(ctxt);
+   
+    if ((RAW == '<') && (NXT(1) == '/')) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    } else if (RAW != 0) {
+	ctxt->errNo = XML_ERR_EXTRA_CONTENT;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"extra content at the end of well balanced chunk\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+    if (ctxt->node != newDoc->children) {
+	ctxt->errNo = XML_ERR_NOT_WELL_BALANCED;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"chunk is not well balanced\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    if (!ctxt->wellFormed) {
+        if (ctxt->errNo == 0)
+	    ret = 1;
+	else
+	    ret = ctxt->errNo;
+    } else {
+	if (list != NULL) {
+	    xmlNodePtr cur;
+
+	    /*
+	     * Return the newly created nodeset after unlinking it from
+	     * they pseudo parent.
+	     */
+	    cur = newDoc->children->children;
+	    *list = cur;
+	    while (cur != NULL) {
+		cur->parent = NULL;
+		cur = cur->next;
+	    }
+            newDoc->children->children = NULL;
+	}
+	ret = 0;
+    }
+    if (sax != NULL) 
+	ctxt->sax = oldsax;
+    xmlFreeParserCtxt(ctxt);
+    newDoc->intSubset = NULL;
+    newDoc->extSubset = NULL;
+    xmlFreeDoc(newDoc);
+    
+    return(ret);
+}
+
+/**
+ * xmlSAXParseEntity:
+ * @sax:  the SAX handler block
+ * @filename:  the filename
+ *
+ * parse an XML external entity out of context and build a tree.
+ * It use the given SAX function block to handle the parsing callback.
+ * If sax is NULL, fallback to the default DOM tree building routines.
+ *
+ * [78] extParsedEnt ::= TextDecl? content
+ *
+ * This correspond to a "Well Balanced" chunk
+ *
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlSAXParseEntity(xmlSAXHandlerPtr sax, const char *filename) {
+    xmlDocPtr ret;
+    xmlParserCtxtPtr ctxt;
+    char *directory = NULL;
+
+    ctxt = xmlCreateFileParserCtxt(filename);
+    if (ctxt == NULL) {
+	return(NULL);
+    }
+    if (sax != NULL) {
+	if (ctxt->sax != NULL)
+	    xmlFree(ctxt->sax);
+        ctxt->sax = sax;
+        ctxt->userData = NULL;
+    }
+
+    if ((ctxt->directory == NULL) && (directory == NULL))
+        directory = xmlParserGetDirectory(filename);
+
+    xmlParseExtParsedEnt(ctxt);
+
+    if (ctxt->wellFormed)
+	ret = ctxt->myDoc;
+    else {
+        ret = NULL;
+        xmlFreeDoc(ctxt->myDoc);
+        ctxt->myDoc = NULL;
+    }
+    if (sax != NULL)
+        ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * xmlParseEntity:
+ * @filename:  the filename
+ *
+ * parse an XML external entity out of context and build a tree.
+ *
+ * [78] extParsedEnt ::= TextDecl? content
+ *
+ * This correspond to a "Well Balanced" chunk
+ *
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlParseEntity(const char *filename) {
+    return(xmlSAXParseEntity(NULL, filename));
+}
+
+/**
+ * xmlCreateEntityParserCtxt:
+ * @URL:  the entity URL
+ * @ID:  the entity PUBLIC ID
+ * @base:  a posible base for the target URI
+ *
+ * Create a parser context for an external entity
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ *
+ * Returns the new parser context or NULL
+ */
+xmlParserCtxtPtr
+xmlCreateEntityParserCtxt(const xmlChar *URL, const xmlChar *ID,
+	                  const xmlChar *base) {
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr inputStream;
+    char *directory = NULL;
+    xmlChar *uri;
+    
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL) {
+	return(NULL);
+    }
+
+    uri = xmlBuildURI(URL, base);
+
+    if (uri == NULL) {
+	inputStream = xmlLoadExternalEntity((char *)URL, (char *)ID, ctxt);
+	if (inputStream == NULL) {
+	    xmlFreeParserCtxt(ctxt);
+	    return(NULL);
+	}
+
+	inputPush(ctxt, inputStream);
+
+	if ((ctxt->directory == NULL) && (directory == NULL))
+	    directory = xmlParserGetDirectory((char *)URL);
+	if ((ctxt->directory == NULL) && (directory != NULL))
+	    ctxt->directory = directory;
+    } else {
+	inputStream = xmlLoadExternalEntity((char *)uri, (char *)ID, ctxt);
+	if (inputStream == NULL) {
+	    xmlFree(uri);
+	    xmlFreeParserCtxt(ctxt);
+	    return(NULL);
+	}
+
+	inputPush(ctxt, inputStream);
+
+	if ((ctxt->directory == NULL) && (directory == NULL))
+	    directory = xmlParserGetDirectory((char *)uri);
+	if ((ctxt->directory == NULL) && (directory != NULL))
+	    ctxt->directory = directory;
+	xmlFree(uri);
+    }
+
+    return(ctxt);
+}
+
+/************************************************************************
+ *									*
+ * 		Front ends when parsing from a file			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlCreateFileParserCtxt:
+ * @filename:  the filename
+ *
+ * Create a parser context for a file content. 
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ *
+ * Returns the new parser context or NULL
+ */
+xmlParserCtxtPtr
+xmlCreateFileParserCtxt(const char *filename)
+{
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr inputStream;
+    xmlParserInputBufferPtr buf;
+    char *directory = NULL;
+
+    buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) {
+	return(NULL);
+    }
+
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL) {
+	if (xmlDefaultSAXHandler.error != NULL) {
+	    xmlDefaultSAXHandler.error(NULL, "out of memory\n");
+	}
+	return(NULL);
+    }
+
+    inputStream = xmlNewInputStream(ctxt);
+    if (inputStream == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+
+    inputStream->filename = xmlMemStrdup(filename);
+    inputStream->buf = buf;
+    inputStream->base = inputStream->buf->buffer->content;
+    inputStream->cur = inputStream->buf->buffer->content;
+
+    inputPush(ctxt, inputStream);
+    if ((ctxt->directory == NULL) && (directory == NULL))
+        directory = xmlParserGetDirectory(filename);
+    if ((ctxt->directory == NULL) && (directory != NULL))
+        ctxt->directory = directory;
+
+    return(ctxt);
+}
+
+/**
+ * xmlSAXParseFile:
+ * @sax:  the SAX handler block
+ * @filename:  the filename
+ * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
+ *             documents
+ *
+ * parse an XML file and build a tree. Automatic support for ZLIB/Compress
+ * compressed document is provided by default if found at compile-time.
+ * It use the given SAX function block to handle the parsing callback.
+ * If sax is NULL, fallback to the default DOM tree building routines.
+ *
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlSAXParseFile(xmlSAXHandlerPtr sax, const char *filename,
+                          int recovery) {
+    xmlDocPtr ret;
+    xmlParserCtxtPtr ctxt;
+    char *directory = NULL;
+
+    ctxt = xmlCreateFileParserCtxt(filename);
+    if (ctxt == NULL) {
+	return(NULL);
+    }
+    if (sax != NULL) {
+	if (ctxt->sax != NULL)
+	    xmlFree(ctxt->sax);
+        ctxt->sax = sax;
+        ctxt->userData = NULL;
+    }
+
+    if ((ctxt->directory == NULL) && (directory == NULL))
+        directory = xmlParserGetDirectory(filename);
+    if ((ctxt->directory == NULL) && (directory != NULL))
+        ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
+
+    xmlParseDocument(ctxt);
+
+    if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
+    else {
+       ret = NULL;
+       xmlFreeDoc(ctxt->myDoc);
+       ctxt->myDoc = NULL;
+    }
+    if (sax != NULL)
+        ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * xmlRecoverDoc:
+ * @cur:  a pointer to an array of xmlChar
+ *
+ * parse an XML in-memory document and build a tree.
+ * In the case the document is not Well Formed, a tree is built anyway
+ * 
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlRecoverDoc(xmlChar *cur) {
+    return(xmlSAXParseDoc(NULL, cur, 1));
+}
+
+/**
+ * xmlParseFile:
+ * @filename:  the filename
+ *
+ * parse an XML file and build a tree. Automatic support for ZLIB/Compress
+ * compressed document is provided by default if found at compile-time.
+ *
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlParseFile(const char *filename) {
+    return(xmlSAXParseFile(NULL, filename, 0));
+}
+
+/**
+ * xmlRecoverFile:
+ * @filename:  the filename
+ *
+ * parse an XML file and build a tree. Automatic support for ZLIB/Compress
+ * compressed document is provided by default if found at compile-time.
+ * In the case the document is not Well Formed, a tree is built anyway
+ *
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlRecoverFile(const char *filename) {
+    return(xmlSAXParseFile(NULL, filename, 1));
+}
+
+
+/**
+ * xmlSetupParserForBuffer:
+ * @ctxt:  an XML parser context
+ * @buffer:  a xmlChar * buffer
+ * @filename:  a file name
+ *
+ * Setup the parser context to parse a new buffer; Clears any prior
+ * contents from the parser context. The buffer parameter must not be
+ * NULL, but the filename parameter can be
+ */
+void
+xmlSetupParserForBuffer(xmlParserCtxtPtr ctxt, const xmlChar* buffer,
+                             const char* filename)
+{
+    xmlParserInputPtr input;
+
+    input = xmlNewInputStream(ctxt);
+    if (input == NULL) {
+        perror("malloc");
+        xmlFree(ctxt);
+        return;
+    }
+  
+    xmlClearParserCtxt(ctxt);
+    if (filename != NULL)
+        input->filename = xmlMemStrdup(filename);
+    input->base = buffer;
+    input->cur = buffer;
+    inputPush(ctxt, input);
+}
+
+/**
+ * xmlSAXUserParseFile:
+ * @sax:  a SAX handler
+ * @user_data:  The user data returned on SAX callbacks
+ * @filename:  a file name
+ *
+ * parse an XML file and call the given SAX handler routines.
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * 
+ * Returns 0 in case of success or a error number otherwise
+ */
+int
+xmlSAXUserParseFile(xmlSAXHandlerPtr sax, void *user_data,
+                    const char *filename) {
+    int ret = 0;
+    xmlParserCtxtPtr ctxt;
+    
+    ctxt = xmlCreateFileParserCtxt(filename);
+    if (ctxt == NULL) return -1;
+    if (ctxt->sax != &xmlDefaultSAXHandler)
+	xmlFree(ctxt->sax);
+    ctxt->sax = sax;
+    if (user_data != NULL)
+	ctxt->userData = user_data;
+    
+    xmlParseDocument(ctxt);
+    
+    if (ctxt->wellFormed)
+	ret = 0;
+    else {
+        if (ctxt->errNo != 0)
+	    ret = ctxt->errNo;
+	else
+	    ret = -1;
+    }
+    if (sax != NULL)
+	ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return ret;
+}
+
+/************************************************************************
+ *									*
+ * 		Front ends when parsing from memory			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlCreateMemoryParserCtxt:
+ * @buffer:  a pointer to a char array
+ * @size:  the size of the array
+ *
+ * Create a parser context for an XML in-memory document.
+ *
+ * Returns the new parser context or NULL
+ */
+xmlParserCtxtPtr
+xmlCreateMemoryParserCtxt(char *buffer, int size) {
+    xmlParserCtxtPtr ctxt;
+    xmlParserInputPtr input;
+    xmlParserInputBufferPtr buf;
+
+    if (buffer == NULL)
+	return(NULL);
+    if (size <= 0)
+	return(NULL);
+
+    ctxt = xmlNewParserCtxt();
+    if (ctxt == NULL)
+	return(NULL);
+
+    buf = xmlParserInputBufferCreateMem(buffer, size, XML_CHAR_ENCODING_NONE);
+    if (buf == NULL) return(NULL);
+
+    input = xmlNewInputStream(ctxt);
+    if (input == NULL) {
+	xmlFreeParserCtxt(ctxt);
+	return(NULL);
+    }
+
+    input->filename = NULL;
+    input->buf = buf;
+    input->base = input->buf->buffer->content;
+    input->cur = input->buf->buffer->content;
+
+    inputPush(ctxt, input);
+    return(ctxt);
+}
+
+/**
+ * xmlSAXParseMemory:
+ * @sax:  the SAX handler block
+ * @buffer:  an pointer to a char array
+ * @size:  the size of the array
+ * @recovery:  work in recovery mode, i.e. tries to read not Well Formed
+ *             documents
+ *
+ * parse an XML in-memory block and use the given SAX function block
+ * to handle the parsing callback. If sax is NULL, fallback to the default
+ * DOM tree building routines.
+ * 
+ * Returns the resulting document tree
+ */
+xmlDocPtr
+xmlSAXParseMemory(xmlSAXHandlerPtr sax, char *buffer, int size, int recovery) {
+    xmlDocPtr ret;
+    xmlParserCtxtPtr ctxt;
+
+    ctxt = xmlCreateMemoryParserCtxt(buffer, size);
+    if (ctxt == NULL) return(NULL);
+    if (sax != NULL) {
+        ctxt->sax = sax;
+        ctxt->userData = NULL;
+    }
+
+    xmlParseDocument(ctxt);
+
+    if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
+    else {
+       ret = NULL;
+       xmlFreeDoc(ctxt->myDoc);
+       ctxt->myDoc = NULL;
+    }
+    if (sax != NULL) 
+	ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * xmlParseMemory:
+ * @buffer:  an pointer to a char array
+ * @size:  the size of the array
+ *
+ * parse an XML in-memory block and build a tree.
+ * 
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr xmlParseMemory(char *buffer, int size) {
+   return(xmlSAXParseMemory(NULL, buffer, size, 0));
+}
+
+/**
+ * xmlRecoverMemory:
+ * @buffer:  an pointer to a char array
+ * @size:  the size of the array
+ *
+ * parse an XML in-memory block and build a tree.
+ * In the case the document is not Well Formed, a tree is built anyway
+ * 
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr xmlRecoverMemory(char *buffer, int size) {
+   return(xmlSAXParseMemory(NULL, buffer, size, 1));
+}
+
+/**
+ * xmlSAXUserParseMemory:
+ * @sax:  a SAX handler
+ * @user_data:  The user data returned on SAX callbacks
+ * @buffer:  an in-memory XML document input
+ * @size:  the length of the XML document in bytes
+ *
+ * A better SAX parsing routine.
+ * parse an XML in-memory buffer and call the given SAX handler routines.
+ * 
+ * Returns 0 in case of success or a error number otherwise
+ */
+int xmlSAXUserParseMemory(xmlSAXHandlerPtr sax, void *user_data,
+			  char *buffer, int size) {
+    int ret = 0;
+    xmlParserCtxtPtr ctxt;
+    xmlSAXHandlerPtr oldsax = NULL;
+    
+    ctxt = xmlCreateMemoryParserCtxt(buffer, size);
+    if (ctxt == NULL) return -1;
+    if (sax != NULL) {
+	oldsax = ctxt->sax;
+	ctxt->sax = sax;
+    }
+    ctxt->userData = user_data;
+    
+    xmlParseDocument(ctxt);
+    
+    if (ctxt->wellFormed)
+	ret = 0;
+    else {
+        if (ctxt->errNo != 0)
+	    ret = ctxt->errNo;
+	else
+	    ret = -1;
+    }
+    if (sax != NULL) {
+	ctxt->sax = oldsax;
+    }
+    xmlFreeParserCtxt(ctxt);
+    
+    return ret;
+}
+
+/**
+ * xmlCreateDocParserCtxt:
+ * @cur:  a pointer to an array of xmlChar
+ *
+ * Creates a parser context for an XML in-memory document.
+ *
+ * Returns the new parser context or NULL
+ */
+xmlParserCtxtPtr
+xmlCreateDocParserCtxt(xmlChar *cur) {
+    int len;
+
+    if (cur == NULL)
+	return(NULL);
+    len = xmlStrlen(cur);
+    return(xmlCreateMemoryParserCtxt((char *)cur, len));
+}
+
+/**
+ * xmlSAXParseDoc:
+ * @sax:  the SAX handler block
+ * @cur:  a pointer to an array of xmlChar
+ * @recovery:  work in recovery mode, i.e. tries to read no Well Formed
+ *             documents
+ *
+ * parse an XML in-memory document and build a tree.
+ * It use the given SAX function block to handle the parsing callback.
+ * If sax is NULL, fallback to the default DOM tree building routines.
+ * 
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlSAXParseDoc(xmlSAXHandlerPtr sax, xmlChar *cur, int recovery) {
+    xmlDocPtr ret;
+    xmlParserCtxtPtr ctxt;
+
+    if (cur == NULL) return(NULL);
+
+
+    ctxt = xmlCreateDocParserCtxt(cur);
+    if (ctxt == NULL) return(NULL);
+    if (sax != NULL) { 
+        ctxt->sax = sax;
+        ctxt->userData = NULL;
+    }
+
+    xmlParseDocument(ctxt);
+    if ((ctxt->wellFormed) || recovery) ret = ctxt->myDoc;
+    else {
+       ret = NULL;
+       xmlFreeDoc(ctxt->myDoc);
+       ctxt->myDoc = NULL;
+    }
+    if (sax != NULL) 
+	ctxt->sax = NULL;
+    xmlFreeParserCtxt(ctxt);
+    
+    return(ret);
+}
+
+/**
+ * xmlParseDoc:
+ * @cur:  a pointer to an array of xmlChar
+ *
+ * parse an XML in-memory document and build a tree.
+ * 
+ * Returns the resulting document tree
+ */
+
+xmlDocPtr
+xmlParseDoc(xmlChar *cur) {
+    return(xmlSAXParseDoc(NULL, cur, 0));
+}
+
+
+/************************************************************************
+ *									*
+ * 				Miscellaneous				*
+ *									*
+ ************************************************************************/
+
+#ifdef LIBXML_XPATH_ENABLED
+#include <libxml/xpath.h>
+#endif
+
+static int xmlParserInitialized = 0;
+
+/**
+ * xmlInitParser:
+ *
+ * Initialization function for the XML parser.
+ * This is not reentrant. Call once before processing in case of
+ * use in multithreaded programs.
+ */
+
+void
+xmlInitParser(void) {
+    if (xmlParserInitialized) return;
+
+    xmlInitCharEncodingHandlers();
+    xmlInitializePredefinedEntities();
+    xmlDefaultSAXHandlerInit();
+    xmlRegisterDefaultInputCallbacks();
+    xmlRegisterDefaultOutputCallbacks();
+#ifdef LIBXML_HTML_ENABLED
+    htmlInitAutoClose();
+    htmlDefaultSAXHandlerInit();
+#endif
+#ifdef LIBXML_XPATH_ENABLED
+    xmlXPathInit();
+#endif
+    xmlParserInitialized = 1;
+}
+
+/**
+ * xmlCleanupParser:
+ *
+ * Cleanup function for the XML parser. It tries to reclaim all
+ * parsing related global memory allocated for the parser processing.
+ * It doesn't deallocate any document related memory. Calling this
+ * function should not prevent reusing the parser.
+ */
+
+void
+xmlCleanupParser(void) {
+    xmlParserInitialized = 0;
+    xmlCleanupCharEncodingHandlers();
+    xmlCleanupPredefinedEntities();
+}
+
+/**
+ * xmlPedanticParserDefault:
+ * @val:  int 0 or 1 
+ *
+ * Set and return the previous value for enabling pedantic warnings.
+ *
+ * Returns the last value for 0 for no substitution, 1 for substitution.
+ */
+
+int
+xmlPedanticParserDefault(int val) {
+    int old = xmlPedanticParserDefaultValue;
+
+    xmlPedanticParserDefaultValue = val;
+    return(old);
+}
+
+/**
+ * xmlSubstituteEntitiesDefault:
+ * @val:  int 0 or 1 
+ *
+ * Set and return the previous value for default entity support.
+ * Initially the parser always keep entity references instead of substituting
+ * entity values in the output. This function has to be used to change the
+ * default parser behaviour
+ * SAX::subtituteEntities() has to be used for changing that on a file by
+ * file basis.
+ *
+ * Returns the last value for 0 for no substitution, 1 for substitution.
+ */
+
+int
+xmlSubstituteEntitiesDefault(int val) {
+    int old = xmlSubstituteEntitiesDefaultValue;
+
+    xmlSubstituteEntitiesDefaultValue = val;
+    return(old);
+}
+
+/**
+ * xmlKeepBlanksDefault:
+ * @val:  int 0 or 1 
+ *
+ * Set and return the previous value for default blanks text nodes support.
+ * The 1.x version of the parser used an heuristic to try to detect
+ * ignorable white spaces. As a result the SAX callback was generating
+ * ignorableWhitespace() callbacks instead of characters() one, and when
+ * using the DOM output text nodes containing those blanks were not generated.
+ * The 2.x and later version will switch to the XML standard way and
+ * ignorableWhitespace() are only generated when running the parser in
+ * validating mode and when the current element doesn't allow CDATA or
+ * mixed content.
+ * This function is provided as a way to force the standard behaviour 
+ * on 1.X libs and to switch back to the old mode for compatibility when
+ * running 1.X client code on 2.X . Upgrade of 1.X code should be done
+ * by using xmlIsBlankNode() commodity function to detect the "empty"
+ * nodes generated.
+ * This value also affect autogeneration of indentation when saving code
+ * if blanks sections are kept, indentation is not generated.
+ *
+ * Returns the last value for 0 for no substitution, 1 for substitution.
+ */
+
+int
+xmlKeepBlanksDefault(int val) {
+    int old = xmlKeepBlanksDefaultValue;
+
+    xmlKeepBlanksDefaultValue = val;
+    xmlIndentTreeOutput = !val;
+    return(old);
+}
+
diff --git a/parser.h b/parser.h
new file mode 100644
index 0000000..b98f2a3
--- /dev/null
+++ b/parser.h
@@ -0,0 +1,527 @@
+/*
+ * parser.h : Interfaces, constants and types related to the XML parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_PARSER_H__
+#define __XML_PARSER_H__
+
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/xmlIO.h>
+#include <libxml/entities.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Constants.
+ */
+#define XML_DEFAULT_VERSION	"1.0"
+
+/**
+ * an xmlParserInput is an input flow for the XML processor.
+ * Each entity parsed is associated an xmlParserInput (except the
+ * few predefined ones). This is the case both for internal entities
+ * - in which case the flow is already completely in memory - or
+ * external entities - in which case we use the buf structure for
+ * progressive reading and I18N conversions to the internal UTF-8 format.
+ */
+
+typedef void (* xmlParserInputDeallocate)(xmlChar *);
+typedef struct _xmlParserInput xmlParserInput;
+typedef xmlParserInput *xmlParserInputPtr;
+struct _xmlParserInput {
+    /* Input buffer */
+    xmlParserInputBufferPtr buf;      /* UTF-8 encoded buffer */
+
+    const char *filename;             /* The file analyzed, if any */
+    const char *directory;            /* the directory/base of teh file */
+    const xmlChar *base;              /* Base of the array to parse */
+    const xmlChar *cur;               /* Current char being parsed */
+    int length;                       /* length if known */
+    int line;                         /* Current line */
+    int col;                          /* Current column */
+    int consumed;                     /* How many xmlChars already consumed */
+    xmlParserInputDeallocate free;    /* function to deallocate the base */
+    const xmlChar *encoding;          /* the encoding string for entity */
+    const xmlChar *version;           /* the version string for entity */
+    int standalone;                   /* Was that entity marked standalone */
+};
+
+/**
+ * the parser can be asked to collect Node informations, i.e. at what
+ * place in the file they were detected. 
+ * NOTE: This is off by default and not very well tested.
+ */
+typedef struct _xmlParserNodeInfo xmlParserNodeInfo;
+typedef xmlParserNodeInfo *xmlParserNodeInfoPtr;
+
+struct _xmlParserNodeInfo {
+  const struct _xmlNode* node;
+  /* Position & line # that text that created the node begins & ends on */
+  unsigned long begin_pos;
+  unsigned long begin_line;
+  unsigned long end_pos;
+  unsigned long end_line;
+};
+
+typedef struct _xmlParserNodeInfoSeq xmlParserNodeInfoSeq;
+typedef xmlParserNodeInfoSeq *xmlParserNodeInfoSeqPtr;
+struct _xmlParserNodeInfoSeq {
+  unsigned long maximum;
+  unsigned long length;
+  xmlParserNodeInfo* buffer;
+};
+
+/**
+ * The parser is now working also as a state based parser
+ * The recursive one use the stagte info for entities processing
+ */
+typedef enum {
+    XML_PARSER_EOF = -1,	/* nothing is to be parsed */
+    XML_PARSER_START = 0,	/* nothing has been parsed */
+    XML_PARSER_MISC,		/* Misc* before int subset */
+    XML_PARSER_PI,		/* Whithin a processing instruction */
+    XML_PARSER_DTD,		/* within some DTD content */
+    XML_PARSER_PROLOG,		/* Misc* after internal subset */
+    XML_PARSER_COMMENT,		/* within a comment */
+    XML_PARSER_START_TAG,	/* within a start tag */
+    XML_PARSER_CONTENT,		/* within the content */
+    XML_PARSER_CDATA_SECTION,	/* within a CDATA section */
+    XML_PARSER_END_TAG,		/* within a closing tag */
+    XML_PARSER_ENTITY_DECL,	/* within an entity declaration */
+    XML_PARSER_ENTITY_VALUE,	/* within an entity value in a decl */
+    XML_PARSER_ATTRIBUTE_VALUE,	/* within an attribute value */
+    XML_PARSER_SYSTEM_LITERAL,	/* within a SYSTEM value */
+    XML_PARSER_EPILOG, 		/* the Misc* after the last end tag */
+    XML_PARSER_IGNORE		/* within an IGNORED section */
+} xmlParserInputState;
+
+/**
+ * The parser context.
+ * NOTE This doesn't completely defines the parser state, the (current ?)
+ *      design of the parser uses recursive function calls since this allow
+ *      and easy mapping from the production rules of the specification
+ *      to the actual code. The drawback is that the actual function call
+ *      also reflect the parser state. However most of the parsing routines
+ *      takes as the only argument the parser context pointer, so migrating
+ *      to a state based parser for progressive parsing shouldn't be too hard.
+ */
+typedef struct _xmlParserCtxt xmlParserCtxt;
+typedef xmlParserCtxt *xmlParserCtxtPtr;
+struct _xmlParserCtxt {
+    struct _xmlSAXHandler *sax;       /* The SAX handler */
+    void            *userData;        /* For SAX interface only, used by DOM build */
+    xmlDocPtr           myDoc;        /* the document being built */
+    int            wellFormed;        /* is the document well formed */
+    int       replaceEntities;        /* shall we replace entities ? */
+    const xmlChar    *version;        /* the XML version string */
+    const xmlChar   *encoding;        /* the declared encoding, if any */
+    int            standalone;        /* standalone document */
+    int                  html;        /* an HTML(1)/Docbook(2) document */
+
+    /* Input stream stack */
+    xmlParserInputPtr  input;         /* Current input stream */
+    int                inputNr;       /* Number of current input streams */
+    int                inputMax;      /* Max number of input streams */
+    xmlParserInputPtr *inputTab;      /* stack of inputs */
+
+    /* Node analysis stack only used for DOM building */
+    xmlNodePtr         node;          /* Current parsed Node */
+    int                nodeNr;        /* Depth of the parsing stack */
+    int                nodeMax;       /* Max depth of the parsing stack */
+    xmlNodePtr        *nodeTab;       /* array of nodes */
+
+    int record_info;                  /* Whether node info should be kept */
+    xmlParserNodeInfoSeq node_seq;    /* info about each node parsed */
+
+    int errNo;                        /* error code */
+
+    int     hasExternalSubset;        /* reference and external subset */
+    int             hasPErefs;        /* the internal subset has PE refs */
+    int              external;        /* are we parsing an external entity */
+
+    int                 valid;        /* is the document valid */
+    int              validate;        /* shall we try to validate ? */
+    xmlValidCtxt        vctxt;        /* The validity context */
+
+    xmlParserInputState instate;      /* current type of input */
+    int                 token;        /* next char look-ahead */    
+
+    char           *directory;        /* the data directory */
+
+    /* Node name stack */
+    xmlChar           *name;          /* Current parsed Node */
+    int                nameNr;        /* Depth of the parsing stack */
+    int                nameMax;       /* Max depth of the parsing stack */
+    xmlChar *         *nameTab;       /* array of nodes */
+
+    long               nbChars;       /* number of xmlChar processed */
+    long            checkIndex;       /* used by progressive parsing lookup */
+    int             keepBlanks;       /* ugly but ... */
+    int             disableSAX;       /* SAX callbacks are disabled */
+    int               inSubset;       /* Parsing is in int 1/ext 2 subset */
+    xmlChar *          intSubName;    /* name of subset */
+    xmlChar *          extSubURI;     /* URI of external subset */
+    xmlChar *          extSubSystem;  /* SYSTEM ID of external subset */
+
+    /* xml:space values */
+    int *              space;         /* Should the parser preserve spaces */
+    int                spaceNr;       /* Depth of the parsing stack */
+    int                spaceMax;      /* Max depth of the parsing stack */
+    int *              spaceTab;      /* array of space infos */
+
+    int                depth;         /* to prevent entity substitution loops */
+    xmlParserInputPtr  entity;        /* used to check entities boundaries */
+    int                charset;       /* encoding of the in-memory content
+				         actually an xmlCharEncoding */
+    int                nodelen;       /* Those two fields are there to */
+    int                nodemem;       /* Speed up large node parsing */
+    int                pedantic;      /* signal pedantic warnings */
+    void              *_private;      /* For user data, libxml won't touch it */
+
+    int                loadsubset;    /* should the external subset be loaded */
+};
+
+/**
+ * a SAX Locator.
+ */
+typedef struct _xmlSAXLocator xmlSAXLocator;
+typedef xmlSAXLocator *xmlSAXLocatorPtr;
+struct _xmlSAXLocator {
+    const xmlChar *(*getPublicId)(void *ctx);
+    const xmlChar *(*getSystemId)(void *ctx);
+    int (*getLineNumber)(void *ctx);
+    int (*getColumnNumber)(void *ctx);
+};
+
+/**
+ * a SAX handler is bunch of callbacks called by the parser when processing
+ * of the input generate data or structure informations.
+ */
+
+typedef xmlParserInputPtr (*resolveEntitySAXFunc) (void *ctx,
+			    const xmlChar *publicId, const xmlChar *systemId);
+typedef void (*internalSubsetSAXFunc) (void *ctx, const xmlChar *name,
+                            const xmlChar *ExternalID, const xmlChar *SystemID);
+typedef void (*externalSubsetSAXFunc) (void *ctx, const xmlChar *name,
+                            const xmlChar *ExternalID, const xmlChar *SystemID);
+typedef xmlEntityPtr (*getEntitySAXFunc) (void *ctx,
+                            const xmlChar *name);
+typedef xmlEntityPtr (*getParameterEntitySAXFunc) (void *ctx,
+                            const xmlChar *name);
+typedef void (*entityDeclSAXFunc) (void *ctx,
+                            const xmlChar *name, int type, const xmlChar *publicId,
+			    const xmlChar *systemId, xmlChar *content);
+typedef void (*notationDeclSAXFunc)(void *ctx, const xmlChar *name,
+			    const xmlChar *publicId, const xmlChar *systemId);
+typedef void (*attributeDeclSAXFunc)(void *ctx, const xmlChar *elem,
+                            const xmlChar *name, int type, int def,
+			    const xmlChar *defaultValue, xmlEnumerationPtr tree);
+typedef void (*elementDeclSAXFunc)(void *ctx, const xmlChar *name,
+			    int type, xmlElementContentPtr content);
+typedef void (*unparsedEntityDeclSAXFunc)(void *ctx,
+                            const xmlChar *name, const xmlChar *publicId,
+			    const xmlChar *systemId, const xmlChar *notationName);
+typedef void (*setDocumentLocatorSAXFunc) (void *ctx,
+                            xmlSAXLocatorPtr loc);
+typedef void (*startDocumentSAXFunc) (void *ctx);
+typedef void (*endDocumentSAXFunc) (void *ctx);
+typedef void (*startElementSAXFunc) (void *ctx, const xmlChar *name,
+                            const xmlChar **atts);
+typedef void (*endElementSAXFunc) (void *ctx, const xmlChar *name);
+typedef void (*attributeSAXFunc) (void *ctx, const xmlChar *name,
+                                  const xmlChar *value);
+typedef void (*referenceSAXFunc) (void *ctx, const xmlChar *name);
+typedef void (*charactersSAXFunc) (void *ctx, const xmlChar *ch,
+		            int len);
+typedef void (*ignorableWhitespaceSAXFunc) (void *ctx,
+			    const xmlChar *ch, int len);
+typedef void (*processingInstructionSAXFunc) (void *ctx,
+                            const xmlChar *target, const xmlChar *data);
+typedef void (*commentSAXFunc) (void *ctx, const xmlChar *value);
+typedef void (*cdataBlockSAXFunc) (void *ctx, const xmlChar *value, int len);
+typedef void (*warningSAXFunc) (void *ctx, const char *msg, ...);
+typedef void (*errorSAXFunc) (void *ctx, const char *msg, ...);
+typedef void (*fatalErrorSAXFunc) (void *ctx, const char *msg, ...);
+typedef int (*isStandaloneSAXFunc) (void *ctx);
+typedef int (*hasInternalSubsetSAXFunc) (void *ctx);
+typedef int (*hasExternalSubsetSAXFunc) (void *ctx);
+
+typedef struct _xmlSAXHandler xmlSAXHandler;
+typedef xmlSAXHandler *xmlSAXHandlerPtr;
+struct _xmlSAXHandler {
+    internalSubsetSAXFunc internalSubset;
+    isStandaloneSAXFunc isStandalone;
+    hasInternalSubsetSAXFunc hasInternalSubset;
+    hasExternalSubsetSAXFunc hasExternalSubset;
+    resolveEntitySAXFunc resolveEntity;
+    getEntitySAXFunc getEntity;
+    entityDeclSAXFunc entityDecl;
+    notationDeclSAXFunc notationDecl;
+    attributeDeclSAXFunc attributeDecl;
+    elementDeclSAXFunc elementDecl;
+    unparsedEntityDeclSAXFunc unparsedEntityDecl;
+    setDocumentLocatorSAXFunc setDocumentLocator;
+    startDocumentSAXFunc startDocument;
+    endDocumentSAXFunc endDocument;
+    startElementSAXFunc startElement;
+    endElementSAXFunc endElement;
+    referenceSAXFunc reference;
+    charactersSAXFunc characters;
+    ignorableWhitespaceSAXFunc ignorableWhitespace;
+    processingInstructionSAXFunc processingInstruction;
+    commentSAXFunc comment;
+    warningSAXFunc warning;
+    errorSAXFunc error;
+    fatalErrorSAXFunc fatalError;
+    getParameterEntitySAXFunc getParameterEntity;
+    cdataBlockSAXFunc cdataBlock;
+    externalSubsetSAXFunc externalSubset;
+};
+
+/**
+ * External entity loaders types
+ */
+typedef xmlParserInputPtr (*xmlExternalEntityLoader)(const char *URL,
+						     const char *ID,
+						     xmlParserCtxtPtr context);
+
+/**
+ * Global variables: just the default SAX interface tables and XML
+ * version infos.
+ */
+LIBXML_DLL_IMPORT extern const char *xmlParserVersion;
+
+LIBXML_DLL_IMPORT extern xmlSAXLocator xmlDefaultSAXLocator;
+LIBXML_DLL_IMPORT extern xmlSAXHandler xmlDefaultSAXHandler;
+LIBXML_DLL_IMPORT extern xmlSAXHandler htmlDefaultSAXHandler;
+LIBXML_DLL_IMPORT extern xmlSAXHandler sgmlDefaultSAXHandler;
+
+/**
+ * entity substitution default behaviour.
+ */
+
+#ifdef VMS
+LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultVal;
+#define xmlSubstituteEntitiesDefaultValue xmlSubstituteEntitiesDefaultVal
+#else
+LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultValue;
+#endif
+LIBXML_DLL_IMPORT extern int xmlGetWarningsDefaultValue;
+
+
+/**
+ * Init/Cleanup
+ */
+void		xmlInitParser		(void);
+void		xmlCleanupParser	(void);
+
+/**
+ * Input functions
+ */
+int		xmlParserInputRead	(xmlParserInputPtr in,
+					 int len);
+int		xmlParserInputGrow	(xmlParserInputPtr in,
+					 int len);
+
+/**
+ * xmlChar handling
+ */
+xmlChar *	xmlStrdup		(const xmlChar *cur);
+xmlChar *	xmlStrndup		(const xmlChar *cur,
+					 int len);
+xmlChar *	xmlStrsub		(const xmlChar *str,
+					 int start,
+					 int len);
+const xmlChar *	xmlStrchr		(const xmlChar *str,
+					 xmlChar val);
+const xmlChar *	xmlStrstr		(const xmlChar *str,
+					 xmlChar *val);
+const xmlChar *	xmlStrcasestr		(const xmlChar *str,
+					 xmlChar *val);
+int		xmlStrcmp		(const xmlChar *str1,
+					 const xmlChar *str2);
+int		xmlStrncmp		(const xmlChar *str1,
+					 const xmlChar *str2,
+					 int len);
+int		xmlStrcasecmp		(const xmlChar *str1,
+					 const xmlChar *str2);
+int		xmlStrncasecmp		(const xmlChar *str1,
+					 const xmlChar *str2,
+					 int len);
+int		xmlStrEqual		(const xmlChar *str1,
+					 const xmlChar *str2);
+int		xmlStrlen		(const xmlChar *str);
+xmlChar *	xmlStrcat		(xmlChar *cur,
+					 const xmlChar *add);
+xmlChar *	xmlStrncat		(xmlChar *cur,
+					 const xmlChar *add,
+					 int len);
+
+/**
+ * Basic parsing Interfaces
+ */
+xmlDocPtr	xmlParseDoc		(xmlChar *cur);
+xmlDocPtr	xmlParseMemory		(char *buffer,
+					 int size);
+xmlDocPtr	xmlParseFile		(const char *filename);
+int		xmlSubstituteEntitiesDefault(int val);
+int		xmlKeepBlanksDefault	(int val);
+void		xmlStopParser		(xmlParserCtxtPtr ctxt);
+int		xmlPedanticParserDefault(int val);
+
+/**
+ * Recovery mode 
+ */
+xmlDocPtr	xmlRecoverDoc		(xmlChar *cur);
+xmlDocPtr	xmlRecoverMemory	(char *buffer,
+					 int size);
+xmlDocPtr	xmlRecoverFile		(const char *filename);
+
+/**
+ * Less common routines and SAX interfaces
+ */
+int		xmlParseDocument	(xmlParserCtxtPtr ctxt);
+int		xmlParseExtParsedEnt	(xmlParserCtxtPtr ctxt);
+xmlDocPtr	xmlSAXParseDoc		(xmlSAXHandlerPtr sax,
+					 xmlChar *cur,
+					 int recovery);
+int		xmlSAXUserParseFile	(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 const char *filename);
+int		xmlSAXUserParseMemory	(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 char *buffer,
+					 int size);
+xmlDocPtr	xmlSAXParseMemory	(xmlSAXHandlerPtr sax,
+					 char *buffer,
+                                   	 int size,
+					 int recovery);
+xmlDocPtr	xmlSAXParseFile		(xmlSAXHandlerPtr sax,
+					 const char *filename,
+					 int recovery);
+xmlDocPtr	xmlSAXParseEntity	(xmlSAXHandlerPtr sax,
+					 const char *filename);
+xmlDocPtr	xmlParseEntity		(const char *filename);
+xmlDtdPtr	xmlParseDTD		(const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlSAXParseDTD		(xmlSAXHandlerPtr sax,
+					 const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlIOParseDTD		(xmlSAXHandlerPtr sax,
+					 xmlParserInputBufferPtr input,
+					 xmlCharEncoding enc);
+int		xmlParseBalancedChunkMemory(xmlDocPtr doc,
+					 xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 int depth,
+					 const xmlChar *string,
+					 xmlNodePtr *list);
+int		xmlParseExternalEntity	(xmlDocPtr doc,
+					 xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 int depth,
+					 const xmlChar *URL,
+					 const xmlChar *ID,
+					 xmlNodePtr *list);
+int		xmlParseCtxtExternalEntity(xmlParserCtxtPtr ctx,
+					 const xmlChar *URL,
+					 const xmlChar *ID,
+					 xmlNodePtr *list);
+
+/**
+ * SAX initialization routines
+ */
+void		xmlDefaultSAXHandlerInit(void);
+void		htmlDefaultSAXHandlerInit(void);
+
+/**
+ * Parser contexts handling.
+ */
+void		xmlInitParserCtxt	(xmlParserCtxtPtr ctxt);
+void		xmlClearParserCtxt	(xmlParserCtxtPtr ctxt);
+void		xmlFreeParserCtxt	(xmlParserCtxtPtr ctxt);
+void		xmlSetupParserForBuffer	(xmlParserCtxtPtr ctxt,
+					 const xmlChar* buffer,
+					 const char* filename);
+xmlParserCtxtPtr xmlCreateDocParserCtxt	(xmlChar *cur);
+
+/**
+ * Reading/setting optional parsing features.
+ */
+
+int		xmlGetFeaturesList	(int *len,
+					 const char **result);
+int		xmlGetFeature		(xmlParserCtxtPtr ctxt,
+					 const char *name,
+					 void *result);
+int		xmlSetFeature		(xmlParserCtxtPtr ctxt,
+					 const char *name,
+					 void *value);
+
+/**
+ * Interfaces for the Push mode
+ */
+xmlParserCtxtPtr xmlCreatePushParserCtxt(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 const char *chunk,
+					 int size,
+					 const char *filename);
+int		 xmlParseChunk		(xmlParserCtxtPtr ctxt,
+					 const char *chunk,
+					 int size,
+					 int terminate);
+
+/**
+ * Special I/O mode
+ */
+
+xmlParserCtxtPtr xmlCreateIOParserCtxt	(xmlSAXHandlerPtr sax,
+					 void *user_data,
+					 xmlInputReadCallback   ioread,
+					 xmlInputCloseCallback  ioclose,
+					 void *ioctx,
+					 xmlCharEncoding enc);
+
+xmlParserInputPtr xmlNewIOInputStream	(xmlParserCtxtPtr ctxt,
+					 xmlParserInputBufferPtr input,
+					 xmlCharEncoding enc);
+
+/**
+ * Node infos
+ */
+const xmlParserNodeInfo*
+		xmlParserFindNodeInfo	(const xmlParserCtxt* ctxt,
+                                               const xmlNode* node);
+void		xmlInitNodeInfoSeq	(xmlParserNodeInfoSeqPtr seq);
+void		xmlClearNodeInfoSeq	(xmlParserNodeInfoSeqPtr seq);
+unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
+                                         const xmlNode* node);
+void		xmlParserAddNodeInfo	(xmlParserCtxtPtr ctxt,
+					 const xmlParserNodeInfo* info);
+
+/*
+ * External entities handling actually implemented in xmlIO
+ */
+
+void		xmlSetExternalEntityLoader(xmlExternalEntityLoader f);
+xmlExternalEntityLoader
+		xmlGetExternalEntityLoader(void);
+xmlParserInputPtr
+		xmlLoadExternalEntity	(const char *URL,
+					 const char *ID,
+					 xmlParserCtxtPtr context);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_PARSER_H__ */
+
diff --git a/parserInternals.c b/parserInternals.c
new file mode 100644
index 0000000..65ebf5f
--- /dev/null
+++ b/parserInternals.c
@@ -0,0 +1,3537 @@
+/*
+ * parser.c : Internal routines (and obsolete ones) needed for the
+ *            XML and HTML parsers.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#define XML_DIR_SEP '\\'
+#else
+#include "config.h"
+#define XML_DIR_SEP '/'
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/valid.h>
+#include <libxml/entities.h>
+#include <libxml/xmlerror.h>
+#include <libxml/encoding.h>
+#include <libxml/valid.h>
+#include <libxml/xmlIO.h>
+#include <libxml/uri.h>
+
+
+/************************************************************************
+ *									*
+ * 		Version and Features handling				*
+ *									*
+ ************************************************************************/
+const char *xmlParserVersion = LIBXML_VERSION_STRING;
+
+/*
+ * xmlCheckVersion:
+ * @version: the include version number
+ *
+ * check the compiled lib version against the include one.
+ * This can warn or immediately kill the application
+ */
+void
+xmlCheckVersion(int version) {
+    int myversion = (int) LIBXML_VERSION;
+
+    if ((myversion / 10000) != (version / 10000)) {
+	xmlGenericError(xmlGenericErrorContext, 
+		"Fatal: program compiled against libxml %d using libxml %d\n",
+		(version / 10000), (myversion / 10000));
+	exit(1);
+    }
+    if ((myversion / 100) < (version / 100)) {
+	xmlGenericError(xmlGenericErrorContext, 
+		"Warning: program compiled against libxml %d using older %d\n",
+		(version / 100), (myversion / 100));
+    }
+}
+
+
+const char *xmlFeaturesList[] = {
+    "validate",
+    "load subset",
+    "keep blanks",
+    "disable SAX",
+    "fetch external entities",
+    "substitute entities",
+    "gather line info",
+    "user data",
+    "is html",
+    "is standalone",
+    "stop parser",
+    "document",
+    "is well formed",
+    "is valid",
+    "SAX block",
+    "SAX function internalSubset",
+    "SAX function isStandalone",
+    "SAX function hasInternalSubset",
+    "SAX function hasExternalSubset",
+    "SAX function resolveEntity",
+    "SAX function getEntity",
+    "SAX function entityDecl",
+    "SAX function notationDecl",
+    "SAX function attributeDecl",
+    "SAX function elementDecl",
+    "SAX function unparsedEntityDecl",
+    "SAX function setDocumentLocator",
+    "SAX function startDocument",
+    "SAX function endDocument",
+    "SAX function startElement",
+    "SAX function endElement",
+    "SAX function reference",
+    "SAX function characters",
+    "SAX function ignorableWhitespace",
+    "SAX function processingInstruction",
+    "SAX function comment",
+    "SAX function warning",
+    "SAX function error",
+    "SAX function fatalError",
+    "SAX function getParameterEntity",
+    "SAX function cdataBlock",
+    "SAX function externalSubset",
+};
+
+/*
+ * xmlGetFeaturesList:
+ * @len:  the length of the features name array (input/output)
+ * @result:  an array of string to be filled with the features name.
+ *
+ * Copy at most *@len feature names into the @result array
+ *
+ * Returns -1 in case or error, or the total number of features,
+ *            len is updated with the number of strings copied,
+ *            strings must not be deallocated
+ */
+int
+xmlGetFeaturesList(int *len, const char **result) {
+    int ret, i;
+
+    ret = sizeof(xmlFeaturesList)/sizeof(xmlFeaturesList[0]);
+    if ((len == NULL) || (result == NULL))
+	return(ret);
+    if ((*len < 0) || (*len >= 1000))
+	return(-1);
+    if (*len > ret)
+	*len = ret;
+    for (i = 0;i < *len;i++)
+	result[i] = xmlFeaturesList[i];
+    return(ret);
+}
+
+/*
+ * xmlGetFeature:
+ * @ctxt:  an XML/HTML parser context
+ * @name:  the feature name
+ * @result:  location to store the result
+ *
+ * Read the current value of one feature of this parser instance
+ *
+ * Returns -1 in case or error, 0 otherwise
+ */
+int
+xmlGetFeature(xmlParserCtxtPtr ctxt, const char *name, void *result) {
+    if ((ctxt == NULL) || (name == NULL) || (result == NULL))
+	return(-1);
+
+    if (!strcmp(name, "validate")) {
+	*((int *) result) = ctxt->validate;
+    } else if (!strcmp(name, "keep blanks")) {
+	*((int *) result) = ctxt->keepBlanks;
+    } else if (!strcmp(name, "disable SAX")) {
+	*((int *) result) = ctxt->disableSAX;
+    } else if (!strcmp(name, "fetch external entities")) {
+	*((int *) result) = ctxt->loadsubset;
+    } else if (!strcmp(name, "substitute entities")) {
+	*((int *) result) = ctxt->replaceEntities;
+    } else if (!strcmp(name, "gather line info")) {
+	*((int *) result) = ctxt->record_info;
+    } else if (!strcmp(name, "user data")) {
+	*((void **)result) = ctxt->userData;
+    } else if (!strcmp(name, "is html")) {
+	*((int *) result) = ctxt->html;
+    } else if (!strcmp(name, "is standalone")) {
+	*((int *) result) = ctxt->standalone;
+    } else if (!strcmp(name, "document")) {
+	*((xmlDocPtr *) result) = ctxt->myDoc;
+    } else if (!strcmp(name, "is well formed")) {
+	*((int *) result) = ctxt->wellFormed;
+    } else if (!strcmp(name, "is valid")) {
+	*((int *) result) = ctxt->valid;
+    } else if (!strcmp(name, "SAX block")) {
+	*((xmlSAXHandlerPtr *) result) = ctxt->sax;
+    } else if (!strcmp(name, "SAX function internalSubset")) {
+        *((internalSubsetSAXFunc *) result) = ctxt->sax->internalSubset;
+    } else if (!strcmp(name, "SAX function isStandalone")) {
+        *((isStandaloneSAXFunc *) result) = ctxt->sax->isStandalone;
+    } else if (!strcmp(name, "SAX function hasInternalSubset")) {
+        *((hasInternalSubsetSAXFunc *) result) = ctxt->sax->hasInternalSubset;
+    } else if (!strcmp(name, "SAX function hasExternalSubset")) {
+        *((hasExternalSubsetSAXFunc *) result) = ctxt->sax->hasExternalSubset;
+    } else if (!strcmp(name, "SAX function resolveEntity")) {
+        *((resolveEntitySAXFunc *) result) = ctxt->sax->resolveEntity;
+    } else if (!strcmp(name, "SAX function getEntity")) {
+        *((getEntitySAXFunc *) result) = ctxt->sax->getEntity;
+    } else if (!strcmp(name, "SAX function entityDecl")) {
+        *((entityDeclSAXFunc *) result) = ctxt->sax->entityDecl;
+    } else if (!strcmp(name, "SAX function notationDecl")) {
+        *((notationDeclSAXFunc *) result) = ctxt->sax->notationDecl;
+    } else if (!strcmp(name, "SAX function attributeDecl")) {
+        *((attributeDeclSAXFunc *) result) = ctxt->sax->attributeDecl;
+    } else if (!strcmp(name, "SAX function elementDecl")) {
+        *((elementDeclSAXFunc *) result) = ctxt->sax->elementDecl;
+    } else if (!strcmp(name, "SAX function unparsedEntityDecl")) {
+        *((unparsedEntityDeclSAXFunc *) result) = ctxt->sax->unparsedEntityDecl;
+    } else if (!strcmp(name, "SAX function setDocumentLocator")) {
+        *((setDocumentLocatorSAXFunc *) result) = ctxt->sax->setDocumentLocator;
+    } else if (!strcmp(name, "SAX function startDocument")) {
+        *((startDocumentSAXFunc *) result) = ctxt->sax->startDocument;
+    } else if (!strcmp(name, "SAX function endDocument")) {
+        *((endDocumentSAXFunc *) result) = ctxt->sax->endDocument;
+    } else if (!strcmp(name, "SAX function startElement")) {
+        *((startElementSAXFunc *) result) = ctxt->sax->startElement;
+    } else if (!strcmp(name, "SAX function endElement")) {
+        *((endElementSAXFunc *) result) = ctxt->sax->endElement;
+    } else if (!strcmp(name, "SAX function reference")) {
+        *((referenceSAXFunc *) result) = ctxt->sax->reference;
+    } else if (!strcmp(name, "SAX function characters")) {
+        *((charactersSAXFunc *) result) = ctxt->sax->characters;
+    } else if (!strcmp(name, "SAX function ignorableWhitespace")) {
+        *((ignorableWhitespaceSAXFunc *) result) = ctxt->sax->ignorableWhitespace;
+    } else if (!strcmp(name, "SAX function processingInstruction")) {
+        *((processingInstructionSAXFunc *) result) = ctxt->sax->processingInstruction;
+    } else if (!strcmp(name, "SAX function comment")) {
+        *((commentSAXFunc *) result) = ctxt->sax->comment;
+    } else if (!strcmp(name, "SAX function warning")) {
+        *((warningSAXFunc *) result) = ctxt->sax->warning;
+    } else if (!strcmp(name, "SAX function error")) {
+        *((errorSAXFunc *) result) = ctxt->sax->error;
+    } else if (!strcmp(name, "SAX function fatalError")) {
+        *((fatalErrorSAXFunc *) result) = ctxt->sax->fatalError;
+    } else if (!strcmp(name, "SAX function getParameterEntity")) {
+        *((getParameterEntitySAXFunc *) result) = ctxt->sax->getParameterEntity;
+    } else if (!strcmp(name, "SAX function cdataBlock")) {
+        *((cdataBlockSAXFunc *) result) = ctxt->sax->cdataBlock;
+    } else if (!strcmp(name, "SAX function externalSubset")) {
+        *((externalSubsetSAXFunc *) result) = ctxt->sax->externalSubset;
+    } else {
+	return(-1);
+    }
+    return(0);
+}
+
+/*
+ * xmlSetFeature:
+ * @ctxt:  an XML/HTML parser context
+ * @name:  the feature name
+ * @value:  pointer to the location of the new value
+ *
+ * Change the current value of one feature of this parser instance
+ *
+ * Returns -1 in case or error, 0 otherwise
+ */
+int	
+xmlSetFeature(xmlParserCtxtPtr ctxt, const char *name, void *value) {
+    if ((ctxt == NULL) || (name == NULL) || (value == NULL))
+	return(-1);
+
+    if (!strcmp(name, "validate")) {
+	int newvalidate = *((int *) value);
+	if ((!ctxt->validate) && (newvalidate != 0)) {
+	    if (ctxt->vctxt.warning == NULL)
+		ctxt->vctxt.warning = xmlParserValidityWarning;
+	    if (ctxt->vctxt.error == NULL)
+		ctxt->vctxt.error = xmlParserValidityError;
+	    /* Allocate the Node stack */
+	    ctxt->vctxt.nodeTab = (xmlNodePtr *)
+		       xmlMalloc(4 * sizeof(xmlNodePtr));
+	    if (ctxt->vctxt.nodeTab == NULL) {
+		ctxt->vctxt.nodeMax = 0;
+		ctxt->validate = 0;
+		return(-1);
+	    }
+	    ctxt->vctxt.nodeNr = 0;
+	    ctxt->vctxt.nodeMax = 4;
+	    ctxt->vctxt.node = NULL;
+	}
+        ctxt->validate = newvalidate;
+    } else if (!strcmp(name, "keep blanks")) {
+        ctxt->keepBlanks = *((int *) value);
+    } else if (!strcmp(name, "disable SAX")) {
+        ctxt->disableSAX = *((int *) value);
+    } else if (!strcmp(name, "fetch external entities")) {
+	ctxt->loadsubset = *((int *) value);
+    } else if (!strcmp(name, "substitute entities")) {
+        ctxt->replaceEntities = *((int *) value);
+    } else if (!strcmp(name, "gather line info")) {
+        ctxt->record_info = *((int *) value);
+    } else if (!strcmp(name, "user data")) {
+        ctxt->userData = *((void **)value);
+    } else if (!strcmp(name, "is html")) {
+        ctxt->html = *((int *) value);
+    } else if (!strcmp(name, "is standalone")) {
+        ctxt->standalone = *((int *) value);
+    } else if (!strcmp(name, "document")) {
+        ctxt->myDoc = *((xmlDocPtr *) value);
+    } else if (!strcmp(name, "is well formed")) {
+        ctxt->wellFormed = *((int *) value);
+    } else if (!strcmp(name, "is valid")) {
+        ctxt->valid = *((int *) value);
+    } else if (!strcmp(name, "SAX block")) {
+        ctxt->sax = *((xmlSAXHandlerPtr *) value);
+    } else if (!strcmp(name, "SAX function internalSubset")) {
+        ctxt->sax->internalSubset = *((internalSubsetSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function isStandalone")) {
+        ctxt->sax->isStandalone = *((isStandaloneSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function hasInternalSubset")) {
+        ctxt->sax->hasInternalSubset = *((hasInternalSubsetSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function hasExternalSubset")) {
+        ctxt->sax->hasExternalSubset = *((hasExternalSubsetSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function resolveEntity")) {
+        ctxt->sax->resolveEntity = *((resolveEntitySAXFunc *) value);
+    } else if (!strcmp(name, "SAX function getEntity")) {
+        ctxt->sax->getEntity = *((getEntitySAXFunc *) value);
+    } else if (!strcmp(name, "SAX function entityDecl")) {
+        ctxt->sax->entityDecl = *((entityDeclSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function notationDecl")) {
+        ctxt->sax->notationDecl = *((notationDeclSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function attributeDecl")) {
+        ctxt->sax->attributeDecl = *((attributeDeclSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function elementDecl")) {
+        ctxt->sax->elementDecl = *((elementDeclSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function unparsedEntityDecl")) {
+        ctxt->sax->unparsedEntityDecl = *((unparsedEntityDeclSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function setDocumentLocator")) {
+        ctxt->sax->setDocumentLocator = *((setDocumentLocatorSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function startDocument")) {
+        ctxt->sax->startDocument = *((startDocumentSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function endDocument")) {
+        ctxt->sax->endDocument = *((endDocumentSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function startElement")) {
+        ctxt->sax->startElement = *((startElementSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function endElement")) {
+        ctxt->sax->endElement = *((endElementSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function reference")) {
+        ctxt->sax->reference = *((referenceSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function characters")) {
+        ctxt->sax->characters = *((charactersSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function ignorableWhitespace")) {
+        ctxt->sax->ignorableWhitespace = *((ignorableWhitespaceSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function processingInstruction")) {
+        ctxt->sax->processingInstruction = *((processingInstructionSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function comment")) {
+        ctxt->sax->comment = *((commentSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function warning")) {
+        ctxt->sax->warning = *((warningSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function error")) {
+        ctxt->sax->error = *((errorSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function fatalError")) {
+        ctxt->sax->fatalError = *((fatalErrorSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function getParameterEntity")) {
+        ctxt->sax->getParameterEntity = *((getParameterEntitySAXFunc *) value);
+    } else if (!strcmp(name, "SAX function cdataBlock")) {
+        ctxt->sax->cdataBlock = *((cdataBlockSAXFunc *) value);
+    } else if (!strcmp(name, "SAX function externalSubset")) {
+        ctxt->sax->externalSubset = *((externalSubsetSAXFunc *) value);
+    } else {
+	return(-1);
+    }
+    return(0);
+}
+
+/************************************************************************
+ *									*
+ * 		Some functions to avoid too large macros		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlIsChar:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
+ *                  | [#x10000-#x10FFFF]
+ * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
+ * Also available as a macro IS_CHAR()
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsChar(int c) {
+    return(
+     ((c) == 0x09) || ((c) == 0x0A) || ((c) == 0x0D) ||
+     (((c) >= 0x20) && ((c) <= 0xD7FF)) ||
+     (((c) >= 0xE000) && ((c) <= 0xFFFD)) ||
+     (((c) >= 0x10000) && ((c) <= 0x10FFFF)));
+}
+
+/**
+ * xmlIsBlank:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [3] S ::= (#x20 | #x9 | #xD | #xA)+
+ * Also available as a macro IS_BLANK()
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsBlank(int c) {
+    return(((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) || ((c) == 0x0D));
+}
+
+/**
+ * xmlIsBaseChar:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [85] BaseChar ::= ... long list see REC ...
+ *
+ * VI is your friend !
+ * :1,$ s/\[#x\([0-9A-Z]*\)-#x\([0-9A-Z]*\)\]/     (((c) >= 0x\1) \&\& ((c) <= 0x\2)) ||/
+ * and 
+ * :1,$ s/#x\([0-9A-Z]*\)/     ((c) == 0x\1) ||/
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+static int xmlBaseArray[] = {
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0000 - 0x000F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0010 - 0x001F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0020 - 0x002F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0030 - 0x003F */
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x0040 - 0x004F */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x0050 - 0x005F */
+  0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x0060 - 0x006F */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 0x0070 - 0x007F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0080 - 0x008F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x0090 - 0x009F */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00A0 - 0x00AF */
+  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00B0 - 0x00BF */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00C0 - 0x00CF */
+  1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00D0 - 0x00DF */
+  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00E0 - 0x00EF */
+  1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /* 0x00F0 - 0x00FF */
+};
+
+int
+xmlIsBaseChar(int c) {
+    return(
+      (((c) < 0x0100) ? xmlBaseArray[c] :
+      (	/* accelerator */
+      (((c) >= 0x0100) && ((c) <= 0x0131)) ||
+      (((c) >= 0x0134) && ((c) <= 0x013E)) ||
+      (((c) >= 0x0141) && ((c) <= 0x0148)) ||
+      (((c) >= 0x014A) && ((c) <= 0x017E)) ||
+      (((c) >= 0x0180) && ((c) <= 0x01C3)) ||
+      (((c) >= 0x01CD) && ((c) <= 0x01F0)) ||
+      (((c) >= 0x01F4) && ((c) <= 0x01F5)) ||
+      (((c) >= 0x01FA) && ((c) <= 0x0217)) ||
+      (((c) >= 0x0250) && ((c) <= 0x02A8)) ||
+      (((c) >= 0x02BB) && ((c) <= 0x02C1)) ||
+      ((c) == 0x0386) ||
+      (((c) >= 0x0388) && ((c) <= 0x038A)) ||
+      ((c) == 0x038C) ||
+      (((c) >= 0x038E) && ((c) <= 0x03A1)) ||
+      (((c) >= 0x03A3) && ((c) <= 0x03CE)) ||
+      (((c) >= 0x03D0) && ((c) <= 0x03D6)) ||
+      ((c) == 0x03DA) ||
+      ((c) == 0x03DC) ||
+      ((c) == 0x03DE) ||
+      ((c) == 0x03E0) ||
+      (((c) >= 0x03E2) && ((c) <= 0x03F3)) ||
+      (((c) >= 0x0401) && ((c) <= 0x040C)) ||
+      (((c) >= 0x040E) && ((c) <= 0x044F)) ||
+      (((c) >= 0x0451) && ((c) <= 0x045C)) ||
+      (((c) >= 0x045E) && ((c) <= 0x0481)) ||
+      (((c) >= 0x0490) && ((c) <= 0x04C4)) ||
+      (((c) >= 0x04C7) && ((c) <= 0x04C8)) ||
+      (((c) >= 0x04CB) && ((c) <= 0x04CC)) ||
+      (((c) >= 0x04D0) && ((c) <= 0x04EB)) ||
+      (((c) >= 0x04EE) && ((c) <= 0x04F5)) ||
+      (((c) >= 0x04F8) && ((c) <= 0x04F9)) ||
+      (((c) >= 0x0531) && ((c) <= 0x0556)) ||
+      ((c) == 0x0559) ||
+      (((c) >= 0x0561) && ((c) <= 0x0586)) ||
+      (((c) >= 0x05D0) && ((c) <= 0x05EA)) ||
+      (((c) >= 0x05F0) && ((c) <= 0x05F2)) ||
+      (((c) >= 0x0621) && ((c) <= 0x063A)) ||
+      (((c) >= 0x0641) && ((c) <= 0x064A)) ||
+      (((c) >= 0x0671) && ((c) <= 0x06B7)) ||
+      (((c) >= 0x06BA) && ((c) <= 0x06BE)) ||
+      (((c) >= 0x06C0) && ((c) <= 0x06CE)) ||
+      (((c) >= 0x06D0) && ((c) <= 0x06D3)) ||
+      ((c) == 0x06D5) ||
+      (((c) >= 0x06E5) && ((c) <= 0x06E6)) ||
+     (((c) >= 0x905) && (	/* accelerator */
+      (((c) >= 0x0905) && ((c) <= 0x0939)) ||
+      ((c) == 0x093D) ||
+      (((c) >= 0x0958) && ((c) <= 0x0961)) ||
+      (((c) >= 0x0985) && ((c) <= 0x098C)) ||
+      (((c) >= 0x098F) && ((c) <= 0x0990)) ||
+      (((c) >= 0x0993) && ((c) <= 0x09A8)) ||
+      (((c) >= 0x09AA) && ((c) <= 0x09B0)) ||
+      ((c) == 0x09B2) ||
+      (((c) >= 0x09B6) && ((c) <= 0x09B9)) ||
+      (((c) >= 0x09DC) && ((c) <= 0x09DD)) ||
+      (((c) >= 0x09DF) && ((c) <= 0x09E1)) ||
+      (((c) >= 0x09F0) && ((c) <= 0x09F1)) ||
+      (((c) >= 0x0A05) && ((c) <= 0x0A0A)) ||
+      (((c) >= 0x0A0F) && ((c) <= 0x0A10)) ||
+      (((c) >= 0x0A13) && ((c) <= 0x0A28)) ||
+      (((c) >= 0x0A2A) && ((c) <= 0x0A30)) ||
+      (((c) >= 0x0A32) && ((c) <= 0x0A33)) ||
+      (((c) >= 0x0A35) && ((c) <= 0x0A36)) ||
+      (((c) >= 0x0A38) && ((c) <= 0x0A39)) ||
+      (((c) >= 0x0A59) && ((c) <= 0x0A5C)) ||
+      ((c) == 0x0A5E) ||
+      (((c) >= 0x0A72) && ((c) <= 0x0A74)) ||
+      (((c) >= 0x0A85) && ((c) <= 0x0A8B)) ||
+      ((c) == 0x0A8D) ||
+      (((c) >= 0x0A8F) && ((c) <= 0x0A91)) ||
+      (((c) >= 0x0A93) && ((c) <= 0x0AA8)) ||
+      (((c) >= 0x0AAA) && ((c) <= 0x0AB0)) ||
+      (((c) >= 0x0AB2) && ((c) <= 0x0AB3)) ||
+      (((c) >= 0x0AB5) && ((c) <= 0x0AB9)) ||
+      ((c) == 0x0ABD) ||
+      ((c) == 0x0AE0) ||
+      (((c) >= 0x0B05) && ((c) <= 0x0B0C)) ||
+      (((c) >= 0x0B0F) && ((c) <= 0x0B10)) ||
+      (((c) >= 0x0B13) && ((c) <= 0x0B28)) ||
+      (((c) >= 0x0B2A) && ((c) <= 0x0B30)) ||
+      (((c) >= 0x0B32) && ((c) <= 0x0B33)) ||
+      (((c) >= 0x0B36) && ((c) <= 0x0B39)) ||
+      ((c) == 0x0B3D) ||
+      (((c) >= 0x0B5C) && ((c) <= 0x0B5D)) ||
+      (((c) >= 0x0B5F) && ((c) <= 0x0B61)) ||
+      (((c) >= 0x0B85) && ((c) <= 0x0B8A)) ||
+      (((c) >= 0x0B8E) && ((c) <= 0x0B90)) ||
+      (((c) >= 0x0B92) && ((c) <= 0x0B95)) ||
+      (((c) >= 0x0B99) && ((c) <= 0x0B9A)) ||
+      ((c) == 0x0B9C) ||
+      (((c) >= 0x0B9E) && ((c) <= 0x0B9F)) ||
+      (((c) >= 0x0BA3) && ((c) <= 0x0BA4)) ||
+      (((c) >= 0x0BA8) && ((c) <= 0x0BAA)) ||
+      (((c) >= 0x0BAE) && ((c) <= 0x0BB5)) ||
+      (((c) >= 0x0BB7) && ((c) <= 0x0BB9)) ||
+      (((c) >= 0x0C05) && ((c) <= 0x0C0C)) ||
+      (((c) >= 0x0C0E) && ((c) <= 0x0C10)) ||
+      (((c) >= 0x0C12) && ((c) <= 0x0C28)) ||
+      (((c) >= 0x0C2A) && ((c) <= 0x0C33)) ||
+      (((c) >= 0x0C35) && ((c) <= 0x0C39)) ||
+      (((c) >= 0x0C60) && ((c) <= 0x0C61)) ||
+      (((c) >= 0x0C85) && ((c) <= 0x0C8C)) ||
+      (((c) >= 0x0C8E) && ((c) <= 0x0C90)) ||
+      (((c) >= 0x0C92) && ((c) <= 0x0CA8)) ||
+      (((c) >= 0x0CAA) && ((c) <= 0x0CB3)) ||
+      (((c) >= 0x0CB5) && ((c) <= 0x0CB9)) ||
+      ((c) == 0x0CDE) ||
+      (((c) >= 0x0CE0) && ((c) <= 0x0CE1)) ||
+      (((c) >= 0x0D05) && ((c) <= 0x0D0C)) ||
+      (((c) >= 0x0D0E) && ((c) <= 0x0D10)) ||
+      (((c) >= 0x0D12) && ((c) <= 0x0D28)) ||
+      (((c) >= 0x0D2A) && ((c) <= 0x0D39)) ||
+      (((c) >= 0x0D60) && ((c) <= 0x0D61)) ||
+      (((c) >= 0x0E01) && ((c) <= 0x0E2E)) ||
+      ((c) == 0x0E30) ||
+      (((c) >= 0x0E32) && ((c) <= 0x0E33)) ||
+      (((c) >= 0x0E40) && ((c) <= 0x0E45)) ||
+      (((c) >= 0x0E81) && ((c) <= 0x0E82)) ||
+      ((c) == 0x0E84) ||
+      (((c) >= 0x0E87) && ((c) <= 0x0E88)) ||
+      ((c) == 0x0E8A) ||
+      ((c) == 0x0E8D) ||
+      (((c) >= 0x0E94) && ((c) <= 0x0E97)) ||
+      (((c) >= 0x0E99) && ((c) <= 0x0E9F)) ||
+      (((c) >= 0x0EA1) && ((c) <= 0x0EA3)) ||
+      ((c) == 0x0EA5) ||
+      ((c) == 0x0EA7) ||
+      (((c) >= 0x0EAA) && ((c) <= 0x0EAB)) ||
+      (((c) >= 0x0EAD) && ((c) <= 0x0EAE)) ||
+      ((c) == 0x0EB0) ||
+      (((c) >= 0x0EB2) && ((c) <= 0x0EB3)) ||
+      ((c) == 0x0EBD) ||
+      (((c) >= 0x0EC0) && ((c) <= 0x0EC4)) ||
+      (((c) >= 0x0F40) && ((c) <= 0x0F47)) ||
+      (((c) >= 0x0F49) && ((c) <= 0x0F69)) ||
+     (((c) >= 0x10A0) && (	/* accelerator */
+      (((c) >= 0x10A0) && ((c) <= 0x10C5)) ||
+      (((c) >= 0x10D0) && ((c) <= 0x10F6)) ||
+      ((c) == 0x1100) ||
+      (((c) >= 0x1102) && ((c) <= 0x1103)) ||
+      (((c) >= 0x1105) && ((c) <= 0x1107)) ||
+      ((c) == 0x1109) ||
+      (((c) >= 0x110B) && ((c) <= 0x110C)) ||
+      (((c) >= 0x110E) && ((c) <= 0x1112)) ||
+      ((c) == 0x113C) ||
+      ((c) == 0x113E) ||
+      ((c) == 0x1140) ||
+      ((c) == 0x114C) ||
+      ((c) == 0x114E) ||
+      ((c) == 0x1150) ||
+      (((c) >= 0x1154) && ((c) <= 0x1155)) ||
+      ((c) == 0x1159) ||
+      (((c) >= 0x115F) && ((c) <= 0x1161)) ||
+      ((c) == 0x1163) ||
+      ((c) == 0x1165) ||
+      ((c) == 0x1167) ||
+      ((c) == 0x1169) ||
+      (((c) >= 0x116D) && ((c) <= 0x116E)) ||
+      (((c) >= 0x1172) && ((c) <= 0x1173)) ||
+      ((c) == 0x1175) ||
+      ((c) == 0x119E) ||
+      ((c) == 0x11A8) ||
+      ((c) == 0x11AB) ||
+      (((c) >= 0x11AE) && ((c) <= 0x11AF)) ||
+      (((c) >= 0x11B7) && ((c) <= 0x11B8)) ||
+      ((c) == 0x11BA) ||
+      (((c) >= 0x11BC) && ((c) <= 0x11C2)) ||
+      ((c) == 0x11EB) ||
+      ((c) == 0x11F0) ||
+      ((c) == 0x11F9) ||
+      (((c) >= 0x1E00) && ((c) <= 0x1E9B)) ||
+      (((c) >= 0x1EA0) && ((c) <= 0x1EF9)) ||
+      (((c) >= 0x1F00) && ((c) <= 0x1F15)) ||
+      (((c) >= 0x1F18) && ((c) <= 0x1F1D)) ||
+      (((c) >= 0x1F20) && ((c) <= 0x1F45)) ||
+      (((c) >= 0x1F48) && ((c) <= 0x1F4D)) ||
+      (((c) >= 0x1F50) && ((c) <= 0x1F57)) ||
+      ((c) == 0x1F59) ||
+      ((c) == 0x1F5B) ||
+      ((c) == 0x1F5D) ||
+      (((c) >= 0x1F5F) && ((c) <= 0x1F7D)) ||
+      (((c) >= 0x1F80) && ((c) <= 0x1FB4)) ||
+      (((c) >= 0x1FB6) && ((c) <= 0x1FBC)) ||
+      ((c) == 0x1FBE) ||
+      (((c) >= 0x1FC2) && ((c) <= 0x1FC4)) ||
+      (((c) >= 0x1FC6) && ((c) <= 0x1FCC)) ||
+      (((c) >= 0x1FD0) && ((c) <= 0x1FD3)) ||
+      (((c) >= 0x1FD6) && ((c) <= 0x1FDB)) ||
+      (((c) >= 0x1FE0) && ((c) <= 0x1FEC)) ||
+      (((c) >= 0x1FF2) && ((c) <= 0x1FF4)) ||
+      (((c) >= 0x1FF6) && ((c) <= 0x1FFC)) ||
+      ((c) == 0x2126) ||
+      (((c) >= 0x212A) && ((c) <= 0x212B)) ||
+      ((c) == 0x212E) ||
+      (((c) >= 0x2180) && ((c) <= 0x2182)) ||
+      (((c) >= 0x3041) && ((c) <= 0x3094)) ||
+      (((c) >= 0x30A1) && ((c) <= 0x30FA)) ||
+      (((c) >= 0x3105) && ((c) <= 0x312C)) ||
+      (((c) >= 0xAC00) && ((c) <= 0xD7A3))) /* accelerators */ ))))));
+}
+
+/**
+ * xmlIsDigit:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [88] Digit ::= ... long list see REC ...
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsDigit(int c) {
+    return(
+      (((c) >= 0x0030) && ((c) <= 0x0039)) ||
+     (((c) >= 0x660) && (	/* accelerator */
+      (((c) >= 0x0660) && ((c) <= 0x0669)) ||
+      (((c) >= 0x06F0) && ((c) <= 0x06F9)) ||
+      (((c) >= 0x0966) && ((c) <= 0x096F)) ||
+      (((c) >= 0x09E6) && ((c) <= 0x09EF)) ||
+      (((c) >= 0x0A66) && ((c) <= 0x0A6F)) ||
+      (((c) >= 0x0AE6) && ((c) <= 0x0AEF)) ||
+      (((c) >= 0x0B66) && ((c) <= 0x0B6F)) ||
+      (((c) >= 0x0BE7) && ((c) <= 0x0BEF)) ||
+      (((c) >= 0x0C66) && ((c) <= 0x0C6F)) ||
+      (((c) >= 0x0CE6) && ((c) <= 0x0CEF)) ||
+      (((c) >= 0x0D66) && ((c) <= 0x0D6F)) ||
+      (((c) >= 0x0E50) && ((c) <= 0x0E59)) ||
+      (((c) >= 0x0ED0) && ((c) <= 0x0ED9)) ||
+      (((c) >= 0x0F20) && ((c) <= 0x0F29))) /* accelerator */ ));
+}
+
+/**
+ * xmlIsCombining:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [87] CombiningChar ::= ... long list see REC ...
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsCombining(int c) {
+    return(
+     (((c) >= 0x300) && (	/* accelerator */
+      (((c) >= 0x0300) && ((c) <= 0x0345)) ||
+      (((c) >= 0x0360) && ((c) <= 0x0361)) ||
+      (((c) >= 0x0483) && ((c) <= 0x0486)) ||
+      (((c) >= 0x0591) && ((c) <= 0x05A1)) ||
+      (((c) >= 0x05A3) && ((c) <= 0x05B9)) ||
+      (((c) >= 0x05BB) && ((c) <= 0x05BD)) ||
+      ((c) == 0x05BF) ||
+      (((c) >= 0x05C1) && ((c) <= 0x05C2)) ||
+      ((c) == 0x05C4) ||
+      (((c) >= 0x064B) && ((c) <= 0x0652)) ||
+      ((c) == 0x0670) ||
+      (((c) >= 0x06D6) && ((c) <= 0x06DC)) ||
+      (((c) >= 0x06DD) && ((c) <= 0x06DF)) ||
+      (((c) >= 0x06E0) && ((c) <= 0x06E4)) ||
+      (((c) >= 0x06E7) && ((c) <= 0x06E8)) ||
+      (((c) >= 0x06EA) && ((c) <= 0x06ED)) ||
+     (((c) >= 0x0901) && (	/* accelerator */
+      (((c) >= 0x0901) && ((c) <= 0x0903)) ||
+      ((c) == 0x093C) ||
+      (((c) >= 0x093E) && ((c) <= 0x094C)) ||
+      ((c) == 0x094D) ||
+      (((c) >= 0x0951) && ((c) <= 0x0954)) ||
+      (((c) >= 0x0962) && ((c) <= 0x0963)) ||
+      (((c) >= 0x0981) && ((c) <= 0x0983)) ||
+      ((c) == 0x09BC) ||
+      ((c) == 0x09BE) ||
+      ((c) == 0x09BF) ||
+      (((c) >= 0x09C0) && ((c) <= 0x09C4)) ||
+      (((c) >= 0x09C7) && ((c) <= 0x09C8)) ||
+      (((c) >= 0x09CB) && ((c) <= 0x09CD)) ||
+      ((c) == 0x09D7) ||
+      (((c) >= 0x09E2) && ((c) <= 0x09E3)) ||
+     (((c) >= 0x0A02) && (	/* accelerator */
+      ((c) == 0x0A02) ||
+      ((c) == 0x0A3C) ||
+      ((c) == 0x0A3E) ||
+      ((c) == 0x0A3F) ||
+      (((c) >= 0x0A40) && ((c) <= 0x0A42)) ||
+      (((c) >= 0x0A47) && ((c) <= 0x0A48)) ||
+      (((c) >= 0x0A4B) && ((c) <= 0x0A4D)) ||
+      (((c) >= 0x0A70) && ((c) <= 0x0A71)) ||
+      (((c) >= 0x0A81) && ((c) <= 0x0A83)) ||
+      ((c) == 0x0ABC) ||
+      (((c) >= 0x0ABE) && ((c) <= 0x0AC5)) ||
+      (((c) >= 0x0AC7) && ((c) <= 0x0AC9)) ||
+      (((c) >= 0x0ACB) && ((c) <= 0x0ACD)) ||
+      (((c) >= 0x0B01) && ((c) <= 0x0B03)) ||
+      ((c) == 0x0B3C) ||
+      (((c) >= 0x0B3E) && ((c) <= 0x0B43)) ||
+      (((c) >= 0x0B47) && ((c) <= 0x0B48)) ||
+      (((c) >= 0x0B4B) && ((c) <= 0x0B4D)) ||
+      (((c) >= 0x0B56) && ((c) <= 0x0B57)) ||
+      (((c) >= 0x0B82) && ((c) <= 0x0B83)) ||
+      (((c) >= 0x0BBE) && ((c) <= 0x0BC2)) ||
+      (((c) >= 0x0BC6) && ((c) <= 0x0BC8)) ||
+      (((c) >= 0x0BCA) && ((c) <= 0x0BCD)) ||
+      ((c) == 0x0BD7) ||
+      (((c) >= 0x0C01) && ((c) <= 0x0C03)) ||
+      (((c) >= 0x0C3E) && ((c) <= 0x0C44)) ||
+      (((c) >= 0x0C46) && ((c) <= 0x0C48)) ||
+      (((c) >= 0x0C4A) && ((c) <= 0x0C4D)) ||
+      (((c) >= 0x0C55) && ((c) <= 0x0C56)) ||
+      (((c) >= 0x0C82) && ((c) <= 0x0C83)) ||
+      (((c) >= 0x0CBE) && ((c) <= 0x0CC4)) ||
+      (((c) >= 0x0CC6) && ((c) <= 0x0CC8)) ||
+      (((c) >= 0x0CCA) && ((c) <= 0x0CCD)) ||
+      (((c) >= 0x0CD5) && ((c) <= 0x0CD6)) ||
+      (((c) >= 0x0D02) && ((c) <= 0x0D03)) ||
+      (((c) >= 0x0D3E) && ((c) <= 0x0D43)) ||
+      (((c) >= 0x0D46) && ((c) <= 0x0D48)) ||
+      (((c) >= 0x0D4A) && ((c) <= 0x0D4D)) ||
+      ((c) == 0x0D57) ||
+     (((c) >= 0x0E31) && (	/* accelerator */
+      ((c) == 0x0E31) ||
+      (((c) >= 0x0E34) && ((c) <= 0x0E3A)) ||
+      (((c) >= 0x0E47) && ((c) <= 0x0E4E)) ||
+      ((c) == 0x0EB1) ||
+      (((c) >= 0x0EB4) && ((c) <= 0x0EB9)) ||
+      (((c) >= 0x0EBB) && ((c) <= 0x0EBC)) ||
+      (((c) >= 0x0EC8) && ((c) <= 0x0ECD)) ||
+      (((c) >= 0x0F18) && ((c) <= 0x0F19)) ||
+      ((c) == 0x0F35) ||
+      ((c) == 0x0F37) ||
+      ((c) == 0x0F39) ||
+      ((c) == 0x0F3E) ||
+      ((c) == 0x0F3F) ||
+      (((c) >= 0x0F71) && ((c) <= 0x0F84)) ||
+      (((c) >= 0x0F86) && ((c) <= 0x0F8B)) ||
+      (((c) >= 0x0F90) && ((c) <= 0x0F95)) ||
+      ((c) == 0x0F97) ||
+      (((c) >= 0x0F99) && ((c) <= 0x0FAD)) ||
+      (((c) >= 0x0FB1) && ((c) <= 0x0FB7)) ||
+      ((c) == 0x0FB9) ||
+      (((c) >= 0x20D0) && ((c) <= 0x20DC)) ||
+      ((c) == 0x20E1) ||
+      (((c) >= 0x302A) && ((c) <= 0x302F)) ||
+      ((c) == 0x3099) ||
+      ((c) == 0x309A))))))))));
+}
+
+/**
+ * xmlIsExtender:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 |
+ *                   #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] |
+ *                   [#x309D-#x309E] | [#x30FC-#x30FE]
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsExtender(int c) {
+    switch (c) {
+    case 0x00B7: case 0x02D0: case 0x02D1: case 0x0387:
+    case 0x0640: case 0x0E46: case 0x0EC6: case 0x3005:
+    case 0x3031: case 0x3032: case 0x3033: case 0x3034:
+    case 0x3035: case 0x309D: case 0x309E: case 0x30FC:
+    case 0x30FE:
+	return 1;
+    default:
+	return 0;
+    }
+}
+
+/**
+ * xmlIsIdeographic:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsIdeographic(int c) {
+    return(((c) < 0x0100) ? 0 :
+     (((c) >= 0x4e00) && ((c) <= 0x9fa5)) ||
+     (((c) >= 0xf900) && ((c) <= 0xfa2d)) ||
+     (((c) >= 0x3021) && ((c) <= 0x3029)) ||
+      ((c) == 0x3007));
+}
+
+/**
+ * xmlIsLetter:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [84] Letter ::= BaseChar | Ideographic
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsLetter(int c) {
+    return(IS_BASECHAR(c) || IS_IDEOGRAPHIC(c));
+}
+
+/**
+ * xmlIsPubidChar:
+ * @c:  an unicode character (int)
+ *
+ * Check whether the character is allowed by the production
+ * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
+ *
+ * Returns 0 if not, non-zero otherwise
+ */
+int
+xmlIsPubidChar(int c) {
+    return(
+     ((c) == 0x20) || ((c) == 0x0D) || ((c) == 0x0A) ||
+     (((c) >= 'a') && ((c) <= 'z')) ||
+     (((c) >= 'A') && ((c) <= 'Z')) ||
+     (((c) >= '0') && ((c) <= '9')) ||
+     ((c) == '-') || ((c) == '\'') || ((c) == '(') || ((c) == ')') ||
+     ((c) == '+') || ((c) == ',') || ((c) == '.') || ((c) == '/') ||
+     ((c) == ':') || ((c) == '=') || ((c) == '?') || ((c) == ';') ||
+     ((c) == '!') || ((c) == '*') || ((c) == '#') || ((c) == '@') ||
+     ((c) == '$') || ((c) == '_') || ((c) == '%'));
+}
+
+/************************************************************************
+ *									*
+ * 		Input handling functions for progressive parsing	*
+ *									*
+ ************************************************************************/
+
+/* #define DEBUG_INPUT */
+/* #define DEBUG_STACK */
+/* #define DEBUG_PUSH */
+
+
+/* we need to keep enough input to show errors in context */
+#define LINE_LEN        80
+
+#ifdef DEBUG_INPUT
+#define CHECK_BUFFER(in) check_buffer(in)
+
+void check_buffer(xmlParserInputPtr in) {
+    if (in->base != in->buf->buffer->content) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlParserInput: base mismatch problem\n");
+    }
+    if (in->cur < in->base) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlParserInput: cur < base problem\n");
+    }
+    if (in->cur > in->base + in->buf->buffer->use) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlParserInput: cur > base + use problem\n");
+    }
+    xmlGenericError(xmlGenericErrorContext,"buffer %x : content %x, cur %d, use %d, size %d\n",
+            (int) in, (int) in->buf->buffer->content, in->cur - in->base,
+	    in->buf->buffer->use, in->buf->buffer->size);
+}
+
+#else
+#define CHECK_BUFFER(in) 
+#endif
+
+
+/**
+ * xmlParserInputRead:
+ * @in:  an XML parser input
+ * @len:  an indicative size for the lookahead
+ *
+ * This function refresh the input for the parser. It doesn't try to
+ * preserve pointers to the input buffer, and discard already read data
+ *
+ * Returns the number of xmlChars read, or -1 in case of error, 0 indicate the
+ * end of this entity
+ */
+int
+xmlParserInputRead(xmlParserInputPtr in, int len) {
+    int ret;
+    int used;
+    int index;
+
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext, "Read\n");
+#endif
+    if (in->buf == NULL) return(-1);
+    if (in->base == NULL) return(-1);
+    if (in->cur == NULL) return(-1);
+    if (in->buf->buffer == NULL) return(-1);
+    if (in->buf->readcallback == NULL) return(-1);
+
+    CHECK_BUFFER(in);
+
+    used = in->cur - in->buf->buffer->content;
+    ret = xmlBufferShrink(in->buf->buffer, used);
+    if (ret > 0) {
+	in->cur -= ret;
+	in->consumed += ret;
+    }
+    ret = xmlParserInputBufferRead(in->buf, len);
+    if (in->base != in->buf->buffer->content) {
+        /*
+	 * the buffer has been realloced
+	 */
+	index = in->cur - in->base;
+	in->base = in->buf->buffer->content;
+	in->cur = &in->buf->buffer->content[index];
+    }
+
+    CHECK_BUFFER(in);
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputGrow:
+ * @in:  an XML parser input
+ * @len:  an indicative size for the lookahead
+ *
+ * This function increase the input for the parser. It tries to
+ * preserve pointers to the input buffer, and keep already read data
+ *
+ * Returns the number of xmlChars read, or -1 in case of error, 0 indicate the
+ * end of this entity
+ */
+int
+xmlParserInputGrow(xmlParserInputPtr in, int len) {
+    int ret;
+    int index;
+
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext, "Grow\n");
+#endif
+    if (in->buf == NULL) return(-1);
+    if (in->base == NULL) return(-1);
+    if (in->cur == NULL) return(-1);
+    if (in->buf->buffer == NULL) return(-1);
+
+    CHECK_BUFFER(in);
+
+    index = in->cur - in->base;
+    if (in->buf->buffer->use > (unsigned int) index + INPUT_CHUNK) {
+
+	CHECK_BUFFER(in);
+
+        return(0);
+    }
+    if (in->buf->readcallback != NULL)
+	ret = xmlParserInputBufferGrow(in->buf, len);
+    else	
+        return(0);
+
+    /*
+     * NOTE : in->base may be a "dandling" i.e. freed pointer in this
+     *        block, but we use it really as an integer to do some
+     *        pointer arithmetic. Insure will raise it as a bug but in
+     *        that specific case, that's not !
+     */
+    if (in->base != in->buf->buffer->content) {
+        /*
+	 * the buffer has been realloced
+	 */
+	index = in->cur - in->base;
+	in->base = in->buf->buffer->content;
+	in->cur = &in->buf->buffer->content[index];
+    }
+
+    CHECK_BUFFER(in);
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputShrink:
+ * @in:  an XML parser input
+ *
+ * This function removes used input for the parser.
+ */
+void
+xmlParserInputShrink(xmlParserInputPtr in) {
+    int used;
+    int ret;
+    int index;
+
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext, "Shrink\n");
+#endif
+    if (in->buf == NULL) return;
+    if (in->base == NULL) return;
+    if (in->cur == NULL) return;
+    if (in->buf->buffer == NULL) return;
+
+    CHECK_BUFFER(in);
+
+    used = in->cur - in->buf->buffer->content;
+    /*
+     * Do not shrink on large buffers whose only a tiny fraction
+     * was consumned
+     */
+    if (in->buf->buffer->use > used + 2 * INPUT_CHUNK)
+	return;
+    if (used > INPUT_CHUNK) {
+	ret = xmlBufferShrink(in->buf->buffer, used - LINE_LEN);
+	if (ret > 0) {
+	    in->cur -= ret;
+	    in->consumed += ret;
+	}
+    }
+
+    CHECK_BUFFER(in);
+
+    if (in->buf->buffer->use > INPUT_CHUNK) {
+        return;
+    }
+    xmlParserInputBufferRead(in->buf, 2 * INPUT_CHUNK);
+    if (in->base != in->buf->buffer->content) {
+        /*
+	 * the buffer has been realloced
+	 */
+	index = in->cur - in->base;
+	in->base = in->buf->buffer->content;
+	in->cur = &in->buf->buffer->content[index];
+    }
+
+    CHECK_BUFFER(in);
+}
+
+/************************************************************************
+ *									*
+ * 		UTF8 character input and related functions		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlNextChar:
+ * @ctxt:  the XML parser context
+ *
+ * Skip to the next char input char.
+ */
+
+void
+xmlNextChar(xmlParserCtxtPtr ctxt) {
+    if (ctxt->instate == XML_PARSER_EOF)
+	return;
+
+    /*
+     *   2.11 End-of-Line Handling
+     *   the literal two-character sequence "#xD#xA" or a standalone
+     *   literal #xD, an XML processor must pass to the application
+     *   the single character #xA. 
+     */
+    if (ctxt->token != 0) ctxt->token = 0;
+    else if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
+	if ((*ctxt->input->cur == 0) &&
+	    (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0) &&
+	    (ctxt->instate != XML_PARSER_COMMENT)) {
+	        /*
+		 * If we are at the end of the current entity and
+		 * the context allows it, we pop consumed entities
+		 * automatically.
+		 * the auto closing should be blocked in other cases
+		 */
+		xmlPopInput(ctxt);
+	} else {
+	    if (*(ctxt->input->cur) == '\n') {
+		ctxt->input->line++; ctxt->input->col = 1;
+	    } else ctxt->input->col++;
+	    if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
+		/*
+		 * We are supposed to handle UTF8, check it's valid
+		 * From rfc2044: encoding of the Unicode values on UTF-8:
+		 *
+		 * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+		 * 0000 0000-0000 007F   0xxxxxxx
+		 * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+		 * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
+		 *
+		 * Check for the 0x110000 limit too
+		 */
+		const unsigned char *cur = ctxt->input->cur;
+		unsigned char c;
+
+		c = *cur;
+		if (c & 0x80) {
+		    if (cur[1] == 0)
+			xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+		    if ((cur[1] & 0xc0) != 0x80)
+			goto encoding_error;
+		    if ((c & 0xe0) == 0xe0) {
+			unsigned int val;
+
+			if (cur[2] == 0)
+			    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+			if ((cur[2] & 0xc0) != 0x80)
+			    goto encoding_error;
+			if ((c & 0xf0) == 0xf0) {
+			    if (cur[3] == 0)
+				xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+			    if (((c & 0xf8) != 0xf0) ||
+				((cur[3] & 0xc0) != 0x80))
+				goto encoding_error;
+			    /* 4-byte code */
+			    ctxt->input->cur += 4;
+			    val = (cur[0] & 0x7) << 18;
+			    val |= (cur[1] & 0x3f) << 12;
+			    val |= (cur[2] & 0x3f) << 6;
+			    val |= cur[3] & 0x3f;
+			} else {
+			  /* 3-byte code */
+			    ctxt->input->cur += 3;
+			    val = (cur[0] & 0xf) << 12;
+			    val |= (cur[1] & 0x3f) << 6;
+			    val |= cur[2] & 0x3f;
+			}
+			if (((val > 0xd7ff) && (val < 0xe000)) ||
+			    ((val > 0xfffd) && (val < 0x10000)) ||
+			    (val >= 0x110000)) {
+			    if ((ctxt->sax != NULL) &&
+				(ctxt->sax->error != NULL))
+				ctxt->sax->error(ctxt->userData, 
+				 "Char 0x%X out of allowed range\n", val);
+			    ctxt->errNo = XML_ERR_INVALID_ENCODING;
+			    ctxt->wellFormed = 0;
+			    ctxt->disableSAX = 1;
+			}    
+		    } else
+		      /* 2-byte code */
+		        ctxt->input->cur += 2;
+		} else
+		    /* 1-byte code */
+		    ctxt->input->cur++;
+	    } else {
+		/*
+		 * Assume it's a fixed lenght encoding (1) with
+		 * a compatibke encoding for the ASCII set, since
+		 * XML constructs only use < 128 chars
+		 */
+	        ctxt->input->cur++;
+	    }
+	    ctxt->nbChars++;
+	    if (*ctxt->input->cur == 0)
+		xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+	}
+    } else {
+	ctxt->input->cur++;
+	ctxt->nbChars++;
+	if (*ctxt->input->cur == 0)
+	    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+    }
+    if ((*ctxt->input->cur == '%') && (!ctxt->html))
+	xmlParserHandlePEReference(ctxt);
+    if ((*ctxt->input->cur == 0) &&
+        (xmlParserInputGrow(ctxt->input, INPUT_CHUNK) <= 0))
+	    xmlPopInput(ctxt);
+    return;
+encoding_error:
+    /*
+     * If we detect an UTF8 error that probably mean that the
+     * input encoding didn't get properly advertized in the
+     * declaration header. Report the error and switch the encoding
+     * to ISO-Latin-1 (if you don't like this policy, just declare the
+     * encoding !)
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
+	ctxt->sax->error(ctxt->userData, 
+			 "Input is not proper UTF-8, indicate encoding !\n");
+	ctxt->sax->error(ctxt->userData, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+			ctxt->input->cur[0], ctxt->input->cur[1],
+			ctxt->input->cur[2], ctxt->input->cur[3]);
+    }
+    ctxt->errNo = XML_ERR_INVALID_ENCODING;
+
+    ctxt->charset = XML_CHAR_ENCODING_8859_1; 
+    ctxt->input->cur++;
+    return;
+}
+
+/**
+ * xmlCurrentChar:
+ * @ctxt:  the XML parser context
+ * @len:  pointer to the length of the char read
+ *
+ * The current char value, if using UTF-8 this may actaully span multiple
+ * bytes in the input buffer. Implement the end of line normalization:
+ * 2.11 End-of-Line Handling
+ * Wherever an external parsed entity or the literal entity value
+ * of an internal parsed entity contains either the literal two-character
+ * sequence "#xD#xA" or a standalone literal #xD, an XML processor
+ * must pass to the application the single character #xA.
+ * This behavior can conveniently be produced by normalizing all
+ * line breaks to #xA on input, before parsing.)
+ *
+ * Returns the current char value and its lenght
+ */
+
+int
+xmlCurrentChar(xmlParserCtxtPtr ctxt, int *len) {
+    if (ctxt->instate == XML_PARSER_EOF)
+	return(0);
+
+    if (ctxt->token != 0) {
+	*len = 0;
+	return(ctxt->token);
+    }	
+    if ((*ctxt->input->cur >= 0x20) && (*ctxt->input->cur <= 0x7F)) {
+	    *len = 1;
+	    return((int) *ctxt->input->cur);
+    }
+    if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
+	/*
+	 * We are supposed to handle UTF8, check it's valid
+	 * From rfc2044: encoding of the Unicode values on UTF-8:
+	 *
+	 * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+	 * 0000 0000-0000 007F   0xxxxxxx
+	 * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+	 * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
+	 *
+	 * Check for the 0x110000 limit too
+	 */
+	const unsigned char *cur = ctxt->input->cur;
+	unsigned char c;
+	unsigned int val;
+
+	c = *cur;
+	if (c & 0x80) {
+	    if (cur[1] == 0)
+		xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+	    if ((cur[1] & 0xc0) != 0x80)
+		goto encoding_error;
+	    if ((c & 0xe0) == 0xe0) {
+
+		if (cur[2] == 0)
+		    xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+		if ((cur[2] & 0xc0) != 0x80)
+		    goto encoding_error;
+		if ((c & 0xf0) == 0xf0) {
+		    if (cur[3] == 0)
+			xmlParserInputGrow(ctxt->input, INPUT_CHUNK);
+		    if (((c & 0xf8) != 0xf0) ||
+			((cur[3] & 0xc0) != 0x80))
+			goto encoding_error;
+		    /* 4-byte code */
+		    *len = 4;
+		    val = (cur[0] & 0x7) << 18;
+		    val |= (cur[1] & 0x3f) << 12;
+		    val |= (cur[2] & 0x3f) << 6;
+		    val |= cur[3] & 0x3f;
+		} else {
+		  /* 3-byte code */
+		    *len = 3;
+		    val = (cur[0] & 0xf) << 12;
+		    val |= (cur[1] & 0x3f) << 6;
+		    val |= cur[2] & 0x3f;
+		}
+	    } else {
+	      /* 2-byte code */
+		*len = 2;
+		val = (cur[0] & 0x1f) << 6;
+		val |= cur[1] & 0x3f;
+	    }
+	    if (!IS_CHAR(val)) {
+		if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+				     "Char 0x%X out of allowed range\n", val);
+		ctxt->errNo = XML_ERR_INVALID_ENCODING;
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }    
+	    return(val);
+	} else {
+	    /* 1-byte code */
+	    *len = 1;
+	    if (*ctxt->input->cur == 0xD) {
+		if (ctxt->input->cur[1] == 0xA) {
+		    ctxt->nbChars++;
+		    ctxt->input->cur++;
+		}
+		return(0xA);
+	    }
+	    return((int) *ctxt->input->cur);
+	}
+    }
+    /*
+     * Assume it's a fixed lenght encoding (1) with
+     * a compatibke encoding for the ASCII set, since
+     * XML constructs only use < 128 chars
+     */
+    *len = 1;
+    if (*ctxt->input->cur == 0xD) {
+	if (ctxt->input->cur[1] == 0xA) {
+	    ctxt->nbChars++;
+	    ctxt->input->cur++;
+	}
+	return(0xA);
+    }
+    return((int) *ctxt->input->cur);
+encoding_error:
+    /*
+     * If we detect an UTF8 error that probably mean that the
+     * input encoding didn't get properly advertized in the
+     * declaration header. Report the error and switch the encoding
+     * to ISO-Latin-1 (if you don't like this policy, just declare the
+     * encoding !)
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
+	ctxt->sax->error(ctxt->userData, 
+			 "Input is not proper UTF-8, indicate encoding !\n");
+	ctxt->sax->error(ctxt->userData, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+			ctxt->input->cur[0], ctxt->input->cur[1],
+			ctxt->input->cur[2], ctxt->input->cur[3]);
+    }
+    ctxt->errNo = XML_ERR_INVALID_ENCODING;
+
+    ctxt->charset = XML_CHAR_ENCODING_8859_1; 
+    *len = 1;
+    return((int) *ctxt->input->cur);
+}
+
+/**
+ * xmlStringCurrentChar:
+ * @ctxt:  the XML parser context
+ * @cur:  pointer to the beginning of the char
+ * @len:  pointer to the length of the char read
+ *
+ * The current char value, if using UTF-8 this may actaully span multiple
+ * bytes in the input buffer.
+ *
+ * Returns the current char value and its lenght
+ */
+
+int
+xmlStringCurrentChar(xmlParserCtxtPtr ctxt, const xmlChar *cur, int *len) {
+    if (ctxt->charset == XML_CHAR_ENCODING_UTF8) {
+	/*
+	 * We are supposed to handle UTF8, check it's valid
+	 * From rfc2044: encoding of the Unicode values on UTF-8:
+	 *
+	 * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+	 * 0000 0000-0000 007F   0xxxxxxx
+	 * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+	 * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
+	 *
+	 * Check for the 0x110000 limit too
+	 */
+	unsigned char c;
+	unsigned int val;
+
+	c = *cur;
+	if (c & 0x80) {
+	    if ((cur[1] & 0xc0) != 0x80)
+		goto encoding_error;
+	    if ((c & 0xe0) == 0xe0) {
+
+		if ((cur[2] & 0xc0) != 0x80)
+		    goto encoding_error;
+		if ((c & 0xf0) == 0xf0) {
+		    if (((c & 0xf8) != 0xf0) ||
+			((cur[3] & 0xc0) != 0x80))
+			goto encoding_error;
+		    /* 4-byte code */
+		    *len = 4;
+		    val = (cur[0] & 0x7) << 18;
+		    val |= (cur[1] & 0x3f) << 12;
+		    val |= (cur[2] & 0x3f) << 6;
+		    val |= cur[3] & 0x3f;
+		} else {
+		  /* 3-byte code */
+		    *len = 3;
+		    val = (cur[0] & 0xf) << 12;
+		    val |= (cur[1] & 0x3f) << 6;
+		    val |= cur[2] & 0x3f;
+		}
+	    } else {
+	      /* 2-byte code */
+		*len = 2;
+		val = (cur[0] & 0x1f) << 6;
+		val |= cur[2] & 0x3f;
+	    }
+	    if (!IS_CHAR(val)) {
+		if ((ctxt->sax != NULL) &&
+		    (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+				     "Char 0x%X out of allowed range\n", val);
+		ctxt->errNo = XML_ERR_INVALID_ENCODING;
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+	    }    
+	    return(val);
+	} else {
+	    /* 1-byte code */
+	    *len = 1;
+	    return((int) *cur);
+	}
+    }
+    /*
+     * Assume it's a fixed lenght encoding (1) with
+     * a compatibke encoding for the ASCII set, since
+     * XML constructs only use < 128 chars
+     */
+    *len = 1;
+    return((int) *cur);
+encoding_error:
+    /*
+     * If we detect an UTF8 error that probably mean that the
+     * input encoding didn't get properly advertized in the
+     * declaration header. Report the error and switch the encoding
+     * to ISO-Latin-1 (if you don't like this policy, just declare the
+     * encoding !)
+     */
+    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL)) {
+	ctxt->sax->error(ctxt->userData, 
+			 "Input is not proper UTF-8, indicate encoding !\n");
+	ctxt->sax->error(ctxt->userData, "Bytes: 0x%02X 0x%02X 0x%02X 0x%02X\n",
+			ctxt->input->cur[0], ctxt->input->cur[1],
+			ctxt->input->cur[2], ctxt->input->cur[3]);
+    }
+    ctxt->errNo = XML_ERR_INVALID_ENCODING;
+
+    *len = 1;
+    return((int) *cur);
+}
+
+/**
+ * xmlCopyChar:
+ * @len:  pointer to the length of the char read (or zero)
+ * @array:  pointer to an arry of xmlChar
+ * @val:  the char value
+ *
+ * append the char value in the array 
+ *
+ * Returns the number of xmlChar written
+ */
+
+int
+xmlCopyChar(int len, xmlChar *out, int val) {
+    /*
+     * We are supposed to handle UTF8, check it's valid
+     * From rfc2044: encoding of the Unicode values on UTF-8:
+     *
+     * UCS-4 range (hex.)           UTF-8 octet sequence (binary)
+     * 0000 0000-0000 007F   0xxxxxxx
+     * 0000 0080-0000 07FF   110xxxxx 10xxxxxx
+     * 0000 0800-0000 FFFF   1110xxxx 10xxxxxx 10xxxxxx 
+     */
+    if (len == 0) {
+	if (val < 0) len = 0;
+	else if (val < 0x80) len = 1;
+	else if (val < 0x800) len = 2;
+	else if (val < 0x10000) len = 3;
+	else if (val < 0x110000) len = 4;
+	if (len == 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Internal error, xmlCopyChar 0x%X out of bound\n",
+		    val);
+	    return(0);
+	}
+    }
+    if (len > 1) {
+	int bits; 
+
+        if      (val <    0x80) {  *out++=  val;                bits= -6; }
+        else if (val <   0x800) {  *out++= (val >>  6) | 0xC0;  bits=  0; }
+        else if (val < 0x10000) {  *out++= (val >> 12) | 0xE0;  bits=  6; }
+        else                  {    *out++= (val >> 18) | 0xF0;  bits= 12; }
+ 
+        for ( ; bits >= 0; bits-= 6)
+            *out++= ((val >> bits) & 0x3F) | 0x80 ;
+
+        return(len);
+    }
+    *out = (xmlChar) val;
+    return(1);
+}
+
+/************************************************************************
+ *									*
+ *		Commodity functions to switch encodings			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSwitchEncoding:
+ * @ctxt:  the parser context
+ * @enc:  the encoding value (number)
+ *
+ * change the input functions when discovering the character encoding
+ * of a given entity.
+ *
+ * Returns 0 in case of success, -1 otherwise
+ */
+int
+xmlSwitchEncoding(xmlParserCtxtPtr ctxt, xmlCharEncoding enc)
+{
+    xmlCharEncodingHandlerPtr handler;
+
+    switch (enc) {
+	case XML_CHAR_ENCODING_ERROR:
+	    ctxt->errNo = XML_ERR_UNKNOWN_ENCODING;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, "encoding unknown\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    break;
+	case XML_CHAR_ENCODING_NONE:
+	    /* let's assume it's UTF-8 without the XML decl */
+	    ctxt->charset = XML_CHAR_ENCODING_UTF8;
+	    return(0);
+	case XML_CHAR_ENCODING_UTF8:
+	    /* default encoding, no conversion should be needed */
+	    ctxt->charset = XML_CHAR_ENCODING_UTF8;
+	    return(0);
+	default:
+	    break;
+    }
+    handler = xmlGetCharEncodingHandler(enc);
+    if (handler == NULL) {
+	/*
+	 * Default handlers.
+	 */
+	switch (enc) {
+	    case XML_CHAR_ENCODING_ERROR:
+		ctxt->errNo = XML_ERR_UNKNOWN_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, "encoding unknown\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		ctxt->charset = XML_CHAR_ENCODING_UTF8;
+		break;
+	    case XML_CHAR_ENCODING_NONE:
+		/* let's assume it's UTF-8 without the XML decl */
+		ctxt->charset = XML_CHAR_ENCODING_UTF8;
+		return(0);
+	    case XML_CHAR_ENCODING_UTF8:
+	    case XML_CHAR_ENCODING_ASCII:
+		/* default encoding, no conversion should be needed */
+		ctxt->charset = XML_CHAR_ENCODING_UTF8;
+		return(0);
+	    case XML_CHAR_ENCODING_UTF16LE:
+		break;
+	    case XML_CHAR_ENCODING_UTF16BE:
+		break;
+	    case XML_CHAR_ENCODING_UCS4LE:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding USC4 little endian not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_UCS4BE:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding USC4 big endian not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_EBCDIC:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding EBCDIC not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_UCS4_2143:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding UCS4 2143 not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_UCS4_3412:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding UCS4 3412 not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_UCS2:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding UCS2 not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_8859_1:
+	    case XML_CHAR_ENCODING_8859_2:
+	    case XML_CHAR_ENCODING_8859_3:
+	    case XML_CHAR_ENCODING_8859_4:
+	    case XML_CHAR_ENCODING_8859_5:
+	    case XML_CHAR_ENCODING_8859_6:
+	    case XML_CHAR_ENCODING_8859_7:
+	    case XML_CHAR_ENCODING_8859_8:
+	    case XML_CHAR_ENCODING_8859_9:
+		/*
+		 * We used to keep the internal content in the
+		 * document encoding however this turns being unmaintainable
+		 * So xmlGetCharEncodingHandler() will return non-null
+		 * values for this now.
+		 */
+		if ((ctxt->inputNr == 1) &&
+		    (ctxt->encoding == NULL) &&
+		    (ctxt->input->encoding != NULL)) {
+		    ctxt->encoding = xmlStrdup(ctxt->input->encoding);
+		}
+		ctxt->charset = enc;
+		return(0);
+	    case XML_CHAR_ENCODING_2022_JP:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding ISO-2022-JPnot supported\n");
+		break;
+	    case XML_CHAR_ENCODING_SHIFT_JIS:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding Shift_JIS not supported\n");
+		break;
+	    case XML_CHAR_ENCODING_EUC_JP:
+		ctxt->errNo = XML_ERR_UNSUPPORTED_ENCODING;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "char encoding EUC-JPnot supported\n");
+		break;
+	}
+    }
+    if (handler == NULL)
+	return(-1);
+    ctxt->charset = XML_CHAR_ENCODING_UTF8;
+    return(xmlSwitchToEncoding(ctxt, handler));
+}
+
+/**
+ * xmlSwitchToEncoding:
+ * @ctxt:  the parser context
+ * @handler:  the encoding handler
+ *
+ * change the input functions when discovering the character encoding
+ * of a given entity.
+ *
+ * Returns 0 in case of success, -1 otherwise
+ */
+int
+xmlSwitchToEncoding(xmlParserCtxtPtr ctxt, xmlCharEncodingHandlerPtr handler) 
+{
+    int nbchars;
+
+    if (handler != NULL) {
+        if (ctxt->input != NULL) {
+	    if (ctxt->input->buf != NULL) {
+	        if (ctxt->input->buf->encoder != NULL) {
+		    if (ctxt->input->buf->encoder == handler)
+			return(0);
+		    /*
+		     * Note: this is a bit dangerous, but that's what it
+		     * takes to use nearly compatible signature for different
+		     * encodings.
+		     */
+		    xmlCharEncCloseFunc(ctxt->input->buf->encoder);
+		    ctxt->input->buf->encoder = handler;
+		    return(0);
+		}
+		ctxt->input->buf->encoder = handler;
+
+	        /*
+		 * Is there already some content down the pipe to convert ?
+		 */
+	        if ((ctxt->input->buf->buffer != NULL) &&
+		    (ctxt->input->buf->buffer->use > 0)) {
+		    int processed;
+
+		    /*
+		     * Specific handling of the Byte Order Mark for 
+		     * UTF-16
+		     */
+		    if ((handler->name != NULL) &&
+			(!strcmp(handler->name, "UTF-16LE")) && 
+		        (ctxt->input->cur[0] == 0xFF) &&
+		        (ctxt->input->cur[1] == 0xFE)) {
+			ctxt->input->cur += 2;
+		    }
+		    if ((handler->name != NULL) &&
+			(!strcmp(handler->name, "UTF-16BE")) && 
+		        (ctxt->input->cur[0] == 0xFE) &&
+		        (ctxt->input->cur[1] == 0xFF)) {
+			ctxt->input->cur += 2;
+		    }
+
+		    /*
+		     * Shring the current input buffer.
+		     * Move it as the raw buffer and create a new input buffer
+		     */
+		    processed = ctxt->input->cur - ctxt->input->base;
+		    xmlBufferShrink(ctxt->input->buf->buffer, processed);
+		    ctxt->input->buf->raw = ctxt->input->buf->buffer;
+		    ctxt->input->buf->buffer = xmlBufferCreate();
+
+		    if (ctxt->html) {
+			/*
+			 * converst as much as possbile of the buffer
+			 */
+			nbchars = xmlCharEncInFunc(ctxt->input->buf->encoder,
+				                   ctxt->input->buf->buffer,
+						   ctxt->input->buf->raw);
+		    } else {
+			/*
+			 * convert just enough to get
+			 * '<?xml version="1.0" encoding="xxx"?>'
+			 * parsed with the autodetected encoding
+			 * into the parser reading buffer.
+			 */
+			nbchars = xmlCharEncFirstLine(ctxt->input->buf->encoder,
+						      ctxt->input->buf->buffer,
+						      ctxt->input->buf->raw);
+		    }
+		    if (nbchars < 0) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSwitchToEncoding: encoder error\n");
+			return(-1);
+		    }
+		    ctxt->input->base =
+		    ctxt->input->cur = ctxt->input->buf->buffer->content;
+
+		}
+		return(0);
+	    } else {
+	        if ((ctxt->input->length == 0) || (ctxt->input->buf == NULL)) {
+		    /*
+		     * When parsing a static memory array one must know the
+		     * size to be able to convert the buffer.
+		     */
+		    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+			ctxt->sax->error(ctxt->userData,
+					 "xmlSwitchEncoding : no input\n");
+		    return(-1);
+		} else {
+		    int processed;
+
+		    /*
+		     * Shring the current input buffer.
+		     * Move it as the raw buffer and create a new input buffer
+		     */
+		    processed = ctxt->input->cur - ctxt->input->base;
+
+		    ctxt->input->buf->raw = xmlBufferCreate();
+		    xmlBufferAdd(ctxt->input->buf->raw, ctxt->input->cur,
+				 ctxt->input->length - processed);
+		    ctxt->input->buf->buffer = xmlBufferCreate();
+
+		    /*
+		     * convert as much as possible of the raw input
+		     * to the parser reading buffer.
+		     */
+		    nbchars = xmlCharEncInFunc(ctxt->input->buf->encoder,
+		                               ctxt->input->buf->buffer,
+					       ctxt->input->buf->raw);
+		    if (nbchars < 0) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSwitchToEncoding: encoder error\n");
+			return(-1);
+		    }
+
+		    /*
+		     * Conversion succeeded, get rid of the old buffer
+		     */
+		    if ((ctxt->input->free != NULL) &&
+		        (ctxt->input->base != NULL))
+			ctxt->input->free((xmlChar *) ctxt->input->base);
+		    ctxt->input->base =
+		    ctxt->input->cur = ctxt->input->buf->buffer->content;
+		}
+	    }
+	} else {
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+		                 "xmlSwitchEncoding : no input\n");
+	    return(-1);
+	}
+	/*
+	 * The parsing is now done in UTF8 natively
+	 */
+	ctxt->charset = XML_CHAR_ENCODING_UTF8;
+    } else 
+	return(-1);
+    return(0);
+
+}
+
+/************************************************************************
+ *									*
+ *	Commodity functions to handle entities processing		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlFreeInputStream:
+ * @input:  an xmlParserInputPtr
+ *
+ * Free up an input stream.
+ */
+void
+xmlFreeInputStream(xmlParserInputPtr input) {
+    if (input == NULL) return;
+
+    if (input->filename != NULL) xmlFree((char *) input->filename);
+    if (input->directory != NULL) xmlFree((char *) input->directory);
+    if (input->encoding != NULL) xmlFree((char *) input->encoding);
+    if (input->version != NULL) xmlFree((char *) input->version);
+    if ((input->free != NULL) && (input->base != NULL))
+        input->free((xmlChar *) input->base);
+    if (input->buf != NULL) 
+        xmlFreeParserInputBuffer(input->buf);
+    memset(input, -1, sizeof(xmlParserInput));
+    xmlFree(input);
+}
+
+/**
+ * xmlNewInputStream:
+ * @ctxt:  an XML parser context
+ *
+ * Create a new input stream structure
+ * Returns the new input stream or NULL
+ */
+xmlParserInputPtr
+xmlNewInputStream(xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr input;
+
+    input = (xmlParserInputPtr) xmlMalloc(sizeof(xmlParserInput));
+    if (input == NULL) {
+	if (ctxt != NULL) {
+	    ctxt->errNo = XML_ERR_NO_MEMORY;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+			 "malloc: couldn't allocate a new input stream\n");
+	    ctxt->errNo = XML_ERR_NO_MEMORY;
+	}
+	return(NULL);
+    }
+    memset(input, 0, sizeof(xmlParserInput));
+    input->line = 1;
+    input->col = 1;
+    input->standalone = -1;
+    return(input);
+}
+
+/**
+ * xmlNewIOInputStream:
+ * @ctxt:  an XML parser context
+ * @input:  an I/O Input
+ * @enc:  the charset encoding if known
+ *
+ * Create a new input stream structure encapsulating the @input into
+ * a stream suitable for the parser.
+ *
+ * Returns the new input stream or NULL
+ */
+xmlParserInputPtr
+xmlNewIOInputStream(xmlParserCtxtPtr ctxt, xmlParserInputBufferPtr input,
+	            xmlCharEncoding enc) {
+    xmlParserInputPtr inputStream;
+
+    if (xmlParserDebugEntities)
+	xmlGenericError(xmlGenericErrorContext, "new input from I/O\n");
+    inputStream = xmlNewInputStream(ctxt);
+    if (inputStream == NULL) {
+	return(NULL);
+    }
+    inputStream->filename = NULL;
+    inputStream->buf = input;
+    inputStream->base = inputStream->buf->buffer->content;
+    inputStream->cur = inputStream->buf->buffer->content;
+    if (enc != XML_CHAR_ENCODING_NONE) {
+        xmlSwitchEncoding(ctxt, enc);
+    }
+
+    return(inputStream);
+}
+
+/**
+ * xmlNewEntityInputStream:
+ * @ctxt:  an XML parser context
+ * @entity:  an Entity pointer
+ *
+ * Create a new input stream based on an xmlEntityPtr
+ *
+ * Returns the new input stream or NULL
+ */
+xmlParserInputPtr
+xmlNewEntityInputStream(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
+    xmlParserInputPtr input;
+
+    if (entity == NULL) {
+        ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	      "internal: xmlNewEntityInputStream entity = NULL\n");
+	ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+	return(NULL);
+    }
+    if (xmlParserDebugEntities)
+	xmlGenericError(xmlGenericErrorContext,
+		"new input from entity: %s\n", entity->name);
+    if (entity->content == NULL) {
+	switch (entity->etype) {
+            case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
+	        ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		      "xmlNewEntityInputStream unparsed entity !\n");
+                break;
+            case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
+            case XML_EXTERNAL_PARAMETER_ENTITY:
+		return(xmlLoadExternalEntity((char *) entity->URI,
+		       (char *) entity->ExternalID, ctxt));
+            case XML_INTERNAL_GENERAL_ENTITY:
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+	  "Internal entity %s without content !\n", entity->name);
+                break;
+            case XML_INTERNAL_PARAMETER_ENTITY:
+		ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+	  "Internal parameter entity %s without content !\n", entity->name);
+                break;
+            case XML_INTERNAL_PREDEFINED_ENTITY:
+		ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+	      "Predefined entity %s without content !\n", entity->name);
+                break;
+	}
+	return(NULL);
+    }
+    input = xmlNewInputStream(ctxt);
+    if (input == NULL) {
+	return(NULL);
+    }
+    input->filename = (char *) entity->URI;
+    input->base = entity->content;
+    input->cur = entity->content;
+    input->length = entity->length;
+    return(input);
+}
+
+/**
+ * xmlNewStringInputStream:
+ * @ctxt:  an XML parser context
+ * @buffer:  an memory buffer
+ *
+ * Create a new input stream based on a memory buffer.
+ * Returns the new input stream
+ */
+xmlParserInputPtr
+xmlNewStringInputStream(xmlParserCtxtPtr ctxt, const xmlChar *buffer) {
+    xmlParserInputPtr input;
+
+    if (buffer == NULL) {
+	ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+	      "internal: xmlNewStringInputStream string = NULL\n");
+	return(NULL);
+    }
+    if (xmlParserDebugEntities)
+	xmlGenericError(xmlGenericErrorContext,
+		"new fixed input: %.30s\n", buffer);
+    input = xmlNewInputStream(ctxt);
+    if (input == NULL) {
+	return(NULL);
+    }
+    input->base = buffer;
+    input->cur = buffer;
+    input->length = xmlStrlen(buffer);
+    return(input);
+}
+
+/**
+ * xmlNewInputFromFile:
+ * @ctxt:  an XML parser context
+ * @filename:  the filename to use as entity
+ *
+ * Create a new input stream based on a file.
+ *
+ * Returns the new input stream or NULL in case of error
+ */
+xmlParserInputPtr
+xmlNewInputFromFile(xmlParserCtxtPtr ctxt, const char *filename) {
+    xmlParserInputBufferPtr buf;
+    xmlParserInputPtr inputStream;
+    char *directory = NULL;
+    xmlChar *URI = NULL;
+
+    if (xmlParserDebugEntities)
+	xmlGenericError(xmlGenericErrorContext,
+		"new input from file: %s\n", filename);
+    if (ctxt == NULL) return(NULL);
+    buf = xmlParserInputBufferCreateFilename(filename, XML_CHAR_ENCODING_NONE);
+    if (buf == NULL)
+	return(NULL);
+
+    URI = xmlStrdup((xmlChar *) filename);
+    directory = xmlParserGetDirectory((const char *) URI);
+
+    inputStream = xmlNewInputStream(ctxt);
+    if (inputStream == NULL) {
+	if (directory != NULL) xmlFree((char *) directory);
+	if (URI != NULL) xmlFree((char *) URI);
+	return(NULL);
+    }
+
+    inputStream->filename = (const char *) URI;
+    inputStream->directory = directory;
+    inputStream->buf = buf;
+
+    inputStream->base = inputStream->buf->buffer->content;
+    inputStream->cur = inputStream->buf->buffer->content;
+    if ((ctxt->directory == NULL) && (directory != NULL))
+        ctxt->directory = (char *) xmlStrdup((const xmlChar *) directory);
+    return(inputStream);
+}
+
+/************************************************************************
+ *									*
+ *		Commodity functions to handle parser contexts		*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlInitParserCtxt:
+ * @ctxt:  an XML parser context
+ *
+ * Initialize a parser context
+ */
+
+void
+xmlInitParserCtxt(xmlParserCtxtPtr ctxt)
+{
+    xmlSAXHandler *sax;
+
+    xmlDefaultSAXHandlerInit();
+
+    sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
+    if (sax == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlInitParserCtxt: out of memory\n");
+    }
+    else
+        memset(sax, 0, sizeof(xmlSAXHandler));
+
+    /* Allocate the Input stack */
+    ctxt->inputTab = (xmlParserInputPtr *)
+	        xmlMalloc(5 * sizeof(xmlParserInputPtr));
+    if (ctxt->inputTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlInitParserCtxt: out of memory\n");
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	return;
+    }
+    ctxt->inputNr = 0;
+    ctxt->inputMax = 5;
+    ctxt->input = NULL;
+
+    ctxt->version = NULL;
+    ctxt->encoding = NULL;
+    ctxt->standalone = -1;
+    ctxt->hasExternalSubset = 0;
+    ctxt->hasPErefs = 0;
+    ctxt->html = 0;
+    ctxt->external = 0;
+    ctxt->instate = XML_PARSER_START;
+    ctxt->token = 0;
+    ctxt->directory = NULL;
+
+    /* Allocate the Node stack */
+    ctxt->nodeTab = (xmlNodePtr *) xmlMalloc(10 * sizeof(xmlNodePtr));
+    if (ctxt->nodeTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlInitParserCtxt: out of memory\n");
+	ctxt->nodeNr = 0;
+	ctxt->nodeMax = 0;
+	ctxt->node = NULL;
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	return;
+    }
+    ctxt->nodeNr = 0;
+    ctxt->nodeMax = 10;
+    ctxt->node = NULL;
+
+    /* Allocate the Name stack */
+    ctxt->nameTab = (xmlChar **) xmlMalloc(10 * sizeof(xmlChar *));
+    if (ctxt->nameTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlInitParserCtxt: out of memory\n");
+	ctxt->nodeNr = 0;
+	ctxt->nodeMax = 0;
+	ctxt->node = NULL;
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	ctxt->nameNr = 0;
+	ctxt->nameMax = 0;
+	ctxt->name = NULL;
+	return;
+    }
+    ctxt->nameNr = 0;
+    ctxt->nameMax = 10;
+    ctxt->name = NULL;
+
+    /* Allocate the space stack */
+    ctxt->spaceTab = (int *) xmlMalloc(10 * sizeof(int));
+    if (ctxt->spaceTab == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlInitParserCtxt: out of memory\n");
+	ctxt->nodeNr = 0;
+	ctxt->nodeMax = 0;
+	ctxt->node = NULL;
+	ctxt->inputNr = 0;
+	ctxt->inputMax = 0;
+	ctxt->input = NULL;
+	ctxt->nameNr = 0;
+	ctxt->nameMax = 0;
+	ctxt->name = NULL;
+	ctxt->spaceNr = 0;
+	ctxt->spaceMax = 0;
+	ctxt->space = NULL;
+	return;
+    }
+    ctxt->spaceNr = 1;
+    ctxt->spaceMax = 10;
+    ctxt->spaceTab[0] = -1;
+    ctxt->space = &ctxt->spaceTab[0];
+
+    if (sax == NULL) {
+	ctxt->sax = &xmlDefaultSAXHandler;
+    } else {
+        ctxt->sax = sax;
+	memcpy(sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
+    }
+    ctxt->userData = ctxt;
+    ctxt->myDoc = NULL;
+    ctxt->wellFormed = 1;
+    ctxt->valid = 1;
+    ctxt->loadsubset = xmlLoadExtDtdDefaultValue;
+    ctxt->validate = xmlDoValidityCheckingDefaultValue;
+    ctxt->pedantic = xmlPedanticParserDefaultValue;
+    ctxt->keepBlanks = xmlKeepBlanksDefaultValue;
+    ctxt->vctxt.userData = ctxt;
+    if (ctxt->validate) {
+	ctxt->vctxt.error = xmlParserValidityError;
+	if (xmlGetWarningsDefaultValue == 0)
+	    ctxt->vctxt.warning = NULL;
+	else
+	    ctxt->vctxt.warning = xmlParserValidityWarning;
+	/* Allocate the Node stack */
+	ctxt->vctxt.nodeTab = (xmlNodePtr *) xmlMalloc(4 * sizeof(xmlNodePtr));
+	if (ctxt->vctxt.nodeTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlInitParserCtxt: out of memory\n");
+	    ctxt->vctxt.nodeMax = 0;
+	    ctxt->validate = 0;
+	    ctxt->vctxt.error = NULL;
+	    ctxt->vctxt.warning = NULL;
+	} else {
+	    ctxt->vctxt.nodeNr = 0;
+	    ctxt->vctxt.nodeMax = 4;
+	    ctxt->vctxt.node = NULL;
+	}
+    } else {
+	ctxt->vctxt.error = NULL;
+	ctxt->vctxt.warning = NULL;
+    }
+    ctxt->replaceEntities = xmlSubstituteEntitiesDefaultValue;
+    ctxt->record_info = 0;
+    ctxt->nbChars = 0;
+    ctxt->checkIndex = 0;
+    ctxt->inSubset = 0;
+    ctxt->errNo = XML_ERR_OK;
+    ctxt->depth = 0;
+    ctxt->charset = XML_CHAR_ENCODING_UTF8;
+    xmlInitNodeInfoSeq(&ctxt->node_seq);
+}
+
+/**
+ * xmlFreeParserCtxt:
+ * @ctxt:  an XML parser context
+ *
+ * Free all the memory used by a parser context. However the parsed
+ * document in ctxt->myDoc is not freed.
+ */
+
+void
+xmlFreeParserCtxt(xmlParserCtxtPtr ctxt)
+{
+    xmlParserInputPtr input;
+    xmlChar *oldname;
+
+    if (ctxt == NULL) return;
+
+    while ((input = inputPop(ctxt)) != NULL) { /* Non consuming */
+        xmlFreeInputStream(input);
+    }
+    while ((oldname = namePop(ctxt)) != NULL) { /* Non consuming */
+	xmlFree(oldname);
+    }
+    if (ctxt->spaceTab != NULL) xmlFree(ctxt->spaceTab);
+    if (ctxt->nameTab != NULL) xmlFree(ctxt->nameTab);
+    if (ctxt->nodeTab != NULL) xmlFree(ctxt->nodeTab);
+    if (ctxt->inputTab != NULL) xmlFree(ctxt->inputTab);
+    if (ctxt->version != NULL) xmlFree((char *) ctxt->version);
+    if (ctxt->encoding != NULL) xmlFree((char *) ctxt->encoding);
+    if (ctxt->intSubName != NULL) xmlFree((char *) ctxt->intSubName);
+    if (ctxt->extSubURI != NULL) xmlFree((char *) ctxt->extSubURI);
+    if (ctxt->extSubSystem != NULL) xmlFree((char *) ctxt->extSubSystem);
+    if (ctxt->vctxt.nodeTab != NULL) xmlFree(ctxt->vctxt.nodeTab);
+    if ((ctxt->sax != NULL) && (ctxt->sax != &xmlDefaultSAXHandler))
+        xmlFree(ctxt->sax);
+    if (ctxt->directory != NULL) xmlFree((char *) ctxt->directory);
+    xmlFree(ctxt);
+}
+
+/**
+ * xmlNewParserCtxt:
+ *
+ * Allocate and initialize a new parser context.
+ *
+ * Returns the xmlParserCtxtPtr or NULL
+ */
+
+xmlParserCtxtPtr
+xmlNewParserCtxt()
+{
+    xmlParserCtxtPtr ctxt;
+
+    ctxt = (xmlParserCtxtPtr) xmlMalloc(sizeof(xmlParserCtxt));
+    if (ctxt == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewParserCtxt : cannot allocate context\n");
+        perror("malloc");
+	return(NULL);
+    }
+    memset(ctxt, 0, sizeof(xmlParserCtxt));
+    xmlInitParserCtxt(ctxt);
+    return(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *		Handling of node informations				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlClearParserCtxt:
+ * @ctxt:  an XML parser context
+ *
+ * Clear (release owned resources) and reinitialize a parser context
+ */
+
+void
+xmlClearParserCtxt(xmlParserCtxtPtr ctxt)
+{
+  xmlClearNodeInfoSeq(&ctxt->node_seq);
+  xmlInitParserCtxt(ctxt);
+}
+
+/**
+ * xmlParserFindNodeInfo:
+ * @ctxt:  an XML parser context
+ * @node:  an XML node within the tree
+ *
+ * Find the parser node info struct for a given node
+ * 
+ * Returns an xmlParserNodeInfo block pointer or NULL
+ */
+const xmlParserNodeInfo* xmlParserFindNodeInfo(const xmlParserCtxt* ctx,
+                                               const xmlNode* node)
+{
+  unsigned long pos;
+
+  /* Find position where node should be at */
+  pos = xmlParserFindNodeInfoIndex(&ctx->node_seq, node);
+  if ( ctx->node_seq.buffer[pos].node == node )
+    return &ctx->node_seq.buffer[pos];
+  else
+    return NULL;
+}
+
+
+/**
+ * xmlInitNodeInfoSeq:
+ * @seq:  a node info sequence pointer
+ *
+ * -- Initialize (set to initial state) node info sequence
+ */
+void
+xmlInitNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
+{
+  seq->length = 0;
+  seq->maximum = 0;
+  seq->buffer = NULL;
+}
+
+/**
+ * xmlClearNodeInfoSeq:
+ * @seq:  a node info sequence pointer
+ *
+ * -- Clear (release memory and reinitialize) node
+ *   info sequence
+ */
+void
+xmlClearNodeInfoSeq(xmlParserNodeInfoSeqPtr seq)
+{
+  if ( seq->buffer != NULL )
+    xmlFree(seq->buffer);
+  xmlInitNodeInfoSeq(seq);
+}
+
+
+/**
+ * xmlParserFindNodeInfoIndex:
+ * @seq:  a node info sequence pointer
+ * @node:  an XML node pointer
+ *
+ * 
+ * xmlParserFindNodeInfoIndex : Find the index that the info record for
+ *   the given node is or should be at in a sorted sequence
+ *
+ * Returns a long indicating the position of the record
+ */
+unsigned long xmlParserFindNodeInfoIndex(const xmlParserNodeInfoSeq* seq,
+                                         const xmlNode* node)
+{
+  unsigned long upper, lower, middle;
+  int found = 0;
+
+  /* Do a binary search for the key */
+  lower = 1;
+  upper = seq->length;
+  middle = 0;
+  while ( lower <= upper && !found) {
+    middle = lower + (upper - lower) / 2;
+    if ( node == seq->buffer[middle - 1].node )
+      found = 1;
+    else if ( node < seq->buffer[middle - 1].node )
+      upper = middle - 1;
+    else
+      lower = middle + 1;
+  }
+
+  /* Return position */
+  if ( middle == 0 || seq->buffer[middle - 1].node < node )
+    return middle;
+  else 
+    return middle - 1;
+}
+
+
+/**
+ * xmlParserAddNodeInfo:
+ * @ctxt:  an XML parser context
+ * @info:  a node info sequence pointer
+ *
+ * Insert node info record into the sorted sequence
+ */
+void
+xmlParserAddNodeInfo(xmlParserCtxtPtr ctxt, 
+                     const xmlParserNodeInfo* info)
+{
+  unsigned long pos;
+  static unsigned int block_size = 5;
+
+  /* Find pos and check to see if node is already in the sequence */
+  pos = xmlParserFindNodeInfoIndex(&ctxt->node_seq, info->node);
+  if ( pos < ctxt->node_seq.length
+       && ctxt->node_seq.buffer[pos].node == info->node ) {
+    ctxt->node_seq.buffer[pos] = *info;
+  }
+
+  /* Otherwise, we need to add new node to buffer */
+  else {
+    /* Expand buffer by 5 if needed */
+    if ( ctxt->node_seq.length + 1 > ctxt->node_seq.maximum ) {
+      xmlParserNodeInfo* tmp_buffer;
+      unsigned int byte_size = (sizeof(*ctxt->node_seq.buffer)
+                                *(ctxt->node_seq.maximum + block_size));
+
+      if ( ctxt->node_seq.buffer == NULL )
+        tmp_buffer = (xmlParserNodeInfo*) xmlMalloc(byte_size);
+      else 
+        tmp_buffer = (xmlParserNodeInfo*) xmlRealloc(ctxt->node_seq.buffer, byte_size);
+
+      if ( tmp_buffer == NULL ) {
+        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Out of memory\n");
+	ctxt->errNo = XML_ERR_NO_MEMORY;
+        return;
+      }
+      ctxt->node_seq.buffer = tmp_buffer;
+      ctxt->node_seq.maximum += block_size;
+    }
+
+    /* If position is not at end, move elements out of the way */
+    if ( pos != ctxt->node_seq.length ) {
+      unsigned long i;
+
+      for ( i = ctxt->node_seq.length; i > pos; i-- )
+        ctxt->node_seq.buffer[i] = ctxt->node_seq.buffer[i - 1];
+    }
+  
+    /* Copy element and increase length */
+    ctxt->node_seq.buffer[pos] = *info;
+    ctxt->node_seq.length++;
+  }   
+}
+
+/************************************************************************
+ *									*
+ *		Deprecated functions kept for compatibility		*
+ *									*
+ ************************************************************************/
+
+/*
+ * xmlCheckLanguageID
+ * @lang:  pointer to the string value
+ *
+ * Checks that the value conforms to the LanguageID production:
+ *
+ * NOTE: this is somewhat deprecated, those productions were removed from
+ *       the XML Second edition.
+ *
+ * [33] LanguageID ::= Langcode ('-' Subcode)*
+ * [34] Langcode ::= ISO639Code |  IanaCode |  UserCode
+ * [35] ISO639Code ::= ([a-z] | [A-Z]) ([a-z] | [A-Z])
+ * [36] IanaCode ::= ('i' | 'I') '-' ([a-z] | [A-Z])+
+ * [37] UserCode ::= ('x' | 'X') '-' ([a-z] | [A-Z])+
+ * [38] Subcode ::= ([a-z] | [A-Z])+
+ *
+ * Returns 1 if correct 0 otherwise
+ **/
+int
+xmlCheckLanguageID(const xmlChar *lang) {
+    const xmlChar *cur = lang;
+
+    if (cur == NULL)
+	return(0);
+    if (((cur[0] == 'i') && (cur[1] == '-')) ||
+	((cur[0] == 'I') && (cur[1] == '-'))) {
+	/*
+	 * IANA code
+	 */
+	cur += 2;
+        while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */
+	       ((cur[0] >= 'a') && (cur[0] <= 'z')))
+	    cur++;
+    } else if (((cur[0] == 'x') && (cur[1] == '-')) ||
+	       ((cur[0] == 'X') && (cur[1] == '-'))) {
+	/*
+	 * User code
+	 */
+	cur += 2;
+        while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */
+	       ((cur[0] >= 'a') && (cur[0] <= 'z')))
+	    cur++;
+    } else if (((cur[0] >= 'A') && (cur[0] <= 'Z')) ||
+	       ((cur[0] >= 'a') && (cur[0] <= 'z'))) {
+	/*
+	 * ISO639
+	 */
+	cur++;
+        if (((cur[0] >= 'A') && (cur[0] <= 'Z')) ||
+	    ((cur[0] >= 'a') && (cur[0] <= 'z')))
+	    cur++;
+	else
+	    return(0);
+    } else
+	return(0);
+    while (cur[0] != 0) { /* non input consuming */
+	if (cur[0] != '-')
+	    return(0);
+	cur++;
+        if (((cur[0] >= 'A') && (cur[0] <= 'Z')) ||
+	    ((cur[0] >= 'a') && (cur[0] <= 'z')))
+	    cur++;
+	else
+	    return(0);
+        while (((cur[0] >= 'A') && (cur[0] <= 'Z')) || /* non input consuming */
+	       ((cur[0] >= 'a') && (cur[0] <= 'z')))
+	    cur++;
+    }
+    return(1);
+}
+
+/**
+ * xmlDecodeEntities:
+ * @ctxt:  the parser context
+ * @what:  combination of XML_SUBSTITUTE_REF and XML_SUBSTITUTE_PEREF
+ * @len:  the len to decode (in bytes !), -1 for no size limit
+ * @end:  an end marker xmlChar, 0 if none
+ * @end2:  an end marker xmlChar, 0 if none
+ * @end3:  an end marker xmlChar, 0 if none
+ * 
+ * This function is deprecated, we now always process entities content
+ * through xmlStringDecodeEntities
+ *
+ * TODO: remove it in next major release.
+ *
+ * [67] Reference ::= EntityRef | CharRef
+ *
+ * [69] PEReference ::= '%' Name ';'
+ *
+ * Returns A newly allocated string with the substitution done. The caller
+ *      must deallocate it !
+ */
+xmlChar *
+xmlDecodeEntities(xmlParserCtxtPtr ctxt, int len, int what,
+                  xmlChar end, xmlChar  end2, xmlChar end3) {
+#if 0
+    xmlChar *buffer = NULL;
+    unsigned int buffer_size = 0;
+    unsigned int nbchars = 0;
+
+    xmlChar *current = NULL;
+    xmlEntityPtr ent;
+    unsigned int max = (unsigned int) len;
+    int c,l;
+#endif
+
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlDecodeEntities() deprecated function reached\n");
+	deprecated = 1;
+    }
+
+#if 0
+    if (ctxt->depth > 40) {
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData,
+		"Detected entity reference loop\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	ctxt->errNo = XML_ERR_ENTITY_LOOP;
+	return(NULL);
+    }
+
+    /*
+     * allocate a translation buffer.
+     */
+    buffer_size = XML_PARSER_BIG_BUFFER_SIZE;
+    buffer = (xmlChar *) xmlMalloc(buffer_size * sizeof(xmlChar));
+    if (buffer == NULL) {
+	perror("xmlDecodeEntities: malloc failed");
+	return(NULL);
+    }
+
+    /*
+     * Ok loop until we reach one of the ending char or a size limit.
+     */
+    GROW;
+    c = CUR_CHAR(l);
+    while ((nbchars < max) && (c != end) && /* NOTUSED */
+           (c != end2) && (c != end3)) {
+	GROW;
+	if (c == 0) break;
+        if (((c == '&') && (ctxt->token != '&')) && (NXT(1) == '#')) {
+	    int val = xmlParseCharRef(ctxt);
+	    COPY_BUF(0,buffer,nbchars,val);
+	    NEXTL(l);
+	} else if ((c == '&') && (ctxt->token != '&') &&
+		   (what & XML_SUBSTITUTE_REF)) {
+	    if (xmlParserDebugEntities)
+		xmlGenericError(xmlGenericErrorContext,
+			"decoding Entity Reference\n");
+	    ent = xmlParseEntityRef(ctxt);
+	    if ((ent != NULL) && 
+		(ctxt->replaceEntities != 0)) {
+		current = ent->content;
+		while (*current != 0) { /* non input consuming loop */
+		    buffer[nbchars++] = *current++;
+		    if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) {
+			growBuffer(buffer);
+		    }
+		}
+	    } else if (ent != NULL) {
+		const xmlChar *cur = ent->name;
+
+		buffer[nbchars++] = '&';
+		if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) {
+		    growBuffer(buffer);
+		}
+		while (*cur != 0) { /* non input consuming loop */
+		    buffer[nbchars++] = *cur++;
+		}
+		buffer[nbchars++] = ';';
+	    }
+	} else if (c == '%' && (what & XML_SUBSTITUTE_PEREF)) {
+	    /*
+	     * a PEReference induce to switch the entity flow,
+	     * we break here to flush the current set of chars
+	     * parsed if any. We will be called back later.
+	     */
+	    if (xmlParserDebugEntities)
+		xmlGenericError(xmlGenericErrorContext,
+			"decoding PE Reference\n");
+	    if (nbchars != 0) break;
+
+	    xmlParsePEReference(ctxt);
+
+	    /*
+	     * Pop-up of finished entities.
+	     */
+	    while ((RAW == 0) && (ctxt->inputNr > 1)) /* non input consuming */
+		xmlPopInput(ctxt);
+
+	    break;
+	} else {
+	    COPY_BUF(l,buffer,nbchars,c);
+	    NEXTL(l);
+	    if (nbchars > buffer_size - XML_PARSER_BUFFER_SIZE) {
+	      growBuffer(buffer);
+	    }
+	}
+	c = CUR_CHAR(l);
+    }
+    buffer[nbchars++] = 0;
+    return(buffer);
+#endif
+    return(NULL);
+}
+
+/**
+ * xmlNamespaceParseNCName:
+ * @ctxt:  an XML parser context
+ *
+ * parse an XML namespace name.
+ *
+ * TODO: this seems not in use anymore, the namespace handling is done on
+ *       top of the SAX interfaces, i.e. not on raw input.
+ *
+ * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
+ *
+ * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
+ *                       CombiningChar | Extender
+ *
+ * Returns the namespace name or NULL
+ */
+
+xmlChar *
+xmlNamespaceParseNCName(xmlParserCtxtPtr ctxt) {
+#if 0
+    xmlChar buf[XML_MAX_NAMELEN + 5];
+    int len = 0, l;
+    int cur = CUR_CHAR(l);
+#endif
+
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNamespaceParseNCName() deprecated function reached\n");
+	deprecated = 1;
+    }
+
+#if 0
+    /* load first the value of the char !!! */
+    GROW;
+    if (!IS_LETTER(cur) && (cur != '_')) return(NULL);
+
+xmlGenericError(xmlGenericErrorContext,
+	"xmlNamespaceParseNCName: reached loop 3\n");
+    while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) || /* NOT REACHED */
+           (cur == '.') || (cur == '-') ||
+	   (cur == '_') ||
+	   (IS_COMBINING(cur)) ||
+	   (IS_EXTENDER(cur))) {
+	COPY_BUF(l,buf,len,cur);
+	NEXTL(l);
+	cur = CUR_CHAR(l);
+	if (len >= XML_MAX_NAMELEN) {
+	    xmlGenericError(xmlGenericErrorContext, 
+	       "xmlNamespaceParseNCName: reached XML_MAX_NAMELEN limit\n");
+	    while ((IS_LETTER(cur)) || (IS_DIGIT(cur)) ||/* NOT REACHED */
+		   (cur == '.') || (cur == '-') ||
+		   (cur == '_') ||
+		   (IS_COMBINING(cur)) ||
+		   (IS_EXTENDER(cur))) {
+		NEXTL(l);
+		cur = CUR_CHAR(l);
+	    }
+	    break;
+	}
+    }
+    return(xmlStrndup(buf, len));
+#endif
+    return(NULL);
+}
+
+/**
+ * xmlNamespaceParseQName:
+ * @ctxt:  an XML parser context
+ * @prefix:  a xmlChar ** 
+ *
+ * TODO: this seems not in use anymore, the namespace handling is done on
+ *       top of the SAX interfaces, i.e. not on raw input.
+ *
+ * parse an XML qualified name
+ *
+ * [NS 5] QName ::= (Prefix ':')? LocalPart
+ *
+ * [NS 6] Prefix ::= NCName
+ *
+ * [NS 7] LocalPart ::= NCName
+ *
+ * Returns the local part, and prefix is updated
+ *   to get the Prefix if any.
+ */
+
+xmlChar *
+xmlNamespaceParseQName(xmlParserCtxtPtr ctxt, xmlChar **prefix) {
+
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNamespaceParseQName() deprecated function reached\n");
+	deprecated = 1;
+    }
+
+#if 0
+    xmlChar *ret = NULL;
+
+    *prefix = NULL;
+    ret = xmlNamespaceParseNCName(ctxt);
+    if (RAW == ':') {
+        *prefix = ret;
+	NEXT;
+	ret = xmlNamespaceParseNCName(ctxt);
+    }
+
+    return(ret);
+#endif
+    return(NULL);
+}
+
+/**
+ * xmlNamespaceParseNSDef:
+ * @ctxt:  an XML parser context
+ *
+ * parse a namespace prefix declaration
+ *
+ * TODO: this seems not in use anymore, the namespace handling is done on
+ *       top of the SAX interfaces, i.e. not on raw input.
+ *
+ * [NS 1] NSDef ::= PrefixDef Eq SystemLiteral
+ *
+ * [NS 2] PrefixDef ::= 'xmlns' (':' NCName)?
+ *
+ * Returns the namespace name
+ */
+
+xmlChar *
+xmlNamespaceParseNSDef(xmlParserCtxtPtr ctxt) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNamespaceParseNSDef() deprecated function reached\n");
+	deprecated = 1;
+    }
+    return(NULL);
+#if 0
+    xmlChar *name = NULL;
+
+    if ((RAW == 'x') && (NXT(1) == 'm') &&
+        (NXT(2) == 'l') && (NXT(3) == 'n') &&
+	(NXT(4) == 's')) {
+	SKIP(5);
+	if (RAW == ':') {
+	    NEXT;
+	    name = xmlNamespaceParseNCName(ctxt);
+	}
+    }
+    return(name);
+#endif
+}
+
+/**
+ * xmlParseQuotedString:
+ * @ctxt:  an XML parser context
+ *
+ * Parse and return a string between quotes or doublequotes
+ *
+ * TODO: Deprecated, to  be removed at next drop of binary compatibility
+ *
+ * Returns the string parser or NULL.
+ */
+xmlChar *
+xmlParseQuotedString(xmlParserCtxtPtr ctxt) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlParseQuotedString() deprecated function reached\n");
+	deprecated = 1;
+    }
+    return(NULL);
+
+#if 0
+    xmlChar *buf = NULL;
+    int len = 0,l;
+    int size = XML_PARSER_BUFFER_SIZE;
+    int c;
+
+    buf = (xmlChar *) xmlMalloc(size * sizeof(xmlChar));
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"malloc of %d byte failed\n", size);
+	return(NULL);
+    }
+xmlGenericError(xmlGenericErrorContext,
+	"xmlParseQuotedString: reached loop 4\n");
+    if (RAW == '"') {
+        NEXT;
+	c = CUR_CHAR(l);
+	while (IS_CHAR(c) && (c != '"')) { /* NOTUSED */
+	    if (len + 5 >= size) {
+		size *= 2;
+		buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+		if (buf == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "realloc of %d byte failed\n", size);
+		    return(NULL);
+		}
+	    }
+	    COPY_BUF(l,buf,len,c);
+	    NEXTL(l);
+	    c = CUR_CHAR(l);
+	}
+	if (c != '"') {
+	    ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, 
+			         "String not closed \"%.50s\"\n", buf);
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+        } else {
+	    NEXT;
+	}
+    } else if (RAW == '\''){
+        NEXT;
+	c = CUR;
+	while (IS_CHAR(c) && (c != '\'')) { /* NOTUSED */
+	    if (len + 1 >= size) {
+		size *= 2;
+		buf = (xmlChar *) xmlRealloc(buf, size * sizeof(xmlChar));
+		if (buf == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "realloc of %d byte failed\n", size);
+		    return(NULL);
+		}
+	    }
+	    buf[len++] = c;
+	    NEXT;
+	    c = CUR;
+	}
+	if (RAW != '\'') {
+	    ctxt->errNo = XML_ERR_STRING_NOT_CLOSED;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData,
+			         "String not closed \"%.50s\"\n", buf);
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+        } else {
+	    NEXT;
+	}
+    }
+    return(buf);
+#endif
+}
+
+/**
+ * xmlParseNamespace:
+ * @ctxt:  an XML parser context
+ *
+ * xmlParseNamespace: parse specific PI '<?namespace ...' constructs.
+ *
+ * This is what the older xml-name Working Draft specified, a bunch of
+ * other stuff may still rely on it, so support is still here as
+ * if it was declared on the root of the Tree:-(
+ *
+ * TODO: remove from library
+ *
+ * To be removed at next drop of binary compatibility
+ */
+
+void
+xmlParseNamespace(xmlParserCtxtPtr ctxt) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlParseNamespace() deprecated function reached\n");
+	deprecated = 1;
+    }
+
+#if 0
+    xmlChar *href = NULL;
+    xmlChar *prefix = NULL;
+    int garbage = 0;
+
+    /*
+     * We just skipped "namespace" or "xml:namespace"
+     */
+    SKIP_BLANKS;
+
+xmlGenericError(xmlGenericErrorContext,
+	"xmlParseNamespace: reached loop 5\n");
+    while (IS_CHAR(RAW) && (RAW != '>')) { /* NOT REACHED */
+	/*
+	 * We can have "ns" or "prefix" attributes
+	 * Old encoding as 'href' or 'AS' attributes is still supported
+	 */
+	if ((RAW == 'n') && (NXT(1) == 's')) {
+	    garbage = 0;
+	    SKIP(2);
+	    SKIP_BLANKS;
+
+	    if (RAW != '=') continue;
+	    NEXT;
+	    SKIP_BLANKS;
+
+	    href = xmlParseQuotedString(ctxt);
+	    SKIP_BLANKS;
+	} else if ((RAW == 'h') && (NXT(1) == 'r') &&
+	    (NXT(2) == 'e') && (NXT(3) == 'f')) {
+	    garbage = 0;
+	    SKIP(4);
+	    SKIP_BLANKS;
+
+	    if (RAW != '=') continue;
+	    NEXT;
+	    SKIP_BLANKS;
+
+	    href = xmlParseQuotedString(ctxt);
+	    SKIP_BLANKS;
+	} else if ((RAW == 'p') && (NXT(1) == 'r') &&
+	           (NXT(2) == 'e') && (NXT(3) == 'f') &&
+	           (NXT(4) == 'i') && (NXT(5) == 'x')) {
+	    garbage = 0;
+	    SKIP(6);
+	    SKIP_BLANKS;
+
+	    if (RAW != '=') continue;
+	    NEXT;
+	    SKIP_BLANKS;
+
+	    prefix = xmlParseQuotedString(ctxt);
+	    SKIP_BLANKS;
+	} else if ((RAW == 'A') && (NXT(1) == 'S')) {
+	    garbage = 0;
+	    SKIP(2);
+	    SKIP_BLANKS;
+
+	    if (RAW != '=') continue;
+	    NEXT;
+	    SKIP_BLANKS;
+
+	    prefix = xmlParseQuotedString(ctxt);
+	    SKIP_BLANKS;
+	} else if ((RAW == '?') && (NXT(1) == '>')) {
+	    garbage = 0;
+	    NEXT;
+	} else {
+            /*
+	     * Found garbage when parsing the namespace
+	     */
+	    if (!garbage) {
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData,
+		                     "xmlParseNamespace found garbage\n");
+	    }
+	    ctxt->errNo = XML_ERR_NS_DECL_ERROR;
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+            NEXT;
+        }
+    }
+
+    MOVETO_ENDTAG(CUR_PTR);
+    NEXT;
+
+    /*
+     * Register the DTD.
+    if (href != NULL)
+	if ((ctxt->sax != NULL) && (ctxt->sax->globalNamespace != NULL))
+	    ctxt->sax->globalNamespace(ctxt->userData, href, prefix);
+     */
+
+    if (prefix != NULL) xmlFree(prefix);
+    if (href != NULL) xmlFree(href);
+#endif
+}
+
+/**
+ * xmlScanName:
+ * @ctxt:  an XML parser context
+ *
+ * Trickery: parse an XML name but without consuming the input flow
+ * Needed for rollback cases. Used only when parsing entities references.
+ *
+ * TODO: seems deprecated now, only used in the default part of
+ *       xmlParserHandleReference
+ *
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ *                  CombiningChar | Extender
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * [6] Names ::= Name (S Name)*
+ *
+ * Returns the Name parsed or NULL
+ */
+
+xmlChar *
+xmlScanName(xmlParserCtxtPtr ctxt) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlScanName() deprecated function reached\n");
+	deprecated = 1;
+    }
+    return(NULL);
+
+#if 0
+    xmlChar buf[XML_MAX_NAMELEN];
+    int len = 0;
+
+    GROW;
+    if (!IS_LETTER(RAW) && (RAW != '_') &&
+        (RAW != ':')) {
+	return(NULL);
+    }
+
+
+    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) || /* NOT REACHED */
+           (NXT(len) == '.') || (NXT(len) == '-') ||
+	   (NXT(len) == '_') || (NXT(len) == ':') || 
+	   (IS_COMBINING(NXT(len))) ||
+	   (IS_EXTENDER(NXT(len)))) {
+	GROW;
+	buf[len] = NXT(len);
+	len++;
+	if (len >= XML_MAX_NAMELEN) {
+	    xmlGenericError(xmlGenericErrorContext, 
+	       "xmlScanName: reached XML_MAX_NAMELEN limit\n");
+	    while ((IS_LETTER(NXT(len))) || /* NOT REACHED */
+		   (IS_DIGIT(NXT(len))) ||
+		   (NXT(len) == '.') || (NXT(len) == '-') ||
+		   (NXT(len) == '_') || (NXT(len) == ':') || 
+		   (IS_COMBINING(NXT(len))) ||
+		   (IS_EXTENDER(NXT(len))))
+		 len++;
+	    break;
+	}
+    }
+    return(xmlStrndup(buf, len));
+#endif
+}
+
+/**
+ * xmlParserHandleReference:
+ * @ctxt:  the parser context
+ * 
+ * TODO: Remove, now deprecated ... the test is done directly in the
+ *       content parsing
+ * routines.
+ *
+ * [67] Reference ::= EntityRef | CharRef
+ *
+ * [68] EntityRef ::= '&' Name ';'
+ *
+ * [ WFC: Entity Declared ]
+ * the Name given in the entity reference must match that in an entity
+ * declaration, except that well-formed documents need not declare any
+ * of the following entities: amp, lt, gt, apos, quot. 
+ *
+ * [ WFC: Parsed Entity ]
+ * An entity reference must not contain the name of an unparsed entity
+ *
+ * [66] CharRef ::= '&#' [0-9]+ ';' |
+ *                  '&#x' [0-9a-fA-F]+ ';'
+ *
+ * A PEReference may have been detectect in the current input stream
+ * the handling is done accordingly to 
+ *      http://www.w3.org/TR/REC-xml#entproc
+ */
+void
+xmlParserHandleReference(xmlParserCtxtPtr ctxt) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlParserHandleReference() deprecated function reached\n");
+	deprecated = 1;
+    }
+
+#if 0
+    xmlParserInputPtr input;
+    xmlChar *name;
+    xmlEntityPtr ent = NULL;
+
+    if (ctxt->token != 0) {
+        return;
+    }	
+    if (RAW != '&') return;
+    GROW;
+    if ((RAW == '&') && (NXT(1) == '#')) {
+	switch(ctxt->instate) {
+	    case XML_PARSER_ENTITY_DECL:
+	    case XML_PARSER_PI:
+	    case XML_PARSER_CDATA_SECTION:
+	    case XML_PARSER_COMMENT:
+	    case XML_PARSER_SYSTEM_LITERAL:
+		/* we just ignore it there */
+		return;
+	    case XML_PARSER_START_TAG:
+		return;
+	    case XML_PARSER_END_TAG:
+		return;
+	    case XML_PARSER_EOF:
+		ctxt->errNo = XML_ERR_CHARREF_AT_EOF;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, "CharRef at EOF\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		return;
+	    case XML_PARSER_PROLOG:
+	    case XML_PARSER_START:
+	    case XML_PARSER_MISC:
+		ctxt->errNo = XML_ERR_CHARREF_IN_PROLOG;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, "CharRef in prolog!\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		return;
+	    case XML_PARSER_EPILOG:
+		ctxt->errNo = XML_ERR_CHARREF_IN_EPILOG;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, "CharRef in epilog!\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		return;
+	    case XML_PARSER_DTD:
+		ctxt->errNo = XML_ERR_CHARREF_IN_DTD;
+		if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		    ctxt->sax->error(ctxt->userData, 
+		           "CharRef are forbiden in DTDs!\n");
+		ctxt->wellFormed = 0;
+		ctxt->disableSAX = 1;
+		return;
+	    case XML_PARSER_ENTITY_VALUE:
+	        /*
+		 * NOTE: in the case of entity values, we don't do the
+		 *       substitution here since we need the literal
+		 *       entity value to be able to save the internal
+		 *       subset of the document.
+		 *       This will be handled by xmlStringDecodeEntities
+		 */
+		return;
+	    case XML_PARSER_CONTENT:
+		return;
+	    case XML_PARSER_ATTRIBUTE_VALUE:
+		/* ctxt->token = xmlParseCharRef(ctxt); */
+		return;
+            case XML_PARSER_IGNORE:
+	        return;
+	}
+	return;
+    }
+
+    switch(ctxt->instate) {
+	case XML_PARSER_CDATA_SECTION:
+	    return;
+	case XML_PARSER_PI:
+        case XML_PARSER_COMMENT:
+	case XML_PARSER_SYSTEM_LITERAL:
+        case XML_PARSER_CONTENT:
+	    return;
+	case XML_PARSER_START_TAG:
+	    return;
+	case XML_PARSER_END_TAG:
+	    return;
+        case XML_PARSER_EOF:
+	    ctxt->errNo = XML_ERR_ENTITYREF_AT_EOF;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Reference at EOF\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+        case XML_PARSER_PROLOG:
+	case XML_PARSER_START:
+	case XML_PARSER_MISC:
+	    ctxt->errNo = XML_ERR_ENTITYREF_IN_PROLOG;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Reference in prolog!\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+        case XML_PARSER_EPILOG:
+	    ctxt->errNo = XML_ERR_ENTITYREF_IN_EPILOG;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	        ctxt->sax->error(ctxt->userData, "Reference in epilog!\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+	case XML_PARSER_ENTITY_VALUE:
+	    /*
+	     * NOTE: in the case of entity values, we don't do the
+	     *       substitution here since we need the literal
+	     *       entity value to be able to save the internal
+	     *       subset of the document.
+	     *       This will be handled by xmlStringDecodeEntities
+	     */
+	    return;
+        case XML_PARSER_ATTRIBUTE_VALUE:
+	    /*
+	     * NOTE: in the case of attributes values, we don't do the
+	     *       substitution here unless we are in a mode where
+	     *       the parser is explicitely asked to substitute
+	     *       entities. The SAX callback is called with values
+	     *       without entity substitution.
+	     *       This will then be handled by xmlStringDecodeEntities
+	     */
+	    return;
+	case XML_PARSER_ENTITY_DECL:
+	    /*
+	     * we just ignore it there
+	     * the substitution will be done once the entity is referenced
+	     */
+	    return;
+        case XML_PARSER_DTD:
+	    ctxt->errNo = XML_ERR_ENTITYREF_IN_DTD;
+	    if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+		ctxt->sax->error(ctxt->userData, 
+		       "Entity references are forbiden in DTDs!\n");
+	    ctxt->wellFormed = 0;
+	    ctxt->disableSAX = 1;
+	    return;
+        case XML_PARSER_IGNORE:
+	    return;
+    }
+
+/* TODO: this seems not reached anymore .... Verify ... */
+xmlGenericError(xmlGenericErrorContext,
+	"Reached deprecated section in xmlParserHandleReference()\n");
+xmlGenericError(xmlGenericErrorContext,
+	"Please forward the document to Daniel.Veillard@w3.org\n");
+xmlGenericError(xmlGenericErrorContext,
+	"indicating the version: %s, thanks !\n", xmlParserVersion);
+    NEXT;
+    name = xmlScanName(ctxt);
+    if (name == NULL) {
+	ctxt->errNo = XML_ERR_ENTITYREF_NO_NAME;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "Entity reference: no name\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	ctxt->token = '&';
+	return;
+    }
+    if (NXT(xmlStrlen(name)) != ';') {
+	ctxt->errNo = XML_ERR_ENTITYREF_SEMICOL_MISSING;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+	                     "Entity reference: ';' expected\n");
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	ctxt->token = '&';
+	xmlFree(name);
+	return;
+    }
+    SKIP(xmlStrlen(name) + 1);
+    if (ctxt->sax != NULL) {
+	if (ctxt->sax->getEntity != NULL)
+	    ent = ctxt->sax->getEntity(ctxt->userData, name);
+    }
+
+    /*
+     * [ WFC: Entity Declared ]
+     * the Name given in the entity reference must match that in an entity
+     * declaration, except that well-formed documents need not declare any
+     * of the following entities: amp, lt, gt, apos, quot. 
+     */
+    if (ent == NULL)
+	ent = xmlGetPredefinedEntity(name);
+    if (ent == NULL) {
+        ctxt->errNo = XML_ERR_UNDECLARED_ENTITY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+			     "Entity reference: entity %s not declared\n",
+			     name);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+	xmlFree(name);
+	return;
+    }
+
+    /*
+     * [ WFC: Parsed Entity ]
+     * An entity reference must not contain the name of an unparsed entity
+     */
+    if (ent->etype == XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
+        ctxt->errNo = XML_ERR_UNPARSED_ENTITY;
+	if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, 
+			 "Entity reference to unparsed entity %s\n", name);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+    }
+
+    if (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY) {
+        ctxt->token = ent->content[0];
+	xmlFree(name);
+	return;
+    }
+    input = xmlNewEntityInputStream(ctxt, ent);
+    xmlPushInput(ctxt, input);
+    xmlFree(name);
+#endif
+    return;
+}
+
+/**
+ * xmlHandleEntity:
+ * @ctxt:  an XML parser context
+ * @entity:  an XML entity pointer.
+ *
+ * Default handling of defined entities, when should we define a new input
+ * stream ? When do we just handle that as a set of chars ?
+ *
+ * OBSOLETE: to be removed at some point.
+ */
+
+void
+xmlHandleEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr entity) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlHandleEntity() deprecated function reached\n");
+	deprecated = 1;
+    }
+
+#if 0
+    int len;
+    xmlParserInputPtr input;
+
+    if (entity->content == NULL) {
+	ctxt->errNo = XML_ERR_INTERNAL_ERROR;
+        if ((ctxt->sax != NULL) && (ctxt->sax->error != NULL))
+	    ctxt->sax->error(ctxt->userData, "xmlHandleEntity %s: content == NULL\n",
+	               entity->name);
+	ctxt->wellFormed = 0;
+	ctxt->disableSAX = 1;
+        return;
+    }
+    len = xmlStrlen(entity->content);
+    if (len <= 2) goto handle_as_char;
+
+    /*
+     * Redefine its content as an input stream.
+     */
+    input = xmlNewEntityInputStream(ctxt, entity);
+    xmlPushInput(ctxt, input);
+    return;
+
+handle_as_char:
+    /*
+     * Just handle the content as a set of chars.
+     */
+    if ((ctxt->sax != NULL) && (!ctxt->disableSAX) &&
+	(ctxt->sax->characters != NULL))
+	ctxt->sax->characters(ctxt->userData, entity->content, len);
+#endif
+}
+
+/**
+ * xmlNewGlobalNs:
+ * @doc:  the document carrying the namespace
+ * @href:  the URI associated
+ * @prefix:  the prefix for the namespace
+ *
+ * Creation of a Namespace, the old way using PI and without scoping
+ *   DEPRECATED !!!
+ * It now create a namespace on the root element of the document if found.
+ * Returns NULL this functionnality had been removed
+ */
+xmlNsPtr
+xmlNewGlobalNs(xmlDocPtr doc, const xmlChar *href, const xmlChar *prefix) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNewGlobalNs() deprecated function reached\n");
+	deprecated = 1;
+    }
+    return(NULL);
+#if 0
+    xmlNodePtr root;
+
+    xmlNsPtr cur;
+ 
+    root = xmlDocGetRootElement(doc);
+    if (root != NULL)
+	return(xmlNewNs(root, href, prefix));
+	
+    /*
+     * if there is no root element yet, create an old Namespace type
+     * and it will be moved to the root at save time.
+     */
+    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewGlobalNs : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNs));
+    cur->type = XML_GLOBAL_NAMESPACE;
+
+    if (href != NULL)
+	cur->href = xmlStrdup(href); 
+    if (prefix != NULL)
+	cur->prefix = xmlStrdup(prefix); 
+
+    /*
+     * Add it at the end to preserve parsing order ...
+     */
+    if (doc != NULL) {
+	if (doc->oldNs == NULL) {
+	    doc->oldNs = cur;
+	} else {
+	    xmlNsPtr prev = doc->oldNs;
+
+	    while (prev->next != NULL) prev = prev->next;
+	    prev->next = cur;
+	}
+    }
+
+  return(NULL);
+#endif
+}
+
+/**
+ * xmlUpgradeOldNs:
+ * @doc:  a document pointer
+ * 
+ * Upgrade old style Namespaces (PI) and move them to the root of the document.
+ * DEPRECATED
+ */
+void
+xmlUpgradeOldNs(xmlDocPtr doc) {
+    static int deprecated = 0;
+    if (!deprecated) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNewGlobalNs() deprecated function reached\n");
+	deprecated = 1;
+    }
+#if 0
+    xmlNsPtr cur;
+
+    if ((doc == NULL) || (doc->oldNs == NULL)) return;
+    if (doc->children == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlUpgradeOldNs: failed no root !\n");
+#endif
+	return;
+    }
+
+    cur = doc->oldNs;
+    while (cur->next != NULL) {
+	cur->type = XML_LOCAL_NAMESPACE;
+        cur = cur->next;
+    }
+    cur->type = XML_LOCAL_NAMESPACE;
+    cur->next = doc->children->nsDef;
+    doc->children->nsDef = doc->oldNs;
+    doc->oldNs = NULL;
+#endif
+}
+
diff --git a/parserInternals.h b/parserInternals.h
new file mode 100644
index 0000000..3fdb8f6
--- /dev/null
+++ b/parserInternals.h
@@ -0,0 +1,314 @@
+/*
+ * parserInternals.h : internals routines exported by the parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - truncated declaration of xmlParseElementChildrenContentDecl 
+ * for VMS
+ *
+ */
+
+#ifndef __XML_PARSER_INTERNALS_H__
+#define __XML_PARSER_INTERNALS_H__
+
+#include <libxml/parser.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* 
+  * Identifiers can be longer, but this will be more costly
+  * at runtime.
+  */
+#define XML_MAX_NAMELEN 100
+
+/*
+ * The parser tries to always have that amount of input ready
+ * one of the point is providing context when reporting errors
+ */
+#define INPUT_CHUNK	250
+
+/************************************************************************
+ *									*
+ * UNICODE version of the macros.      					*
+ *									*
+ ************************************************************************/
+/*
+ * [2] Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD]
+ *                  | [#x10000-#x10FFFF]
+ * any Unicode character, excluding the surrogate blocks, FFFE, and FFFF.
+ */
+#define IS_CHAR(c)							\
+    ((((c) >= 0x20) && ((c) <= 0xD7FF)) ||				\
+     ((c) == 0x09) || ((c) == 0x0A) || ((c) == 0x0D) ||			\
+     (((c) >= 0xE000) && ((c) <= 0xFFFD)) ||				\
+     (((c) >= 0x10000) && ((c) <= 0x10FFFF)))
+
+/*
+ * [3] S ::= (#x20 | #x9 | #xD | #xA)+
+ */
+#define IS_BLANK(c) (((c) == 0x20) || ((c) == 0x09) || ((c) == 0xA) ||	\
+                     ((c) == 0x0D))
+
+/*
+ * [85] BaseChar ::= ... long list see REC ...
+ */
+#define IS_BASECHAR(c) xmlIsBaseChar(c)
+
+/*
+ * [88] Digit ::= ... long list see REC ...
+ */
+#define IS_DIGIT(c) xmlIsDigit(c)
+
+/*
+ * [87] CombiningChar ::= ... long list see REC ...
+ */
+#define IS_COMBINING(c) xmlIsCombining(c)
+
+/*
+ * [89] Extender ::= #x00B7 | #x02D0 | #x02D1 | #x0387 | #x0640 |
+ *                   #x0E46 | #x0EC6 | #x3005 | [#x3031-#x3035] |
+ *                   [#x309D-#x309E] | [#x30FC-#x30FE]
+ */
+#define IS_EXTENDER(c) xmlIsExtender(c)
+
+/*
+ * [86] Ideographic ::= [#x4E00-#x9FA5] | #x3007 | [#x3021-#x3029]
+ */
+#define IS_IDEOGRAPHIC(c) xmlIsIdeographic(c)
+
+/*
+ * [84] Letter ::= BaseChar | Ideographic 
+ */
+#define IS_LETTER(c) (IS_BASECHAR(c) || IS_IDEOGRAPHIC(c))
+
+
+/*
+ * [13] PubidChar ::= #x20 | #xD | #xA | [a-zA-Z0-9] | [-'()+,./:=?;!*#@$_%]
+ */
+#define IS_PUBIDCHAR(c)	xmlIsPubidChar(c)
+
+#define SKIP_EOL(p) 							\
+    if (*(p) == 0x13) { p++ ; if (*(p) == 0x10) p++; }			\
+    if (*(p) == 0x10) { p++ ; if (*(p) == 0x13) p++; }
+
+#define MOVETO_ENDTAG(p)						\
+    while ((*p) && (*(p) != '>')) (p)++
+
+#define MOVETO_STARTTAG(p)						\
+    while ((*p) && (*(p) != '<')) (p)++
+
+/**
+ * Global vaiables affecting the default parser behaviour.
+ */
+
+LIBXML_DLL_IMPORT extern int xmlParserDebugEntities;
+LIBXML_DLL_IMPORT extern int xmlGetWarningsDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlParserDebugEntities;
+LIBXML_DLL_IMPORT extern int xmlSubstituteEntitiesDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlDoValidityCheckingDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlLoadExtDtdDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlPedanticParserDefaultValue;
+LIBXML_DLL_IMPORT extern int xmlKeepBlanksDefaultValue;
+LIBXML_DLL_IMPORT extern xmlChar xmlStringText[];
+LIBXML_DLL_IMPORT extern xmlChar xmlStringTextNoenc[];
+LIBXML_DLL_IMPORT extern xmlChar xmlStringComment[];
+
+/*
+ * Function to finish teh work of the macros where needed
+ */
+int			xmlIsBaseChar	(int c);
+int			xmlIsBlank	(int c);
+int			xmlIsPubidChar	(int c);
+int			xmlIsLetter	(int c);
+int			xmlIsDigit	(int c);
+int			xmlIsIdeographic(int c);
+int			xmlIsCombining	(int c);
+int			xmlIsExtender	(int c);
+int			xmlIsCombining	(int c);
+int			xmlIsChar	(int c);
+
+/**
+ * Parser context
+ */
+xmlParserCtxtPtr	xmlCreateDocParserCtxt	(xmlChar *cur);
+xmlParserCtxtPtr	xmlCreateFileParserCtxt	(const char *filename);
+xmlParserCtxtPtr	xmlCreateMemoryParserCtxt(char *buffer,
+						 int size);
+xmlParserCtxtPtr	xmlNewParserCtxt	(void);
+xmlParserCtxtPtr	xmlCreateEntityParserCtxt(const xmlChar *URL,
+						 const xmlChar *ID,
+						 const xmlChar *base);
+int			xmlSwitchEncoding	(xmlParserCtxtPtr ctxt,
+						 xmlCharEncoding enc);
+int			xmlSwitchToEncoding	(xmlParserCtxtPtr ctxt,
+					     xmlCharEncodingHandlerPtr handler);
+void			xmlFreeParserCtxt	(xmlParserCtxtPtr ctxt);
+
+/**
+ * Entities
+ */
+void			xmlHandleEntity		(xmlParserCtxtPtr ctxt,
+						 xmlEntityPtr entity);
+
+/**
+ * Input Streams
+ */
+xmlParserInputPtr	xmlNewEntityInputStream	(xmlParserCtxtPtr ctxt,
+						 xmlEntityPtr entity);
+void			xmlPushInput		(xmlParserCtxtPtr ctxt,
+						 xmlParserInputPtr input);
+xmlChar			xmlPopInput		(xmlParserCtxtPtr ctxt);
+void			xmlFreeInputStream	(xmlParserInputPtr input);
+xmlParserInputPtr	xmlNewInputFromFile	(xmlParserCtxtPtr ctxt,
+						 const char *filename);
+xmlParserInputPtr	xmlNewInputStream	(xmlParserCtxtPtr ctxt);
+
+/**
+ * Namespaces.
+ */
+xmlChar *		xmlSplitQName		(xmlParserCtxtPtr ctxt,
+						 const xmlChar *name,
+						 xmlChar **prefix);
+xmlChar *		xmlNamespaceParseNCName	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlNamespaceParseQName	(xmlParserCtxtPtr ctxt,
+						 xmlChar **prefix);
+xmlChar *		xmlNamespaceParseNSDef	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseQuotedString	(xmlParserCtxtPtr ctxt);
+void			xmlParseNamespace	(xmlParserCtxtPtr ctxt);
+
+/**
+ * Generic production rules
+ */
+xmlChar *		xmlScanName		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseName		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseNmtoken		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseEntityValue	(xmlParserCtxtPtr ctxt,
+						 xmlChar **orig);
+xmlChar *		xmlParseAttValue	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseSystemLiteral	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParsePubidLiteral	(xmlParserCtxtPtr ctxt);
+void			xmlParseCharData	(xmlParserCtxtPtr ctxt,
+						 int cdata);
+xmlChar *		xmlParseExternalID	(xmlParserCtxtPtr ctxt,
+						 xmlChar **publicID,
+						 int strict);
+void			xmlParseComment		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParsePITarget	(xmlParserCtxtPtr ctxt);
+void			xmlParsePI		(xmlParserCtxtPtr ctxt);
+void			xmlParseNotationDecl	(xmlParserCtxtPtr ctxt);
+void			xmlParseEntityDecl	(xmlParserCtxtPtr ctxt);
+int			xmlParseDefaultDecl	(xmlParserCtxtPtr ctxt,
+						 xmlChar **value);
+xmlEnumerationPtr	xmlParseNotationType	(xmlParserCtxtPtr ctxt);
+xmlEnumerationPtr	xmlParseEnumerationType	(xmlParserCtxtPtr ctxt);
+int			xmlParseEnumeratedType	(xmlParserCtxtPtr ctxt,
+						 xmlEnumerationPtr *tree);
+int			xmlParseAttributeType	(xmlParserCtxtPtr ctxt,
+						 xmlEnumerationPtr *tree);
+void			xmlParseAttributeListDecl(xmlParserCtxtPtr ctxt);
+xmlElementContentPtr	xmlParseElementMixedContentDecl
+						(xmlParserCtxtPtr ctxt);
+#ifdef VMS
+xmlElementContentPtr	xmlParseElementChildrenContentD
+						(xmlParserCtxtPtr ctxt);
+#define xmlParseElementChildrenContentDecl	xmlParseElementChildrenContentD
+#else
+xmlElementContentPtr	xmlParseElementChildrenContentDecl
+						(xmlParserCtxtPtr ctxt);
+#endif
+int			xmlParseElementContentDecl(xmlParserCtxtPtr ctxt,
+						 xmlChar *name,
+						 xmlElementContentPtr *result);
+int			xmlParseElementDecl	(xmlParserCtxtPtr ctxt);
+void			xmlParseMarkupDecl	(xmlParserCtxtPtr ctxt);
+int			xmlParseCharRef		(xmlParserCtxtPtr ctxt);
+xmlEntityPtr		xmlParseEntityRef	(xmlParserCtxtPtr ctxt);
+void			xmlParseReference	(xmlParserCtxtPtr ctxt);
+void			xmlParsePEReference	(xmlParserCtxtPtr ctxt);
+void			xmlParseDocTypeDecl	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseAttribute	(xmlParserCtxtPtr ctxt,
+						 xmlChar **value);
+xmlChar *		xmlParseStartTag	(xmlParserCtxtPtr ctxt);
+void			xmlParseEndTag		(xmlParserCtxtPtr ctxt);
+void			xmlParseCDSect		(xmlParserCtxtPtr ctxt);
+void			xmlParseContent		(xmlParserCtxtPtr ctxt);
+void			xmlParseElement		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseVersionNum	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseVersionInfo	(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseEncName		(xmlParserCtxtPtr ctxt);
+xmlChar *		xmlParseEncodingDecl	(xmlParserCtxtPtr ctxt);
+int			xmlParseSDDecl		(xmlParserCtxtPtr ctxt);
+void			xmlParseXMLDecl		(xmlParserCtxtPtr ctxt);
+void			xmlParseTextDecl	(xmlParserCtxtPtr ctxt);
+void			xmlParseMisc		(xmlParserCtxtPtr ctxt);
+void			xmlParseExternalSubset	(xmlParserCtxtPtr ctxt,
+						 const xmlChar *ExternalID,
+						 const xmlChar *SystemID); 
+/*
+ * Entities substitution
+ */
+#define XML_SUBSTITUTE_NONE	0
+#define XML_SUBSTITUTE_REF	1
+#define XML_SUBSTITUTE_PEREF	2
+#define XML_SUBSTITUTE_BOTH 	3
+
+xmlChar *		xmlDecodeEntities	(xmlParserCtxtPtr ctxt,
+						 int len,
+						 int what,
+						 xmlChar end,
+						 xmlChar  end2,
+						 xmlChar end3);
+xmlChar *		xmlStringDecodeEntities	(xmlParserCtxtPtr ctxt,
+						 const xmlChar *str,
+						 int what,
+						 xmlChar end,
+						 xmlChar  end2,
+						 xmlChar end3);
+
+/*
+ * Generated by MACROS on top of parser.c c.f. PUSH_AND_POP
+ */
+int			nodePush		(xmlParserCtxtPtr ctxt,
+						 xmlNodePtr value);
+xmlNodePtr		nodePop			(xmlParserCtxtPtr ctxt);
+int			inputPush		(xmlParserCtxtPtr ctxt,
+						 xmlParserInputPtr value);
+xmlParserInputPtr	inputPop		(xmlParserCtxtPtr ctxt);
+
+/*
+ * other comodities shared between parser.c and parserInternals
+ */
+int			xmlSkipBlankChars	(xmlParserCtxtPtr ctxt);
+int			xmlStringCurrentChar	(xmlParserCtxtPtr ctxt,
+						 const xmlChar *cur,
+						 int *len);
+void			xmlParserHandlePEReference(xmlParserCtxtPtr ctxt);
+void			xmlParserHandleReference(xmlParserCtxtPtr ctxt);
+xmlChar                *namePop			(xmlParserCtxtPtr ctxt);
+int			xmlCheckLanguageID	(const xmlChar *lang);
+
+/*
+ * Really core function shared with HTML parser
+ */
+int			xmlCurrentChar		(xmlParserCtxtPtr ctxt,
+						 int *len);
+int			xmlCopyChar		(int len,
+						 xmlChar *out,
+						 int val);
+void			xmlNextChar		(xmlParserCtxtPtr ctxt);
+void			xmlParserInputShrink	(xmlParserInputPtr in);
+
+#ifdef LIBXML_HTML_ENABLED
+/*
+ * Actually comes from the HTML parser but launched from the init stuff
+ */
+void			htmlInitAutoClose	(void);
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_PARSER_INTERNALS_H__ */
diff --git a/tree.c b/tree.c
new file mode 100644
index 0000000..ae9c8c2
--- /dev/null
+++ b/tree.c
@@ -0,0 +1,6144 @@
+/*
+ * tree.c : implemetation of access function for an XML tree.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - Changed the name of function xmlBufferWriteChar under VMS
+ * as it was similar to xmlBufferWriteCHAR when compiling without case
+ * sensitivity.
+ *  
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h> /* for memset() only ! */
+
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/entities.h>
+#include <libxml/valid.h>
+#include <libxml/xmlerror.h>
+
+xmlChar xmlStringText[] = { 't', 'e', 'x', 't', 0 };
+xmlChar xmlStringTextNoenc[] =
+              { 't', 'e', 'x', 't', 'n', 'o', 'e', 'n', 'c', 0 };
+xmlChar xmlStringComment[] = { 'c', 'o', 'm', 'm', 'e', 'n', 't', 0 };
+int oldXMLWDcompatibility = 0;
+int xmlIndentTreeOutput = 0;
+xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT;
+
+static int xmlCompressMode = 0;
+static int xmlCheckDTD = 1;
+int xmlSaveNoEmptyTags = 0;
+
+#define IS_BLANK(c)							\
+  (((c) == '\n') || ((c) == '\r') || ((c) == '\t') || ((c) == ' '))
+
+#define UPDATE_LAST_CHILD_AND_PARENT(n) if ((n) != NULL) {		\
+    xmlNodePtr ulccur = (n)->children;					\
+    if (ulccur == NULL) {						\
+        (n)->last = NULL;						\
+    } else {								\
+        while (ulccur->next != NULL) {					\
+	       	ulccur->parent = (n);					\
+		ulccur = ulccur->next;					\
+	}								\
+	ulccur->parent = (n);						\
+	(n)->last = ulccur;						\
+}}
+
+/* #define DEBUG_BUFFER */
+/* #define DEBUG_TREE */
+
+/************************************************************************
+ *									*
+ *		Allocation and deallocation of basic structures		*
+ *									*
+ ************************************************************************/
+ 
+/**
+ * xmlSetBufferAllocationScheme:
+ * @scheme:  allocation method to use
+ * 
+ * Set the buffer allocation method.  Types are
+ * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
+ * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, 
+ *                             improves performance
+ */
+void
+xmlSetBufferAllocationScheme(xmlBufferAllocationScheme scheme) {
+    xmlBufferAllocScheme = scheme;
+}
+
+/**
+ * xmlGetBufferAllocationScheme:
+ *
+ * Types are
+ * XML_BUFFER_ALLOC_EXACT - use exact sizes, keeps memory usage down
+ * XML_BUFFER_ALLOC_DOUBLEIT - double buffer when extra needed, 
+ *                             improves performance
+ * 
+ * Returns the current allocation scheme
+ */
+xmlBufferAllocationScheme
+xmlGetBufferAllocationScheme() {
+    return xmlBufferAllocScheme;
+}
+
+/**
+ * xmlNewNs:
+ * @node:  the element carrying the namespace
+ * @href:  the URI associated
+ * @prefix:  the prefix for the namespace
+ *
+ * Creation of a new Namespace. This function will refuse to create
+ * a namespace with a similar prefix than an existing one present on this
+ * node.
+ * We use href==NULL in the case of an element creation where the namespace
+ * was not defined.
+ * Returns returns a new namespace pointer or NULL
+ */
+xmlNsPtr
+xmlNewNs(xmlNodePtr node, const xmlChar *href, const xmlChar *prefix) {
+    xmlNsPtr cur;
+
+    if ((node != NULL) && (node->type != XML_ELEMENT_NODE))
+	return(NULL);
+
+    /*
+     * Allocate a new Namespace and fill the fields.
+     */
+    cur = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewNs : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNs));
+    cur->type = XML_LOCAL_NAMESPACE;
+
+    if (href != NULL)
+	cur->href = xmlStrdup(href); 
+    if (prefix != NULL)
+	cur->prefix = xmlStrdup(prefix); 
+
+    /*
+     * Add it at the end to preserve parsing order ...
+     * and checks for existing use of the prefix
+     */
+    if (node != NULL) {
+	if (node->nsDef == NULL) {
+	    node->nsDef = cur;
+	} else {
+	    xmlNsPtr prev = node->nsDef;
+
+	    if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
+		(xmlStrEqual(prev->prefix, cur->prefix))) {
+		xmlFreeNs(cur);
+		return(NULL);
+	    }    
+	    while (prev->next != NULL) {
+	        prev = prev->next;
+		if (((prev->prefix == NULL) && (cur->prefix == NULL)) ||
+		    (xmlStrEqual(prev->prefix, cur->prefix))) {
+		    xmlFreeNs(cur);
+		    return(NULL);
+		}    
+	    }
+	    prev->next = cur;
+	}
+    }
+    return(cur);
+}
+
+/**
+ * xmlSetNs:
+ * @node:  a node in the document
+ * @ns:  a namespace pointer
+ *
+ * Associate a namespace to a node, a posteriori.
+ */
+void
+xmlSetNs(xmlNodePtr node, xmlNsPtr ns) {
+    if (node == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlSetNs: node == NULL\n");
+#endif
+	return;
+    }
+    node->ns = ns;
+}
+
+/**
+ * xmlFreeNs:
+ * @cur:  the namespace pointer
+ *
+ * Free up the structures associated to a namespace
+ */
+void
+xmlFreeNs(xmlNsPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeNs : ns == NULL\n");
+#endif
+	return;
+    }
+    if (cur->href != NULL) xmlFree((char *) cur->href);
+    if (cur->prefix != NULL) xmlFree((char *) cur->prefix);
+    memset(cur, -1, sizeof(xmlNs));
+    xmlFree(cur);
+}
+
+/**
+ * xmlFreeNsList:
+ * @cur:  the first namespace pointer
+ *
+ * Free up all the structures associated to the chained namespaces.
+ */
+void
+xmlFreeNsList(xmlNsPtr cur) {
+    xmlNsPtr next;
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeNsList : ns == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+        next = cur->next;
+        xmlFreeNs(cur);
+	cur = next;
+    }
+}
+
+/**
+ * xmlNewDtd:
+ * @doc:  the document pointer
+ * @name:  the DTD name
+ * @ExternalID:  the external ID
+ * @SystemID:  the system ID
+ *
+ * Creation of a new DTD for the external subset. To create an
+ * internal subset, use xmlCreateIntSubset().
+ *
+ * Returns a pointer to the new DTD structure
+ */
+xmlDtdPtr
+xmlNewDtd(xmlDocPtr doc, const xmlChar *name,
+                    const xmlChar *ExternalID, const xmlChar *SystemID) {
+    xmlDtdPtr cur;
+
+    if ((doc != NULL) && (doc->extSubset != NULL)) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewDtd(%s): document %s already have a DTD %s\n",
+	    /* !!! */ (char *) name, doc->name,
+	    /* !!! */ (char *)doc->extSubset->name);
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new DTD and fill the fields.
+     */
+    cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewDtd : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0 , sizeof(xmlDtd));
+    cur->type = XML_DTD_NODE;
+
+    if (name != NULL)
+	cur->name = xmlStrdup(name); 
+    if (ExternalID != NULL)
+	cur->ExternalID = xmlStrdup(ExternalID); 
+    if (SystemID != NULL)
+	cur->SystemID = xmlStrdup(SystemID); 
+    if (doc != NULL)
+	doc->extSubset = cur;
+    cur->doc = doc;
+
+    return(cur);
+}
+
+/**
+ * xmlGetIntSubset:
+ * @doc:  the document pointer
+ *
+ * Get the internal subset of a document
+ * Returns a pointer to the DTD structure or NULL if not found
+ */
+
+xmlDtdPtr
+xmlGetIntSubset(xmlDocPtr doc) {
+    xmlNodePtr cur;
+
+    if (doc == NULL)
+	return(NULL);
+    cur = doc->children;
+    while (cur != NULL) {
+	if (cur->type == XML_DTD_NODE)
+	    return((xmlDtdPtr) cur);
+	cur = cur->next;
+    }
+    return((xmlDtdPtr) doc->intSubset);
+}
+
+/**
+ * xmlCreateIntSubset:
+ * @doc:  the document pointer
+ * @name:  the DTD name
+ * @ExternalID:  the external ID
+ * @SystemID:  the system ID
+ *
+ * Create the internal subset of a document
+ * Returns a pointer to the new DTD structure
+ */
+xmlDtdPtr
+xmlCreateIntSubset(xmlDocPtr doc, const xmlChar *name,
+                   const xmlChar *ExternalID, const xmlChar *SystemID) {
+    xmlDtdPtr cur;
+
+    if ((doc != NULL) && (xmlGetIntSubset(doc) != NULL)) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+
+     "xmlCreateIntSubset(): document %s already have an internal subset\n",
+	    doc->name);
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new DTD and fill the fields.
+     */
+    cur = (xmlDtdPtr) xmlMalloc(sizeof(xmlDtd));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewDtd : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlDtd));
+    cur->type = XML_DTD_NODE;
+
+    if (name != NULL)
+	cur->name = xmlStrdup(name); 
+    if (ExternalID != NULL)
+	cur->ExternalID = xmlStrdup(ExternalID); 
+    if (SystemID != NULL)
+	cur->SystemID = xmlStrdup(SystemID); 
+    if (doc != NULL) {
+	doc->intSubset = cur;
+	cur->parent = doc;
+	cur->doc = doc;
+	if (doc->children == NULL) {
+	    doc->children = (xmlNodePtr) cur;
+	    doc->last = (xmlNodePtr) cur;
+	} else {
+	    xmlNodePtr prev;
+
+	    if (doc->type == XML_HTML_DOCUMENT_NODE) {
+		prev = doc->children;
+		prev->prev = (xmlNodePtr) cur;
+		cur->next = prev;
+		doc->children = (xmlNodePtr) cur;
+	    } else {
+		prev = doc->last;
+		prev->next = (xmlNodePtr) cur;
+		cur->prev = prev;
+		doc->last = (xmlNodePtr) cur;
+	    }
+	}
+    }
+    return(cur);
+}
+
+/**
+ * xmlFreeDtd:
+ * @cur:  the DTD structure to free up
+ *
+ * Free a DTD structure.
+ */
+void
+xmlFreeDtd(xmlDtdPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeDtd : DTD == NULL\n");
+#endif
+	return;
+    }
+    if (cur->children != NULL) {
+	xmlNodePtr next, c = cur->children;
+
+	/*
+	 * Cleanup all the DTD comments they are not in the Dtd
+	 * indexes.
+	 */
+        while (c != NULL) {
+	    next = c->next;
+	    if (c->type == XML_COMMENT_NODE) {
+		xmlUnlinkNode(c);
+		xmlFreeNode(c);
+	    }
+	    c = next;
+	}
+    }
+    if (cur->name != NULL) xmlFree((char *) cur->name);
+    if (cur->SystemID != NULL) xmlFree((char *) cur->SystemID);
+    if (cur->ExternalID != NULL) xmlFree((char *) cur->ExternalID);
+    /* TODO !!! */
+    if (cur->notations != NULL)
+        xmlFreeNotationTable((xmlNotationTablePtr) cur->notations);
+    
+    if (cur->elements != NULL)
+        xmlFreeElementTable((xmlElementTablePtr) cur->elements);
+    if (cur->attributes != NULL)
+        xmlFreeAttributeTable((xmlAttributeTablePtr) cur->attributes);
+    if (cur->entities != NULL)
+        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->entities);
+    if (cur->pentities != NULL)
+        xmlFreeEntitiesTable((xmlEntitiesTablePtr) cur->pentities);
+
+    memset(cur, -1, sizeof(xmlDtd));
+    xmlFree(cur);
+}
+
+/**
+ * xmlNewDoc:
+ * @version:  xmlChar string giving the version of XML "1.0"
+ *
+ * Returns a new document
+ */
+xmlDocPtr
+xmlNewDoc(const xmlChar *version) {
+    xmlDocPtr cur;
+
+    if (version == NULL)
+	version = (const xmlChar *) "1.0";
+
+    /*
+     * Allocate a new document and fill the fields.
+     */
+    cur = (xmlDocPtr) xmlMalloc(sizeof(xmlDoc));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewDoc : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlDoc));
+    cur->type = XML_DOCUMENT_NODE;
+
+    cur->version = xmlStrdup(version); 
+    cur->standalone = -1;
+    cur->compression = -1; /* not initialized */
+    cur->doc = cur;
+    return(cur);
+}
+
+/**
+ * xmlFreeDoc:
+ * @cur:  pointer to the document
+ * @:  
+ *
+ * Free up all the structures used by a document, tree included.
+ */
+void
+xmlFreeDoc(xmlDocPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeDoc : document == NULL\n");
+#endif
+	return;
+    }
+    if (cur->version != NULL) xmlFree((char *) cur->version);
+    if (cur->name != NULL) xmlFree((char *) cur->name);
+    if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
+    if (cur->children != NULL) xmlFreeNodeList(cur->children);
+    if (cur->intSubset != NULL) xmlFreeDtd(cur->intSubset);
+    if (cur->extSubset != NULL) xmlFreeDtd(cur->extSubset);
+    if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
+    if (cur->ids != NULL) xmlFreeIDTable((xmlIDTablePtr) cur->ids);
+    if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
+    if (cur->URL != NULL) xmlFree((char *) cur->URL);
+    memset(cur, -1, sizeof(xmlDoc));
+    xmlFree(cur);
+}
+
+/**
+ * xmlStringLenGetNodeList:
+ * @doc:  the document
+ * @value:  the value of the text
+ * @len:  the length of the string value
+ *
+ * Parse the value string and build the node list associated. Should
+ * produce a flat tree with only TEXTs and ENTITY_REFs.
+ * Returns a pointer to the first child
+ */
+xmlNodePtr
+xmlStringLenGetNodeList(xmlDocPtr doc, const xmlChar *value, int len) {
+    xmlNodePtr ret = NULL, last = NULL;
+    xmlNodePtr node;
+    xmlChar *val;
+    const xmlChar *cur = value;
+    const xmlChar *q;
+    xmlEntityPtr ent;
+
+    if (value == NULL) return(NULL);
+
+    q = cur;
+    while ((*cur != 0) && (cur - value < len)) {
+	if (*cur == '&') {
+	    /*
+	     * Save the current text.
+	     */
+            if (cur != q) {
+		if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
+		    xmlNodeAddContentLen(last, q, cur - q);
+		} else {
+		    node = xmlNewDocTextLen(doc, q, cur - q);
+		    if (node == NULL) return(ret);
+		    if (last == NULL)
+			last = ret = node;
+		    else {
+			last->next = node;
+			node->prev = last;
+			last = node;
+		    }
+		}
+	    }
+	    /*
+	     * Read the entity string
+	     */
+	    cur++;
+	    q = cur;
+	    while ((*cur != 0) && (cur - value < len) && (*cur != ';')) cur++;
+	    if ((*cur == 0) || (cur - value >= len)) {
+#ifdef DEBUG_TREE
+	        xmlGenericError(xmlGenericErrorContext,
+		    "xmlStringLenGetNodeList: unterminated entity %30s\n", q);
+#endif
+	        return(ret);
+	    }
+            if (cur != q) {
+		/*
+		 * Predefined entities don't generate nodes
+		 */
+		val = xmlStrndup(q, cur - q);
+		ent = xmlGetDocEntity(doc, val);
+		if ((ent != NULL) &&
+		    (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
+		    if (last == NULL) {
+		        node = xmlNewDocText(doc, ent->content);
+			last = ret = node;
+		    } else
+		        xmlNodeAddContent(last, ent->content);
+		        
+		} else {
+		    /*
+		     * Create a new REFERENCE_REF node
+		     */
+		    node = xmlNewReference(doc, val);
+		    if (node == NULL) {
+			if (val != NULL) xmlFree(val);
+		        return(ret);
+		    }
+		    if (last == NULL)
+			last = ret = node;
+		    else {
+			last->next = node;
+			node->prev = last;
+			last = node;
+		    }
+		}
+		xmlFree(val);
+	    }
+	    cur++;
+	    q = cur;
+	} else 
+	    cur++;
+    }
+    if (cur != q) {
+        /*
+	 * Handle the last piece of text.
+	 */
+	if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
+	    xmlNodeAddContentLen(last, q, cur - q);
+	} else {
+	    node = xmlNewDocTextLen(doc, q, cur - q);
+	    if (node == NULL) return(ret);
+	    if (last == NULL)
+		last = ret = node;
+	    else {
+		last->next = node;
+		node->prev = last;
+		last = node;
+	    }
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlStringGetNodeList:
+ * @doc:  the document
+ * @value:  the value of the attribute
+ *
+ * Parse the value string and build the node list associated. Should
+ * produce a flat tree with only TEXTs and ENTITY_REFs.
+ * Returns a pointer to the first child
+ */
+xmlNodePtr
+xmlStringGetNodeList(xmlDocPtr doc, const xmlChar *value) {
+    xmlNodePtr ret = NULL, last = NULL;
+    xmlNodePtr node;
+    xmlChar *val;
+    const xmlChar *cur = value;
+    const xmlChar *q;
+    xmlEntityPtr ent;
+
+    if (value == NULL) return(NULL);
+
+    q = cur;
+    while (*cur != 0) {
+	if (*cur == '&') {
+	    /*
+	     * Save the current text.
+	     */
+            if (cur != q) {
+		if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
+		    xmlNodeAddContentLen(last, q, cur - q);
+		} else {
+		    node = xmlNewDocTextLen(doc, q, cur - q);
+		    if (node == NULL) return(ret);
+		    if (last == NULL)
+			last = ret = node;
+		    else {
+			last->next = node;
+			node->prev = last;
+			last = node;
+		    }
+		}
+	    }
+	    /*
+	     * Read the entity string
+	     */
+	    cur++;
+	    q = cur;
+	    while ((*cur != 0) && (*cur != ';')) cur++;
+	    if (*cur == 0) {
+#ifdef DEBUG_TREE
+	        xmlGenericError(xmlGenericErrorContext,
+		        "xmlStringGetNodeList: unterminated entity %30s\n", q);
+#endif
+	        return(ret);
+	    }
+            if (cur != q) {
+		/*
+		 * Predefined entities don't generate nodes
+		 */
+		val = xmlStrndup(q, cur - q);
+		ent = xmlGetDocEntity(doc, val);
+		if ((ent != NULL) &&
+		    (ent->etype == XML_INTERNAL_PREDEFINED_ENTITY)) {
+		    if (last == NULL) {
+		        node = xmlNewDocText(doc, ent->content);
+			last = ret = node;
+		    } else
+		        xmlNodeAddContent(last, ent->content);
+		        
+		} else {
+		    /*
+		     * Create a new REFERENCE_REF node
+		     */
+		    node = xmlNewReference(doc, val);
+		    if (node == NULL) {
+			if (val != NULL) xmlFree(val);
+		        return(ret);
+		    }
+		    if (last == NULL)
+			last = ret = node;
+		    else {
+			last->next = node;
+			node->prev = last;
+			last = node;
+		    }
+		}
+		xmlFree(val);
+	    }
+	    cur++;
+	    q = cur;
+	} else 
+	    cur++;
+    }
+    if (cur != q) {
+        /*
+	 * Handle the last piece of text.
+	 */
+	if ((last != NULL) && (last->type == XML_TEXT_NODE)) {
+	    xmlNodeAddContentLen(last, q, cur - q);
+	} else {
+	    node = xmlNewDocTextLen(doc, q, cur - q);
+	    if (node == NULL) return(ret);
+	    if (last == NULL)
+		last = ret = node;
+	    else {
+		last->next = node;
+		node->prev = last;
+		last = node;
+	    }
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlNodeListGetString:
+ * @doc:  the document
+ * @list:  a Node list
+ * @inLine:  should we replace entity contents or show their external form
+ *
+ * Returns the string equivalent to the text contained in the Node list
+ * made of TEXTs and ENTITY_REFs
+ * Returns a pointer to the string copy, the calller must free it.
+ */
+xmlChar *
+xmlNodeListGetString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
+    xmlNodePtr node = list;
+    xmlChar *ret = NULL;
+    xmlEntityPtr ent;
+
+    if (list == NULL) return(NULL);
+
+    while (node != NULL) {
+        if ((node->type == XML_TEXT_NODE) ||
+	    (node->type == XML_CDATA_SECTION_NODE)) {
+	    if (inLine) {
+#ifndef XML_USE_BUFFER_CONTENT
+		ret = xmlStrcat(ret, node->content);
+#else
+		ret = xmlStrcat(ret, xmlBufferContent(node->content));
+#endif
+	    } else {
+	        xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+		buffer = xmlEncodeEntitiesReentrant(doc, node->content);
+#else
+		buffer = xmlEncodeEntitiesReentrant(doc,
+					    xmlBufferContent(node->content));
+#endif
+		if (buffer != NULL) {
+		    ret = xmlStrcat(ret, buffer);
+		    xmlFree(buffer);
+		}
+            }
+	} else if (node->type == XML_ENTITY_REF_NODE) {
+	    if (inLine) {
+		ent = xmlGetDocEntity(doc, node->name);
+		if (ent != NULL)
+		    ret = xmlStrcat(ret, ent->content);
+		else {
+#ifndef XML_USE_BUFFER_CONTENT
+		    ret = xmlStrcat(ret, node->content);
+#else
+		    ret = xmlStrcat(ret, xmlBufferContent(node->content));
+#endif
+		}    
+            } else {
+	        xmlChar buf[2];
+		buf[0] = '&'; buf[1] = 0;
+		ret = xmlStrncat(ret, buf, 1);
+		ret = xmlStrcat(ret, node->name);
+		buf[0] = ';'; buf[1] = 0;
+		ret = xmlStrncat(ret, buf, 1);
+	    }
+	}
+#if 0
+	else {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlGetNodeListString : invalide node type %d\n",
+	            node->type);
+	}
+#endif
+	node = node->next;
+    }
+    return(ret);
+}
+
+/**
+ * xmlNodeListGetRawString:
+ * @doc:  the document
+ * @list:  a Node list
+ * @inLine:  should we replace entity contents or show their external form
+ *
+ * Returns the string equivalent to the text contained in the Node list
+ * made of TEXTs and ENTITY_REFs, contrary to xmlNodeListGetString()
+ * this function doesn't do any character encoding handling.
+ *
+ * Returns a pointer to the string copy, the calller must free it.
+ */
+xmlChar *
+xmlNodeListGetRawString(xmlDocPtr doc, xmlNodePtr list, int inLine) {
+    xmlNodePtr node = list;
+    xmlChar *ret = NULL;
+    xmlEntityPtr ent;
+
+    if (list == NULL) return(NULL);
+
+    while (node != NULL) {
+        if (node->type == XML_TEXT_NODE) {
+	    if (inLine) {
+#ifndef XML_USE_BUFFER_CONTENT
+		ret = xmlStrcat(ret, node->content);
+#else
+		ret = xmlStrcat(ret, xmlBufferContent(node->content));
+#endif
+	    } else {
+	        xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+		buffer = xmlEncodeSpecialChars(doc, node->content);
+#else
+		buffer = xmlEncodeSpecialChars(doc,
+					    xmlBufferContent(node->content));
+#endif
+		if (buffer != NULL) {
+		    ret = xmlStrcat(ret, buffer);
+		    xmlFree(buffer);
+		}
+            }
+	} else if (node->type == XML_ENTITY_REF_NODE) {
+	    if (inLine) {
+		ent = xmlGetDocEntity(doc, node->name);
+		if (ent != NULL)
+		    ret = xmlStrcat(ret, ent->content);
+		else {
+#ifndef XML_USE_BUFFER_CONTENT
+		    ret = xmlStrcat(ret, node->content);
+#else
+		    ret = xmlStrcat(ret, xmlBufferContent(node->content));
+#endif
+		}    
+            } else {
+	        xmlChar buf[2];
+		buf[0] = '&'; buf[1] = 0;
+		ret = xmlStrncat(ret, buf, 1);
+		ret = xmlStrcat(ret, node->name);
+		buf[0] = ';'; buf[1] = 0;
+		ret = xmlStrncat(ret, buf, 1);
+	    }
+	}
+#if 0
+	else {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlGetNodeListString : invalide node type %d\n",
+	            node->type);
+	}
+#endif
+	node = node->next;
+    }
+    return(ret);
+}
+
+/**
+ * xmlNewProp:
+ * @node:  the holding node
+ * @name:  the name of the attribute
+ * @value:  the value of the attribute
+ *
+ * Create a new property carried by a node.
+ * Returns a pointer to the attribute
+ */
+xmlAttrPtr
+xmlNewProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
+    xmlAttrPtr cur;
+    xmlDocPtr doc = NULL;
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewProp : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new property and fill the fields.
+     */
+    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewProp : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlAttr));
+    cur->type = XML_ATTRIBUTE_NODE;
+
+    cur->parent = node; 
+    if (node != NULL) {
+	doc = node->doc;
+	cur->doc = doc;
+    }
+    cur->name = xmlStrdup(name);
+    if (value != NULL) {
+	xmlChar *buffer;
+	xmlNodePtr tmp;
+
+	buffer = xmlEncodeEntitiesReentrant(doc, value);
+	cur->children = xmlStringGetNodeList(doc, buffer);
+	cur->last = NULL;
+	tmp = cur->children;
+	while (tmp != NULL) {
+	    tmp->parent = (xmlNodePtr) cur;
+	    tmp->doc = doc;
+	    if (tmp->next == NULL)
+		cur->last = tmp;
+	    tmp = tmp->next;
+	}
+	xmlFree(buffer);
+    }	
+
+    /*
+     * Add it at the end to preserve parsing order ...
+     */
+    if (node != NULL) {
+	if (node->properties == NULL) {
+	    node->properties = cur;
+	} else {
+	    xmlAttrPtr prev = node->properties;
+
+	    while (prev->next != NULL) prev = prev->next;
+	    prev->next = cur;
+	    cur->prev = prev;
+	}
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewNsProp:
+ * @node:  the holding node
+ * @ns:  the namespace
+ * @name:  the name of the attribute
+ * @value:  the value of the attribute
+ *
+ * Create a new property tagged with a namespace and carried by a node.
+ * Returns a pointer to the attribute
+ */
+xmlAttrPtr
+xmlNewNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
+           const xmlChar *value) {
+    xmlAttrPtr cur;
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewProp : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new property and fill the fields.
+     */
+    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewProp : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlAttr));
+    cur->type = XML_ATTRIBUTE_NODE;
+
+    cur->parent = node; 
+    if (node != NULL)
+	cur->doc = node->doc; 
+    cur->ns = ns;
+    cur->name = xmlStrdup(name);
+    if (value != NULL) {
+	xmlChar *buffer;
+	xmlNodePtr tmp;
+
+	buffer = xmlEncodeEntitiesReentrant(node->doc, value);
+	cur->children = xmlStringGetNodeList(node->doc, buffer);
+	cur->last = NULL;
+	tmp = cur->children;
+	while (tmp != NULL) {
+	    tmp->parent = (xmlNodePtr) cur;
+	    if (tmp->next == NULL)
+		cur->last = tmp;
+	    tmp = tmp->next;
+	}
+	xmlFree(buffer);
+    }
+
+    /*
+     * Add it at the end to preserve parsing order ...
+     */
+    if (node != NULL) {
+	if (node->properties == NULL) {
+	    node->properties = cur;
+	} else {
+	    xmlAttrPtr prev = node->properties;
+
+	    while (prev->next != NULL) prev = prev->next;
+	    prev->next = cur;
+	    cur->prev = prev;
+	}
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewDocProp:
+ * @doc:  the document
+ * @name:  the name of the attribute
+ * @value:  the value of the attribute
+ *
+ * Create a new property carried by a document.
+ * Returns a pointer to the attribute
+ */
+xmlAttrPtr
+xmlNewDocProp(xmlDocPtr doc, const xmlChar *name, const xmlChar *value) {
+    xmlAttrPtr cur;
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewProp : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new property and fill the fields.
+     */
+    cur = (xmlAttrPtr) xmlMalloc(sizeof(xmlAttr));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewProp : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlAttr));
+    cur->type = XML_ATTRIBUTE_NODE;
+
+    cur->name = xmlStrdup(name);
+    cur->doc = doc; 
+    if (value != NULL) {
+	xmlNodePtr tmp;
+
+	cur->children = xmlStringGetNodeList(doc, value);
+	cur->last = NULL;
+
+	tmp = cur->children;
+	while (tmp != NULL) {
+	    tmp->parent = (xmlNodePtr) cur;
+	    if (tmp->next == NULL)
+		cur->last = tmp;
+	    tmp = tmp->next;
+	}
+    }
+    return(cur);
+}
+
+/**
+ * xmlFreePropList:
+ * @cur:  the first property in the list
+ *
+ * Free a property and all its siblings, all the children are freed too.
+ */
+void
+xmlFreePropList(xmlAttrPtr cur) {
+    xmlAttrPtr next;
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreePropList : property == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+        next = cur->next;
+        xmlFreeProp(cur);
+	cur = next;
+    }
+}
+
+/**
+ * xmlFreeProp:
+ * @cur:  an attribute
+ *
+ * Free one attribute, all the content is freed too
+ */
+void
+xmlFreeProp(xmlAttrPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeProp : property == NULL\n");
+#endif
+	return;
+    }
+    /* Check for ID removal -> leading to invalid references ! */
+    if ((cur->parent != NULL) && 
+        (xmlIsID(cur->parent->doc, cur->parent, cur)))
+        xmlRemoveID(cur->parent->doc, cur);
+    if (cur->name != NULL) xmlFree((char *) cur->name);
+    if (cur->children != NULL) xmlFreeNodeList(cur->children);
+    memset(cur, -1, sizeof(xmlAttr));
+    xmlFree(cur);
+}
+
+/**
+ * xmlRemoveProp:
+ * @cur:  an attribute
+ *
+ * Unlink and free one attribute, all the content is freed too
+ * Note this doesn't work for namespace definition attributes
+ *
+ * Returns 0 if success and -1 in case of error.
+ */
+int
+xmlRemoveProp(xmlAttrPtr cur) {
+    xmlAttrPtr tmp;
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlRemoveProp : cur == NULL\n");
+#endif
+	return(-1);
+    }
+    if (cur->parent == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlRemoveProp : cur->parent == NULL\n");
+#endif
+	return(-1);
+    }
+    tmp = cur->parent->properties;
+    if (tmp == cur) {
+        cur->parent->properties = cur->next;
+	xmlFreeProp(cur);
+	return(0);
+    }
+    while (tmp != NULL) {
+	if (tmp->next == cur) {
+	    tmp->next = cur->next;
+	    if (tmp->next != NULL)
+		tmp->next->prev = tmp;
+	    xmlFreeProp(cur);
+	    return(0);
+	}
+        tmp = tmp->next;
+    }
+#ifdef DEBUG_TREE
+    xmlGenericError(xmlGenericErrorContext,
+	    "xmlRemoveProp : attribute not owned by its node\n");
+#endif
+    return(-1);
+}
+
+/**
+ * xmlNewPI:
+ * @name:  the processing instruction name
+ * @content:  the PI content
+ *
+ * Creation of a processing instruction element.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewPI(const xmlChar *name, const xmlChar *content) {
+    xmlNodePtr cur;
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewPI : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewPI : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_PI_NODE;
+
+    cur->name = xmlStrdup(name);
+    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	cur->content = xmlStrdup(content);
+#else
+	cur->content = xmlBufferCreateSize(0);
+	xmlBufferSetAllocationScheme(cur->content,
+		                     xmlGetBufferAllocationScheme());
+	xmlBufferAdd(cur->content, content, -1);
+#endif
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewNode:
+ * @ns:  namespace if any
+ * @name:  the node name
+ *
+ * Creation of a new node element. @ns is optionnal (NULL).
+ *
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewNode(xmlNsPtr ns, const xmlChar *name) {
+    xmlNodePtr cur;
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewNode : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewNode : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_ELEMENT_NODE;
+    
+    cur->name = xmlStrdup(name);
+    cur->ns = ns;
+    return(cur);
+}
+
+/**
+ * xmlNewDocNode:
+ * @doc:  the document
+ * @ns:  namespace if any
+ * @name:  the node name
+ * @content:  the XML text content if any
+ *
+ * Creation of a new node element within a document. @ns and @content
+ * are optionnal (NULL).
+ * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
+ *       references, but XML special chars need to be escaped first by using
+ *       xmlEncodeEntitiesReentrant(). Use xmlNewDocRawNode() if you don't
+ *       need entities support.
+ *
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewDocNode(xmlDocPtr doc, xmlNsPtr ns,
+              const xmlChar *name, const xmlChar *content) {
+    xmlNodePtr cur;
+
+    cur = xmlNewNode(ns, name);
+    if (cur != NULL) {
+        cur->doc = doc;
+	if (content != NULL) {
+	    cur->children = xmlStringGetNodeList(doc, content);
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
+	}
+    }
+    return(cur);
+}
+
+
+/**
+ * xmlNewDocRawNode:
+ * @doc:  the document
+ * @ns:  namespace if any
+ * @name:  the node name
+ * @content:  the text content if any
+ *
+ * Creation of a new node element within a document. @ns and @content
+ * are optionnal (NULL).
+ *
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewDocRawNode(xmlDocPtr doc, xmlNsPtr ns,
+                 const xmlChar *name, const xmlChar *content) {
+    xmlNodePtr cur;
+
+    cur = xmlNewNode(ns, name);
+    if (cur != NULL) {
+        cur->doc = doc;
+	if (content != NULL) {
+	    cur->children = xmlNewDocText(doc, content);
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
+	}
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewDocFragment:
+ * @doc:  the document owning the fragment
+ *
+ * Creation of a new Fragment node.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewDocFragment(xmlDocPtr doc) {
+    xmlNodePtr cur;
+
+    /*
+     * Allocate a new DocumentFragment node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewDocFragment : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_DOCUMENT_FRAG_NODE;
+
+    cur->doc = doc;
+    return(cur);
+}
+
+/**
+ * xmlNewText:
+ * @content:  the text content
+ *
+ * Creation of a new text node.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewText(const xmlChar *content) {
+    xmlNodePtr cur;
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewText : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_TEXT_NODE;
+
+    cur->name = xmlStringText;
+    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	cur->content = xmlStrdup(content);
+#else
+	cur->content = xmlBufferCreateSize(0);
+	xmlBufferSetAllocationScheme(cur->content,
+		                     xmlGetBufferAllocationScheme());
+	xmlBufferAdd(cur->content, content, -1);
+#endif
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewTextChild:
+ * @parent:  the parent node
+ * @ns:  a namespace if any
+ * @name:  the name of the child
+ * @content:  the text content of the child if any.
+ *
+ * Creation of a new child element, added at the end of @parent children list.
+ * @ns and @content parameters are optionnal (NULL). If content is non NULL,
+ * a child TEXT node will be created containing the string content.
+ *
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewTextChild(xmlNodePtr parent, xmlNsPtr ns,
+            const xmlChar *name, const xmlChar *content) {
+    xmlNodePtr cur, prev;
+
+    if (parent == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewTextChild : parent == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewTextChild : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new node
+     */
+    if (ns == NULL)
+	cur = xmlNewDocRawNode(parent->doc, parent->ns, name, content);
+    else
+	cur = xmlNewDocRawNode(parent->doc, ns, name, content);
+    if (cur == NULL) return(NULL);
+
+    /*
+     * add the new element at the end of the children list.
+     */
+    cur->type = XML_ELEMENT_NODE;
+    cur->parent = parent;
+    cur->doc = parent->doc;
+    if (parent->children == NULL) {
+        parent->children = cur;
+	parent->last = cur;
+    } else {
+        prev = parent->last;
+	prev->next = cur;
+	cur->prev = prev;
+	parent->last = cur;
+    }
+
+    return(cur);
+}
+
+/**
+ * xmlNewCharRef:
+ * @doc: the document
+ * @name:  the char ref string, starting with # or "&# ... ;"
+ *
+ * Creation of a new character reference node.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewCharRef(xmlDocPtr doc, const xmlChar *name) {
+    xmlNodePtr cur;
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewText : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_ENTITY_REF_NODE;
+
+    cur->doc = doc;
+    if (name[0] == '&') {
+        int len;
+        name++;
+	len = xmlStrlen(name);
+	if (name[len - 1] == ';')
+	    cur->name = xmlStrndup(name, len - 1);
+	else
+	    cur->name = xmlStrndup(name, len);
+    } else
+	cur->name = xmlStrdup(name);
+    return(cur);
+}
+
+/**
+ * xmlNewReference:
+ * @doc: the document
+ * @name:  the reference name, or the reference string with & and ;
+ *
+ * Creation of a new reference node.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewReference(xmlDocPtr doc, const xmlChar *name) {
+    xmlNodePtr cur;
+    xmlEntityPtr ent;
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewText : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_ENTITY_REF_NODE;
+
+    cur->doc = doc;
+    if (name[0] == '&') {
+        int len;
+        name++;
+	len = xmlStrlen(name);
+	if (name[len - 1] == ';')
+	    cur->name = xmlStrndup(name, len - 1);
+	else
+	    cur->name = xmlStrndup(name, len);
+    } else
+	cur->name = xmlStrdup(name);
+
+    ent = xmlGetDocEntity(doc, cur->name);
+    if (ent != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	cur->content = ent->content;
+#else
+	/*
+	 * CJN 11.18.99 this might be a problem, since the xmlBuffer gets
+	 * a copy of this pointer.  Let's hope we don't manipulate it
+	 * later 
+	 */
+	cur->content = xmlBufferCreateSize(0);
+	xmlBufferSetAllocationScheme(cur->content,
+		                     xmlGetBufferAllocationScheme());
+	if (ent->content != NULL)
+	    xmlBufferAdd(cur->content, ent->content, -1);
+#endif
+	/*
+	 * The parent pointer in entity is a Dtd pointer and thus is NOT
+	 * updated.  Not sure if this is 100% correct.
+	 *  -George
+	 */
+	cur->children = (xmlNodePtr) ent;
+	cur->last = (xmlNodePtr) ent;
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewDocText:
+ * @doc: the document
+ * @content:  the text content
+ *
+ * Creation of a new text node within a document.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewDocText(xmlDocPtr doc, const xmlChar *content) {
+    xmlNodePtr cur;
+
+    cur = xmlNewText(content);
+    if (cur != NULL) cur->doc = doc;
+    return(cur);
+}
+
+/**
+ * xmlNewTextLen:
+ * @content:  the text content
+ * @len:  the text len.
+ *
+ * Creation of a new text node with an extra parameter for the content's lenght
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewTextLen(const xmlChar *content, int len) {
+    xmlNodePtr cur;
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewText : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_TEXT_NODE;
+
+    cur->name = xmlStringText;
+    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	cur->content = xmlStrndup(content, len);
+#else
+	cur->content = xmlBufferCreateSize(len);
+	xmlBufferSetAllocationScheme(cur->content,
+		                     xmlGetBufferAllocationScheme());
+	xmlBufferAdd(cur->content, content, len);
+#endif
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewDocTextLen:
+ * @doc: the document
+ * @content:  the text content
+ * @len:  the text len.
+ *
+ * Creation of a new text node with an extra content lenght parameter. The
+ * text node pertain to a given document.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewDocTextLen(xmlDocPtr doc, const xmlChar *content, int len) {
+    xmlNodePtr cur;
+
+    cur = xmlNewTextLen(content, len);
+    if (cur != NULL) cur->doc = doc;
+    return(cur);
+}
+
+/**
+ * xmlNewComment:
+ * @content:  the comment content
+ *
+ * Creation of a new node containing a comment.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewComment(const xmlChar *content) {
+    xmlNodePtr cur;
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewComment : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_COMMENT_NODE;
+
+    cur->name = xmlStringComment;
+    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	cur->content = xmlStrdup(content);
+#else
+	cur->content = xmlBufferCreateSize(0);
+	xmlBufferSetAllocationScheme(cur->content,
+		                     xmlGetBufferAllocationScheme());
+	xmlBufferAdd(cur->content, content, -1);
+#endif
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewCDataBlock:
+ * @doc:  the document
+ * @content:  the CData block content content
+ * @len:  the length of the block
+ *
+ * Creation of a new node containing a CData block.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewCDataBlock(xmlDocPtr doc, const xmlChar *content, int len) {
+    xmlNodePtr cur;
+
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    cur = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (cur == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewCDataBlock : malloc failed\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlNode));
+    cur->type = XML_CDATA_SECTION_NODE;
+
+    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	cur->content = xmlStrndup(content, len);
+#else
+	cur->content = xmlBufferCreateSize(len);
+	xmlBufferSetAllocationScheme(cur->content,
+		                     xmlGetBufferAllocationScheme());
+	xmlBufferAdd(cur->content, content, len);
+#endif
+    }
+    return(cur);
+}
+
+/**
+ * xmlNewDocComment:
+ * @doc:  the document
+ * @content:  the comment content
+ *
+ * Creation of a new node containing a commentwithin a document.
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewDocComment(xmlDocPtr doc, const xmlChar *content) {
+    xmlNodePtr cur;
+
+    cur = xmlNewComment(content);
+    if (cur != NULL) cur->doc = doc;
+    return(cur);
+}
+
+/**
+ * xmlSetTreeDoc:
+ * @tree:  the top element
+ * @doc:  the document
+ *
+ * update all nodes under the tree to point to the right document
+ */
+void
+xmlSetTreeDoc(xmlNodePtr tree, xmlDocPtr doc) {
+    if (tree == NULL)
+	return;
+    if (tree->type == XML_ENTITY_DECL)
+	return;
+    if (tree->doc != doc) {
+	if (tree->children != NULL)
+	    xmlSetListDoc(tree->children, doc);
+	tree->doc = doc;
+    }
+}
+
+/**
+ * xmlSetListDoc:
+ * @tree:  the first element
+ * @doc:  the document
+ *
+ * update all nodes in the list to point to the right document
+ */
+void
+xmlSetListDoc(xmlNodePtr list, xmlDocPtr doc) {
+    xmlNodePtr cur;
+
+    if (list == NULL)
+	return;
+    cur = list;
+    while (cur != NULL) {
+	if (cur->doc != doc)
+	    xmlSetTreeDoc(cur, doc);
+	cur = cur->next;
+    }
+}
+
+
+/**
+ * xmlNewChild:
+ * @parent:  the parent node
+ * @ns:  a namespace if any
+ * @name:  the name of the child
+ * @content:  the XML content of the child if any.
+ *
+ * Creation of a new child element, added at the end of @parent children list.
+ * @ns and @content parameters are optionnal (NULL). If content is non NULL,
+ * a child list containing the TEXTs and ENTITY_REFs node will be created.
+ * NOTE: @content is supposed to be a piece of XML CDATA, so it allow entities
+ *       references, but XML special chars need to be escaped first by using
+ *       xmlEncodeEntitiesReentrant(). Use xmlNewTextChild() if entities
+ *       support is not needed.
+ *
+ * Returns a pointer to the new node object.
+ */
+xmlNodePtr
+xmlNewChild(xmlNodePtr parent, xmlNsPtr ns,
+            const xmlChar *name, const xmlChar *content) {
+    xmlNodePtr cur, prev;
+
+    if (parent == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewChild : parent == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if (name == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewChild : name == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Allocate a new node
+     */
+    if (ns == NULL)
+	cur = xmlNewDocNode(parent->doc, parent->ns, name, content);
+    else
+	cur = xmlNewDocNode(parent->doc, ns, name, content);
+    if (cur == NULL) return(NULL);
+
+    /*
+     * add the new element at the end of the children list.
+     */
+    cur->type = XML_ELEMENT_NODE;
+    cur->parent = parent;
+    cur->doc = parent->doc;
+    if (parent->children == NULL) {
+        parent->children = cur;
+	parent->last = cur;
+    } else {
+        prev = parent->last;
+	prev->next = cur;
+	cur->prev = prev;
+	parent->last = cur;
+    }
+
+    return(cur);
+}
+
+/**
+ * xmlAddNextSibling:
+ * @cur:  the child node
+ * @elem:  the new node
+ *
+ * Add a new element @elem as the next siblings of @cur
+ * If the new element was already inserted in a document it is
+ * first unlinked from its existing context.
+ * As a result of text merging @elem may be freed.
+ *
+ * Returns the new element or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddNextSibling(xmlNodePtr cur, xmlNodePtr elem) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNextSibling : cur == NULL\n");
+#endif
+	return(NULL);
+    }
+    if (elem == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNextSibling : elem == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    xmlUnlinkNode(elem);
+
+    if (elem->type == XML_TEXT_NODE) {
+	if (cur->type == XML_TEXT_NODE) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlNodeAddContent(cur, elem->content);
+#else
+	    xmlNodeAddContent(cur, xmlBufferContent(elem->content));
+#endif
+	    xmlFreeNode(elem);
+	    return(cur);
+	}
+	if ((cur->next != NULL) && (cur->type == XML_TEXT_NODE)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlChar *tmp;
+
+	    tmp = xmlStrdup(elem->content);
+	    tmp = xmlStrcat(tmp, cur->next->content);
+	    xmlNodeSetContent(cur->next, tmp);
+	    xmlFree(tmp);
+#else
+	    xmlBufferAddHead(cur->next->content,
+		             xmlBufferContent(elem->content),
+			     xmlBufferLength(elem->content));
+#endif
+	    xmlFreeNode(elem);
+	    return(cur->next);
+	}
+    }
+
+    if (elem->doc != cur->doc) {
+	xmlSetTreeDoc(elem, cur->doc);
+    }
+    elem->parent = cur->parent;
+    elem->prev = cur;
+    elem->next = cur->next;
+    cur->next = elem;
+    if (elem->next != NULL)
+	elem->next->prev = elem;
+    if ((elem->parent != NULL) && (elem->parent->last == cur))
+	elem->parent->last = elem;
+    return(elem);
+}
+
+/**
+ * xmlAddPrevSibling:
+ * @cur:  the child node
+ * @elem:  the new node
+ *
+ * Add a new element @elem as the previous siblings of @cur
+ * merging adjacent TEXT nodes (@elem may be freed)
+ * If the new element was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the new element or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddPrevSibling(xmlNodePtr cur, xmlNodePtr elem) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddPrevSibling : cur == NULL\n");
+#endif
+	return(NULL);
+    }
+    if (elem == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddPrevSibling : elem == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    xmlUnlinkNode(elem);
+
+    if (elem->type == XML_TEXT_NODE) {
+	if (cur->type == XML_TEXT_NODE) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlChar *tmp;
+
+	    tmp = xmlStrdup(elem->content);
+	    tmp = xmlStrcat(tmp, cur->content);
+	    xmlNodeSetContent(cur, tmp);
+	    xmlFree(tmp);
+#else
+	    xmlBufferAddHead(cur->content, xmlBufferContent(elem->content), 
+			     xmlBufferLength(elem->content));
+#endif
+	    xmlFreeNode(elem);
+	    return(cur);
+	}
+	if ((cur->prev != NULL) && (cur->prev->type == XML_TEXT_NODE)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlNodeAddContent(cur->prev, elem->content);
+#else
+	    xmlNodeAddContent(cur->prev, xmlBufferContent(elem->content));
+#endif
+	    xmlFreeNode(elem);
+	    return(cur->prev);
+	}
+    }
+
+    if (elem->doc != cur->doc) {
+	xmlSetTreeDoc(elem, cur->doc);
+    }
+    elem->parent = cur->parent;
+    elem->next = cur;
+    elem->prev = cur->prev;
+    cur->prev = elem;
+    if (elem->prev != NULL)
+	elem->prev->next = elem;
+    if ((elem->parent != NULL) && (elem->parent->children == cur))
+	elem->parent->children = elem;
+    return(elem);
+}
+
+/**
+ * xmlAddSibling:
+ * @cur:  the child node
+ * @elem:  the new node
+ *
+ * Add a new element @elem to the list of siblings of @cur
+ * merging adjacent TEXT nodes (@elem may be freed)
+ * If the new element was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the new element or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddSibling(xmlNodePtr cur, xmlNodePtr elem) {
+    xmlNodePtr parent;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddSibling : cur == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if (elem == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddSibling : elem == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    /*
+     * Constant time is we can rely on the ->parent->last to find
+     * the last sibling.
+     */
+    if ((cur->parent != NULL) && 
+	(cur->parent->children != NULL) &&
+	(cur->parent->last != NULL) &&
+	(cur->parent->last->next == NULL)) {
+	cur = cur->parent->last;
+    } else {
+	while (cur->next != NULL) cur = cur->next;
+    }
+
+    xmlUnlinkNode(elem);
+
+    if ((cur->type == XML_TEXT_NODE) && (elem->type == XML_TEXT_NODE)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	xmlNodeAddContent(cur, elem->content);
+#else
+	xmlNodeAddContent(cur, xmlBufferContent(elem->content));
+#endif
+	xmlFreeNode(elem);
+	return(cur);
+    }
+
+    if (elem->doc != cur->doc) {
+	xmlSetTreeDoc(elem, cur->doc);
+    }
+    parent = cur->parent;
+    elem->prev = cur;
+    elem->next = NULL;
+    elem->parent = parent;
+    cur->next = elem;
+    if (parent != NULL)
+	parent->last = elem;
+
+    return(elem);
+}
+
+/**
+ * xmlAddChildList:
+ * @parent:  the parent node
+ * @cur:  the first node in the list
+ *
+ * Add a list of node at the end of the child list of the parent
+ * merging adjacent TEXT nodes (@cur may be freed)
+ *
+ * Returns the last child or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddChildList(xmlNodePtr parent, xmlNodePtr cur) {
+    xmlNodePtr prev;
+
+    if (parent == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddChild : parent == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddChild : child == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if ((cur->doc != NULL) && (parent->doc != NULL) &&
+        (cur->doc != parent->doc)) {
+#ifdef DEBUG_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"Elements moved to a different document\n");
+#endif
+    }
+
+    /*
+     * add the first element at the end of the children list.
+     */
+    if (parent->children == NULL) {
+        parent->children = cur;
+    } else {
+	/*
+	 * If cur and parent->last both are TEXT nodes, then merge them.
+	 */
+	if ((cur->type == XML_TEXT_NODE) && 
+	    (parent->last->type == XML_TEXT_NODE) &&
+	    (cur->name == parent->last->name)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlNodeAddContent(parent->last, cur->content);
+#else
+	    xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
+#endif
+	    /*
+	     * if it's the only child, nothing more to be done.
+	     */
+	    if (cur->next == NULL) {
+		xmlFreeNode(cur);
+		return(parent->last);
+	    }
+	    prev = cur;
+	    cur = cur->next;
+	    xmlFreeNode(prev);
+	}
+        prev = parent->last;
+	prev->next = cur;
+	cur->prev = prev;
+    }
+    while (cur->next != NULL) {
+	cur->parent = parent;
+	if (cur->doc != parent->doc) {
+	    xmlSetTreeDoc(cur, parent->doc);
+	}
+        cur = cur->next;
+    }
+    cur->parent = parent;
+    cur->doc = parent->doc; /* the parent may not be linked to a doc ! */
+    parent->last = cur;
+
+    return(cur);
+}
+
+/**
+ * xmlAddChild:
+ * @parent:  the parent node
+ * @cur:  the child node
+ *
+ * Add a new child element, to @parent, at the end of the child list
+ * merging adjacent TEXT nodes (in which case @cur is freed)
+ * Returns the child or NULL in case of error.
+ */
+xmlNodePtr
+xmlAddChild(xmlNodePtr parent, xmlNodePtr cur) {
+    xmlNodePtr prev;
+
+    if (parent == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddChild : parent == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddChild : child == NULL\n");
+#endif
+	return(NULL);
+    }
+
+    if ((cur->doc != NULL) && (parent->doc != NULL) &&
+        (cur->doc != parent->doc)) {
+#ifdef DEBUG_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"Elements moved to a different document\n");
+#endif
+    }
+
+    /*
+     * If cur is a TEXT node, merge its content with adjacent TEXT nodes
+     * or with parent->content if parent->content != NULL.
+     * cur is then freed.
+     */
+    if (cur->type == XML_TEXT_NODE) {
+	if (((parent->type == XML_ELEMENT_NODE) || 
+	     (parent->type == XML_TEXT_NODE)) &&
+	    (parent->content != NULL)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlNodeAddContent(parent, cur->content);
+#else
+	    xmlNodeAddContent(parent, xmlBufferContent(cur->content));
+#endif
+	    xmlFreeNode(cur);
+	    return(parent);
+	}
+	if ((parent->last != NULL) && (parent->last->type == XML_TEXT_NODE) &&
+	    (parent->last->name == cur->name)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlNodeAddContent(parent->last, cur->content);
+#else
+	    xmlNodeAddContent(parent->last, xmlBufferContent(cur->content));
+#endif
+	    xmlFreeNode(cur);
+	    return(parent->last);
+	}
+    }
+
+    /*
+     * add the new element at the end of the children list.
+     */
+    cur->parent = parent;
+    if (cur->doc != parent->doc) {
+	xmlSetTreeDoc(cur, parent->doc);
+    }
+
+    /*
+     * Handle the case where parent->content != NULL, in that case it will
+     * create a intermediate TEXT node.
+     */
+    if (((parent->type == XML_ELEMENT_NODE) || (parent->type == XML_TEXT_NODE)) &&
+	(parent->content != NULL)) {
+        xmlNodePtr text;
+	
+#ifndef XML_USE_BUFFER_CONTENT
+	text = xmlNewDocText(parent->doc, parent->content);
+#else
+	text = xmlNewDocText(parent->doc, xmlBufferContent(parent->content));
+#endif
+	if (text != NULL) {
+	    text->next = parent->children;
+	    if (text->next != NULL)
+		text->next->prev = text;
+	    parent->children = text;
+	    UPDATE_LAST_CHILD_AND_PARENT(parent)
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlFree(parent->content);
+#else
+	    xmlBufferFree(parent->content);
+#endif
+	    parent->content = NULL;
+	}
+    }
+    if (parent->children == NULL) {
+        parent->children = cur;
+	parent->last = cur;
+    } else {
+        prev = parent->last;
+	prev->next = cur;
+	cur->prev = prev;
+	parent->last = cur;
+    }
+
+    return(cur);
+}
+
+/**
+ * xmlGetLastChild:
+ * @parent:  the parent node
+ *
+ * Search the last child of a node.
+ * Returns the last child or NULL if none.
+ */
+xmlNodePtr
+xmlGetLastChild(xmlNodePtr parent) {
+    if (parent == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlGetLastChild : parent == NULL\n");
+#endif
+	return(NULL);
+    }
+    return(parent->last);
+}
+
+/**
+ * xmlFreeNodeList:
+ * @cur:  the first node in the list
+ *
+ * Free a node and all its siblings, this is a recursive behaviour, all
+ * the children are freed too.
+ */
+void
+xmlFreeNodeList(xmlNodePtr cur) {
+    xmlNodePtr next;
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeNodeList : node == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+        next = cur->next;
+        xmlFreeNode(cur);
+	cur = next;
+    }
+}
+
+/**
+ * xmlFreeNode:
+ * @cur:  the node
+ *
+ * Free a node, this is a recursive behaviour, all the children are freed too.
+ * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
+ */
+void
+xmlFreeNode(xmlNodePtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlFreeNode : node == NULL\n");
+#endif
+	return;
+    }
+    if (cur->type == XML_DTD_NODE)
+	return;
+    cur->doc = NULL;
+    cur->parent = NULL;
+    cur->next = NULL;
+    cur->prev = NULL;
+    if ((cur->children != NULL) &&
+	(cur->type != XML_ENTITY_REF_NODE))
+	xmlFreeNodeList(cur->children);
+    if (cur->properties != NULL) xmlFreePropList(cur->properties);
+    if (cur->type != XML_ENTITY_REF_NODE)
+#ifndef XML_USE_BUFFER_CONTENT
+	if (cur->content != NULL) xmlFree(cur->content);
+#else
+    	if (cur->content != NULL) xmlBufferFree(cur->content);
+#endif
+    if ((cur->name != NULL) &&
+	(cur->name != xmlStringText) &&
+	(cur->name != xmlStringTextNoenc) &&
+	(cur->name != xmlStringComment))
+	xmlFree((char *) cur->name);
+    if (cur->nsDef != NULL) xmlFreeNsList(cur->nsDef);
+    memset(cur, -1, sizeof(xmlNode));
+    xmlFree(cur);
+}
+
+/**
+ * xmlUnlinkNode:
+ * @cur:  the node
+ *
+ * Unlink a node from it's current context, the node is not freed
+ */
+void
+xmlUnlinkNode(xmlNodePtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlUnlinkNode : node == NULL\n");
+#endif
+	return;
+    }
+    if ((cur->parent != NULL) && (cur->parent->children == cur))
+        cur->parent->children = cur->next;
+    if ((cur->parent != NULL) && (cur->parent->last == cur))
+        cur->parent->last = cur->prev;
+    if (cur->next != NULL)
+        cur->next->prev = cur->prev;
+    if (cur->prev != NULL)
+        cur->prev->next = cur->next;
+    cur->next = cur->prev = NULL;
+    cur->parent = NULL;
+}
+
+/**
+ * xmlReplaceNode:
+ * @old:  the old node
+ * @cur:  the node
+ *
+ * Unlink the old node from it's current context, prune the new one
+ * at the same place. If cur was already inserted in a document it is
+ * first unlinked from its existing context.
+ *
+ * Returns the old node
+ */
+xmlNodePtr
+xmlReplaceNode(xmlNodePtr old, xmlNodePtr cur) {
+    if (old == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlReplaceNode : old == NULL\n");
+#endif
+	return(NULL);
+    }
+    if (cur == NULL) {
+	xmlUnlinkNode(old);
+	return(old);
+    }
+    if (cur == old) {
+	return(old);
+    }
+    xmlUnlinkNode(cur);
+    cur->doc = old->doc;
+    cur->parent = old->parent;
+    cur->next = old->next;
+    if (cur->next != NULL)
+	cur->next->prev = cur;
+    cur->prev = old->prev;
+    if (cur->prev != NULL)
+	cur->prev->next = cur;
+    if (cur->parent != NULL) {
+	if (cur->parent->children == old)
+	    cur->parent->children = cur;
+	if (cur->parent->last == old)
+	    cur->parent->last = cur;
+    }
+    old->next = old->prev = NULL;
+    old->parent = NULL;
+    return(old);
+}
+
+/************************************************************************
+ *									*
+ *		Copy operations						*
+ *									*
+ ************************************************************************/
+ 
+/**
+ * xmlCopyNamespace:
+ * @cur:  the namespace
+ *
+ * Do a copy of the namespace.
+ *
+ * Returns: a new xmlNsPtr, or NULL in case of error.
+ */
+xmlNsPtr
+xmlCopyNamespace(xmlNsPtr cur) {
+    xmlNsPtr ret;
+
+    if (cur == NULL) return(NULL);
+    switch (cur->type) {
+	case XML_LOCAL_NAMESPACE:
+	    ret = xmlNewNs(NULL, cur->href, cur->prefix);
+	    break;
+	default:
+#ifdef DEBUG_TREE
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlCopyNamespace: invalid type %d\n", cur->type);
+#endif
+	    return(NULL);
+    }
+    return(ret);
+}
+
+/**
+ * xmlCopyNamespaceList:
+ * @cur:  the first namespace
+ *
+ * Do a copy of an namespace list.
+ *
+ * Returns: a new xmlNsPtr, or NULL in case of error.
+ */
+xmlNsPtr
+xmlCopyNamespaceList(xmlNsPtr cur) {
+    xmlNsPtr ret = NULL;
+    xmlNsPtr p = NULL,q;
+
+    while (cur != NULL) {
+        q = xmlCopyNamespace(cur);
+	if (p == NULL) {
+	    ret = p = q;
+	} else {
+	    p->next = q;
+	    p = q;
+	}
+	cur = cur->next;
+    }
+    return(ret);
+}
+
+static xmlNodePtr
+xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
+/**
+ * xmlCopyProp:
+ * @target:  the element where the attribute will be grafted
+ * @cur:  the attribute
+ *
+ * Do a copy of the attribute.
+ *
+ * Returns: a new xmlAttrPtr, or NULL in case of error.
+ */
+xmlAttrPtr
+xmlCopyProp(xmlNodePtr target, xmlAttrPtr cur) {
+    xmlAttrPtr ret;
+
+    if (cur == NULL) return(NULL);
+    if (target != NULL)
+	ret = xmlNewDocProp(target->doc, cur->name, NULL);
+    else if (cur->parent != NULL)
+	ret = xmlNewDocProp(cur->parent->doc, cur->name, NULL);
+    else if (cur->children != NULL)
+	ret = xmlNewDocProp(cur->children->doc, cur->name, NULL);
+    else
+	ret = xmlNewDocProp(NULL, cur->name, NULL);
+    if (ret == NULL) return(NULL);
+    ret->parent = target;
+    
+    if ((cur->ns != NULL) && (target != NULL)) {
+        xmlNsPtr ns;
+
+	ns = xmlSearchNs(target->doc, target, cur->ns->prefix);
+	ret->ns = ns;
+    } else
+        ret->ns = NULL;
+
+    if (cur->children != NULL) {
+	xmlNodePtr tmp;
+
+	ret->children = xmlStaticCopyNodeList(cur->children, ret->doc, (xmlNodePtr) ret);
+	ret->last = NULL;
+	tmp = ret->children;
+	while (tmp != NULL) {
+	    /* tmp->parent = (xmlNodePtr)ret; */
+	    if (tmp->next == NULL)
+	        ret->last = tmp;
+	    tmp = tmp->next;
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlCopyPropList:
+ * @target:  the element where the attributes will be grafted
+ * @cur:  the first attribute
+ *
+ * Do a copy of an attribute list.
+ *
+ * Returns: a new xmlAttrPtr, or NULL in case of error.
+ */
+xmlAttrPtr
+xmlCopyPropList(xmlNodePtr target, xmlAttrPtr cur) {
+    xmlAttrPtr ret = NULL;
+    xmlAttrPtr p = NULL,q;
+
+    while (cur != NULL) {
+        q = xmlCopyProp(target, cur);
+	if (p == NULL) {
+	    ret = p = q;
+	} else {
+	    p->next = q;
+	    q->prev = p;
+	    p = q;
+	}
+	cur = cur->next;
+    }
+    return(ret);
+}
+
+/*
+ * NOTE abeut the CopyNode operations !
+ *
+ * They are splitted into external and internal parts for one
+ * tricky reason: namespaces. Doing a direct copy of a node
+ * say RPM:Copyright without changing the namespace pointer to
+ * something else can produce stale links. One way to do it is
+ * to keep a reference counter but this doesn't work as soon
+ * as one move the element or the subtree out of the scope of
+ * the existing namespace. The actual solution seems to add
+ * a copy of the namespace at the top of the copied tree if
+ * not available in the subtree.
+ * Hence two functions, the public front-end call the inner ones
+ */
+
+static xmlNodePtr
+xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent);
+
+static xmlNodePtr
+xmlStaticCopyNode(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent,
+                  int recursive) {
+    xmlNodePtr ret;
+
+    if (node == NULL) return(NULL);
+    /*
+     * Allocate a new node and fill the fields.
+     */
+    ret = (xmlNodePtr) xmlMalloc(sizeof(xmlNode));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlStaticCopyNode : malloc failed\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlNode));
+    ret->type = node->type;
+
+    ret->doc = doc;
+    ret->parent = parent; 
+    if (node->name == xmlStringText)
+	ret->name = xmlStringText;
+    else if (node->name == xmlStringTextNoenc)
+	ret->name = xmlStringTextNoenc;
+    else if (node->name == xmlStringComment)
+	ret->name = xmlStringComment;
+    else if (node->name != NULL)
+	ret->name = xmlStrdup(node->name);
+    if ((node->content != NULL) && (node->type != XML_ENTITY_REF_NODE)) {
+#ifndef XML_USE_BUFFER_CONTENT
+	ret->content = xmlStrdup(node->content);
+#else
+	ret->content = xmlBufferCreateSize(xmlBufferLength(node->content));
+	xmlBufferSetAllocationScheme(ret->content,
+		                     xmlGetBufferAllocationScheme());
+	xmlBufferAdd(ret->content,
+		     xmlBufferContent(node->content),
+		     xmlBufferLength(node->content));
+#endif
+    }
+    if (parent != NULL)
+        xmlAddChild(parent, ret);
+    
+    if (!recursive) return(ret);
+    if (node->nsDef != NULL)
+        ret->nsDef = xmlCopyNamespaceList(node->nsDef);
+
+    if (node->ns != NULL) {
+        xmlNsPtr ns;
+
+	ns = xmlSearchNs(doc, ret, node->ns->prefix);
+	if (ns == NULL) {
+	    /*
+	     * Humm, we are copying an element whose namespace is defined
+	     * out of the new tree scope. Search it in the original tree
+	     * and add it at the top of the new tree
+	     */
+	    ns = xmlSearchNs(node->doc, node, node->ns->prefix);
+	    if (ns != NULL) {
+	        xmlNodePtr root = ret;
+
+		while (root->parent != NULL) root = root->parent;
+		xmlNewNs(root, ns->href, ns->prefix);
+	    }
+	} else {
+	    /*
+	     * reference the existing namespace definition in our own tree.
+	     */
+	    ret->ns = ns;
+	}
+    }
+    if (node->properties != NULL)
+        ret->properties = xmlCopyPropList(ret, node->properties);
+    if (node->children != NULL)
+        ret->children = xmlStaticCopyNodeList(node->children, doc, ret);
+    UPDATE_LAST_CHILD_AND_PARENT(ret)
+    return(ret);
+}
+
+static xmlNodePtr
+xmlStaticCopyNodeList(xmlNodePtr node, xmlDocPtr doc, xmlNodePtr parent) {
+    xmlNodePtr ret = NULL;
+    xmlNodePtr p = NULL,q;
+
+    while (node != NULL) {
+       if( node->type == XML_DTD_NODE )
+	 q = (xmlNodePtr) xmlCopyDtd( (xmlDtdPtr) node );
+       else
+	 q = xmlStaticCopyNode(node, doc, parent, 1);
+	if (ret == NULL) {
+	    q->prev = NULL;
+	    ret = p = q;
+	} else {
+	    p->next = q;
+	    q->prev = p;
+	    p = q;
+	}
+	node = node->next;
+    }
+    return(ret);
+}
+
+/**
+ * xmlCopyNode:
+ * @node:  the node
+ * @recursive:  if 1 do a recursive copy.
+ *
+ * Do a copy of the node.
+ *
+ * Returns: a new xmlNodePtr, or NULL in case of error.
+ */
+xmlNodePtr
+xmlCopyNode(xmlNodePtr node, int recursive) {
+    xmlNodePtr ret;
+
+    ret = xmlStaticCopyNode(node, NULL, NULL, recursive);
+    return(ret);
+}
+
+/**
+ * xmlCopyNodeList:
+ * @node:  the first node in the list.
+ *
+ * Do a recursive copy of the node list.
+ *
+ * Returns: a new xmlNodePtr, or NULL in case of error.
+ */
+xmlNodePtr xmlCopyNodeList(xmlNodePtr node) {
+    xmlNodePtr ret = xmlStaticCopyNodeList(node, NULL, NULL);
+    return(ret);
+}
+
+/**
+ * xmlCopyElement:
+ * @elem:  the element
+ *
+ * Do a copy of the element definition.
+ *
+ * Returns: a new xmlElementPtr, or NULL in case of error.
+xmlElementPtr
+xmlCopyElement(xmlElementPtr elem) {
+    xmlElementPtr ret;
+
+    if (elem == NULL) return(NULL);
+    ret = xmlNewDocElement(elem->doc, elem->ns, elem->name, elem->content);
+    if (ret == NULL) return(NULL);
+    if (!recursive) return(ret);
+    if (elem->properties != NULL)
+        ret->properties = xmlCopyPropList(elem->properties);
+    
+    if (elem->nsDef != NULL)
+        ret->nsDef = xmlCopyNamespaceList(elem->nsDef);
+    if (elem->children != NULL)
+        ret->children = xmlCopyElementList(elem->children);
+    return(ret);
+}
+ */
+
+/**
+ * xmlCopyDtd:
+ * @dtd:  the dtd
+ *
+ * Do a copy of the dtd.
+ *
+ * Returns: a new xmlDtdPtr, or NULL in case of error.
+ */
+xmlDtdPtr
+xmlCopyDtd(xmlDtdPtr dtd) {
+    xmlDtdPtr ret;
+
+    if (dtd == NULL) return(NULL);
+    ret = xmlNewDtd(NULL, dtd->name, dtd->ExternalID, dtd->SystemID);
+    if (ret == NULL) return(NULL);
+    if (dtd->entities != NULL)
+        ret->entities = (void *) xmlCopyEntitiesTable(
+	                    (xmlEntitiesTablePtr) dtd->entities);
+    if (dtd->notations != NULL)
+        ret->notations = (void *) xmlCopyNotationTable(
+	                    (xmlNotationTablePtr) dtd->notations);
+    if (dtd->elements != NULL)
+        ret->elements = (void *) xmlCopyElementTable(
+	                    (xmlElementTablePtr) dtd->elements);
+    if (dtd->attributes != NULL)
+        ret->attributes = (void *) xmlCopyAttributeTable(
+	                    (xmlAttributeTablePtr) dtd->attributes);
+    return(ret);
+}
+
+/**
+ * xmlCopyDoc:
+ * @doc:  the document
+ * @recursive:  if 1 do a recursive copy.
+ *
+ * Do a copy of the document info. If recursive, the content tree will
+ * be copied too as well as Dtd, namespaces and entities.
+ *
+ * Returns: a new xmlDocPtr, or NULL in case of error.
+ */
+xmlDocPtr
+xmlCopyDoc(xmlDocPtr doc, int recursive) {
+    xmlDocPtr ret;
+
+    if (doc == NULL) return(NULL);
+    ret = xmlNewDoc(doc->version);
+    if (ret == NULL) return(NULL);
+    if (doc->name != NULL)
+        ret->name = xmlMemStrdup(doc->name);
+    if (doc->encoding != NULL)
+        ret->encoding = xmlStrdup(doc->encoding);
+    ret->charset = doc->charset;
+    ret->compression = doc->compression;
+    ret->standalone = doc->standalone;
+    if (!recursive) return(ret);
+
+    if (doc->intSubset != NULL)
+        ret->intSubset = xmlCopyDtd(doc->intSubset);
+    if (doc->oldNs != NULL)
+        ret->oldNs = xmlCopyNamespaceList(doc->oldNs);
+    if (doc->children != NULL) {
+	xmlNodePtr tmp;
+        ret->children = xmlStaticCopyNodeList(doc->children, ret,
+		                              (xmlNodePtr)ret);
+	ret->last = NULL;
+	tmp = ret->children;
+	while (tmp != NULL) {
+	    if (tmp->next == NULL)
+	        ret->last = tmp;
+	    tmp = tmp->next;
+	}
+    }
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *		Content access functions				*
+ *									*
+ ************************************************************************/
+ 
+/**
+ * xmlDocGetRootElement:
+ * @doc:  the document
+ *
+ * Get the root element of the document (doc->children is a list
+ * containing possibly comments, PIs, etc ...).
+ *
+ * Returns the xmlNodePtr for the root or NULL
+ */
+xmlNodePtr
+xmlDocGetRootElement(xmlDocPtr doc) {
+    xmlNodePtr ret;
+
+    if (doc == NULL) return(NULL);
+    ret = doc->children;
+    while (ret != NULL) {
+	if (ret->type == XML_ELEMENT_NODE)
+	    return(ret);
+        ret = ret->next;
+    }
+    return(ret);
+}
+ 
+/**
+ * xmlDocSetRootElement:
+ * @doc:  the document
+ * @root:  the new document root element
+ *
+ * Set the root element of the document (doc->children is a list
+ * containing possibly comments, PIs, etc ...).
+ *
+ * Returns the old root element if any was found
+ */
+xmlNodePtr
+xmlDocSetRootElement(xmlDocPtr doc, xmlNodePtr root) {
+    xmlNodePtr old = NULL;
+
+    if (doc == NULL) return(NULL);
+    old = doc->children;
+    while (old != NULL) {
+	if (old->type == XML_ELEMENT_NODE)
+	    break;
+        old = old->next;
+    }
+    if (old == NULL) {
+	if (doc->children == NULL) {
+	    doc->children = root;
+	    doc->last = root;
+	} else {
+	    xmlAddSibling(doc->children, root);
+	}
+    } else {
+	xmlReplaceNode(old, root);
+    }
+    return(old);
+}
+ 
+/**
+ * xmlNodeSetLang:
+ * @cur:  the node being changed
+ * @lang:  the langage description
+ *
+ * Set the language of a node, i.e. the values of the xml:lang
+ * attribute.
+ */
+void
+xmlNodeSetLang(xmlNodePtr cur, const xmlChar *lang) {
+    if (cur == NULL) return;
+    switch(cur->type) {
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_COMMENT_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_NOTATION_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DTD_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+        case XML_PI_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+	case XML_NAMESPACE_DECL:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+	    return;
+        case XML_ELEMENT_NODE:
+        case XML_ATTRIBUTE_NODE:
+	    break;
+    }
+    xmlSetProp(cur, BAD_CAST "xml:lang", lang);
+}
+ 
+/**
+ * xmlNodeGetLang:
+ * @cur:  the node being checked
+ *
+ * Searches the language of a node, i.e. the values of the xml:lang
+ * attribute or the one carried by the nearest ancestor.
+ *
+ * Returns a pointer to the lang value, or NULL if not found
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlNodeGetLang(xmlNodePtr cur) {
+    xmlChar *lang;
+
+    while (cur != NULL) {
+        lang = xmlGetProp(cur, BAD_CAST "xml:lang");
+	if (lang != NULL)
+	    return(lang);
+	cur = cur->parent;
+    }
+    return(NULL);
+}
+ 
+
+/**
+ * xmlNodeSetSpacePreserve:
+ * @cur:  the node being changed
+ * @val:  the xml:space value ("0": default, 1: "preserve")
+ *
+ * Set (or reset) the space preserving behaviour of a node, i.e. the
+ * value of the xml:space attribute.
+ */
+void
+xmlNodeSetSpacePreserve(xmlNodePtr cur, int val) {
+    if (cur == NULL) return;
+    switch(cur->type) {
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_COMMENT_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_NOTATION_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DTD_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+        case XML_PI_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    return;
+        case XML_ELEMENT_NODE:
+        case XML_ATTRIBUTE_NODE:
+	    break;
+    }
+    switch (val) {
+    case 0:
+	xmlSetProp(cur, BAD_CAST "xml:space", BAD_CAST "default");
+	break;
+    case 1:
+	xmlSetProp(cur, BAD_CAST "xml:space", 
+		       BAD_CAST "preserve");
+	break;
+    }
+}
+
+/**
+ * xmlNodeGetSpacePreserve:
+ * @cur:  the node being checked
+ *
+ * Searches the space preserving behaviour of a node, i.e. the values
+ * of the xml:space attribute or the one carried by the nearest
+ * ancestor.
+ *
+ * Returns -1 if xml:space is not inheried, 0 if "default", 1 if "preserve"
+ */
+int
+xmlNodeGetSpacePreserve(xmlNodePtr cur) {
+    xmlChar *space;
+
+    while (cur != NULL) {
+        space = xmlGetProp(cur, BAD_CAST "xml:space");
+	if (space != NULL) {
+	    if (xmlStrEqual(space, BAD_CAST "preserve")) {
+		xmlFree(space);
+		return(1);
+	    }
+	    if (xmlStrEqual(space, BAD_CAST "default")) {
+		xmlFree(space);
+		return(0);
+	    }
+	    xmlFree(space);
+	}
+	cur = cur->parent;
+    }
+    return(-1);
+}
+ 
+/**
+ * xmlNodeSetName:
+ * @cur:  the node being changed
+ * @name:  the new tag name
+ *
+ * Set (or reset) the name of a node.
+ */
+void
+xmlNodeSetName(xmlNodePtr cur, const xmlChar *name) {
+    if (cur == NULL) return;
+    if (name == NULL) return;
+    switch(cur->type) {
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_COMMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_NOTATION_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    return;
+        case XML_ELEMENT_NODE:
+        case XML_ATTRIBUTE_NODE:
+        case XML_PI_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+        case XML_DTD_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+	    break;
+    }
+    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
+    cur->name = xmlStrdup(name);
+}
+ 
+/**
+ * xmlNodeSetBase:
+ * @cur:  the node being changed
+ * @uri:  the new base URI
+ *
+ * Set (or reset) the base URI of a node, i.e. the value of the
+ * xml:base attribute.
+ */
+void
+xmlNodeSetBase(xmlNodePtr cur, xmlChar* uri) {
+    if (cur == NULL) return;
+    switch(cur->type) {
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_COMMENT_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_NOTATION_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DTD_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+        case XML_PI_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    return;
+        case XML_ELEMENT_NODE:
+        case XML_ATTRIBUTE_NODE:
+	    break;
+    }
+    xmlSetProp(cur, BAD_CAST "xml:base", uri);
+}
+
+/**
+ * xmlDocumentGetBase:
+ * @doc:  the document
+ *
+ * Searches for the Document BASE URL. The code should work on both XML
+ * and HTML document.
+ * It returns the base as defined in RFC 2396 section
+ * 5.1.3. Base URI from the Retrieval URI
+ * However it does not return the computed base (5.1.1 and 5.1.2), use
+ * xmlNodeGetBase() for this
+ *
+ * Returns a pointer to the base URL, or NULL if not found
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlDocumentGetBase(xmlDocPtr doc) {
+    if (doc == NULL)
+        return(NULL);
+    if (doc->type == XML_HTML_DOCUMENT_NODE) {
+	if (doc->URL != NULL)
+	    return(xmlStrdup(doc->URL));
+	return(NULL);
+    }
+    if (doc->URL != NULL)
+	return(xmlStrdup(doc->URL));
+    return(NULL);
+}
+
+/**
+ * xmlNodeGetBase:
+ * @doc:  the document the node pertains to
+ * @cur:  the node being checked
+ *
+ * Searches for the BASE URL. The code should work on both XML
+ * and HTML document even if base mechanisms are completely different.
+ * It returns the base as defined in RFC 2396 sections
+ * 5.1.1. Base URI within Document Content
+ * and
+ * 5.1.2. Base URI from the Encapsulating Entity
+ * However it does not return the document base (5.1.3), use
+ * xmlDocumentGetBase() for this
+ *
+ * Returns a pointer to the base URL, or NULL if not found
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlNodeGetBase(xmlDocPtr doc, xmlNodePtr cur) {
+    xmlChar *base;
+
+    if ((cur == NULL) && (doc == NULL)) 
+        return(NULL);
+    if (doc == NULL) doc = cur->doc;	
+    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
+        cur = doc->children;
+	while ((cur != NULL) && (cur->name != NULL)) {
+	    if (cur->type != XML_ELEMENT_NODE) {
+	        cur = cur->next;
+		continue;
+	    }
+	    if (!xmlStrcasecmp(cur->name, BAD_CAST "html")) {
+	        cur = cur->children;
+		continue;
+	    }
+	    if (!xmlStrcasecmp(cur->name, BAD_CAST "head")) {
+	        cur = cur->children;
+		continue;
+	    }
+	    if (!xmlStrcasecmp(cur->name, BAD_CAST "base")) {
+                return(xmlGetProp(cur, BAD_CAST "href"));
+	    }
+	    cur = cur->next;
+	}
+	return(NULL);
+    }
+    while (cur != NULL) {
+	if (cur->type == XML_ENTITY_DECL) {
+	    xmlEntityPtr ent = (xmlEntityPtr) cur;
+	    return(xmlStrdup(ent->URI));
+	}
+        base = xmlGetProp(cur, BAD_CAST "xml:base");
+	if (base != NULL)
+	    return(base);
+	cur = cur->parent;
+    }
+    if ((doc != NULL) && (doc->URL != NULL))
+        return(xmlStrdup(doc->URL));
+    return(NULL);
+}
+ 
+/**
+ * xmlNodeGetContent:
+ * @cur:  the node being read
+ *
+ * Read the value of a node, this can be either the text carried
+ * directly by this node if it's a TEXT node or the aggregate string
+ * of the values carried by this node child's (TEXT and ENTITY_REF).
+ * Entity references are substitued.
+ * Returns a new xmlChar * or NULL if no content is available.
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlNodeGetContent(xmlNodePtr cur) {
+    if (cur == NULL) return(NULL);
+    switch (cur->type) {
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE: {
+	    xmlNodePtr tmp = cur;
+	    xmlBufferPtr buffer;
+	    xmlChar *ret;
+
+            buffer = xmlBufferCreate();
+	    if (buffer == NULL)
+		return(NULL);
+	    while (tmp != NULL) {
+		switch (tmp->type) {
+		    case XML_ELEMENT_NODE: 
+		    case XML_TEXT_NODE:
+			if (tmp->content != NULL)
+#ifndef XML_USE_BUFFER_CONTENT
+			    xmlBufferCat(buffer, tmp->content);
+#else
+			    xmlBufferCat(buffer,
+				    xmlBufferContent(tmp->content));
+#endif
+			break;
+		    case XML_ENTITY_REF_NODE: {
+		        xmlEntityPtr ent;
+
+			ent = xmlGetDocEntity(cur->doc, tmp->name);
+			if (ent != NULL)
+			    xmlBufferCat(buffer, ent->content);
+		    }
+		    default:
+			break;
+		}
+		/*
+		 * Skip to next node
+		 */
+		if (tmp->children != NULL) {
+		    if (tmp->children->type != XML_ENTITY_DECL) {
+			tmp = tmp->children;
+			continue;
+		    }
+		}
+		if (tmp->next != NULL) {
+		    tmp = tmp->next;
+		    continue;
+		}
+		
+		do {
+		    tmp = tmp->parent;
+		    if (tmp == NULL)
+			break;
+		    if (tmp == (xmlNodePtr) cur) {
+			tmp = NULL;
+			break;
+		    }
+		    if (tmp->next != NULL) {
+			tmp = tmp->next;
+			break;
+		    }
+		} while (tmp != NULL);
+	    }
+	    ret = buffer->content;
+	    buffer->content = NULL;
+	    xmlBufferFree(buffer);
+	    return(ret);
+        }
+        case XML_ATTRIBUTE_NODE: {
+	    xmlAttrPtr attr = (xmlAttrPtr) cur;
+	    if (attr->parent != NULL)
+		return(xmlNodeListGetString(attr->parent->doc, attr->children, 1));
+	    else
+		return(xmlNodeListGetString(NULL, attr->children, 1));
+	    break;
+	}
+        case XML_COMMENT_NODE:
+        case XML_PI_NODE:
+	    if (cur->content != NULL)
+#ifndef XML_USE_BUFFER_CONTENT
+	        return(xmlStrdup(cur->content));
+#else
+	        return(xmlStrdup(xmlBufferContent(cur->content)));
+#endif
+	    return(NULL);
+        case XML_ENTITY_REF_NODE:
+	    /*
+	     * Locate the entity, and get it's content
+	     * @@@
+	     */
+            return(NULL);
+        case XML_ENTITY_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_NOTATION_NODE:
+        case XML_DTD_NODE:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    return(NULL);
+	case XML_NAMESPACE_DECL:
+	    return(xmlStrdup(((xmlNsPtr)cur)->href));
+        case XML_ELEMENT_DECL:
+	    /* TODO !!! */
+	    return(NULL);
+        case XML_ATTRIBUTE_DECL:
+	    /* TODO !!! */
+	    return(NULL);
+        case XML_ENTITY_DECL:
+	    /* TODO !!! */
+	    return(NULL);
+        case XML_CDATA_SECTION_NODE:
+        case XML_TEXT_NODE:
+	    if (cur->content != NULL)
+#ifndef XML_USE_BUFFER_CONTENT
+		return(xmlStrdup(cur->content));
+#else
+	        return(xmlStrdup(xmlBufferContent(cur->content)));
+#endif
+            return(NULL);
+    }
+    return(NULL);
+}
+ 
+/**
+ * xmlNodeSetContent:
+ * @cur:  the node being modified
+ * @content:  the new value of the content
+ *
+ * Replace the content of a node.
+ */
+void
+xmlNodeSetContent(xmlNodePtr cur, const xmlChar *content) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeSetContent : node == NULL\n");
+#endif
+	return;
+    }
+    switch (cur->type) {
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE:
+	    if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	        xmlFree(cur->content);
+#else
+		xmlBufferFree(cur->content);
+#endif
+		cur->content = NULL;
+	    }
+	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
+	    cur->children = xmlStringGetNodeList(cur->doc, content);
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
+	    break;
+        case XML_ATTRIBUTE_NODE:
+	    break;
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+	    if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+		xmlFree(cur->content);
+#else
+	        xmlBufferFree(cur->content);
+#endif
+	    }	
+	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
+	    cur->last = cur->children = NULL;
+	    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+		cur->content = xmlStrdup(content);
+#else
+		cur->content = xmlBufferCreateSize(0);
+		xmlBufferSetAllocationScheme(cur->content,
+			                     xmlGetBufferAllocationScheme());
+		xmlBufferAdd(cur->content, content, -1);
+#endif
+	    } else 
+		cur->content = NULL;
+	    break;
+        case XML_DOCUMENT_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    break;
+        case XML_NOTATION_NODE:
+	    break;
+        case XML_DTD_NODE:
+	    break;
+	case XML_NAMESPACE_DECL:
+	    break;
+        case XML_ELEMENT_DECL:
+	    /* TODO !!! */
+	    break;
+        case XML_ATTRIBUTE_DECL:
+	    /* TODO !!! */
+	    break;
+        case XML_ENTITY_DECL:
+	    /* TODO !!! */
+	    break;
+    }
+}
+
+/**
+ * xmlNodeSetContentLen:
+ * @cur:  the node being modified
+ * @content:  the new value of the content
+ * @len:  the size of @content
+ *
+ * Replace the content of a node.
+ */
+void
+xmlNodeSetContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeSetContentLen : node == NULL\n");
+#endif
+	return;
+    }
+    switch (cur->type) {
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE:
+	    if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	        xmlFree(cur->content);
+#else
+		xmlBufferFree(cur->content);
+#endif
+		cur->content = NULL;
+	    }
+	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
+	    cur->children = xmlStringLenGetNodeList(cur->doc, content, len);
+	    UPDATE_LAST_CHILD_AND_PARENT(cur)
+	    break;
+        case XML_ATTRIBUTE_NODE:
+	    break;
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+        case XML_NOTATION_NODE:
+	    if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+		xmlFree(cur->content);
+#else
+	        xmlBufferFree(cur->content);
+#endif
+	    }	
+	    if (cur->children != NULL) xmlFreeNodeList(cur->children);
+	    cur->children = cur->last = NULL;
+	    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+		cur->content = xmlStrndup(content, len);
+#else
+		cur->content = xmlBufferCreateSize(len);
+		xmlBufferSetAllocationScheme(cur->content,
+			                     xmlGetBufferAllocationScheme());
+		xmlBufferAdd(cur->content, content, len);
+#endif
+	    } else 
+		cur->content = NULL;
+	    break;
+        case XML_DOCUMENT_NODE:
+        case XML_DTD_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    break;
+        case XML_ELEMENT_DECL:
+	    /* TODO !!! */
+	    break;
+        case XML_ATTRIBUTE_DECL:
+	    /* TODO !!! */
+	    break;
+        case XML_ENTITY_DECL:
+	    /* TODO !!! */
+	    break;
+    }
+}
+
+/**
+ * xmlNodeAddContentLen:
+ * @cur:  the node being modified
+ * @content:  extra content
+ * @len:  the size of @content
+ * 
+ * Append the extra substring to the node content.
+ */
+void
+xmlNodeAddContentLen(xmlNodePtr cur, const xmlChar *content, int len) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeAddContentLen : node == NULL\n");
+#endif
+	return;
+    }
+    if (len <= 0) return;
+    switch (cur->type) {
+        case XML_DOCUMENT_FRAG_NODE:
+        case XML_ELEMENT_NODE: {
+	    xmlNodePtr last = NULL, newNode;
+
+	    if (cur->children != NULL) {
+		last = cur->last;
+	    } else {
+	        if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+		    cur->children = xmlStringGetNodeList(cur->doc, cur->content);
+#else
+		    cur->children = xmlStringGetNodeList(cur->doc,
+			                       xmlBufferContent(cur->content));
+#endif
+		    UPDATE_LAST_CHILD_AND_PARENT(cur)
+#ifndef XML_USE_BUFFER_CONTENT
+		    xmlFree(cur->content);
+#else
+		    xmlBufferFree(cur->content);
+#endif
+		    cur->content = NULL;
+		    last = cur->last;
+		}
+	    }
+	    newNode = xmlNewTextLen(content, len);
+	    if (newNode != NULL) {
+		xmlAddChild(cur, newNode);
+	        if ((last != NULL) && (last->next == newNode)) {
+		    xmlTextMerge(last, newNode);
+		}
+	    }
+	    break;
+	}
+        case XML_ATTRIBUTE_NODE:
+	    break;
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_ENTITY_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+        case XML_NOTATION_NODE:
+	    if (content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+		cur->content = xmlStrncat(cur->content, content, len);
+#else
+		xmlBufferAdd(cur->content, content, len);
+#endif
+            }
+        case XML_DOCUMENT_NODE:
+        case XML_DTD_NODE:
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+	case XML_NAMESPACE_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    break;
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+	    break;
+    }
+}
+
+/**
+ * xmlNodeAddContent:
+ * @cur:  the node being modified
+ * @content:  extra content
+ * 
+ * Append the extra substring to the node content.
+ */
+void
+xmlNodeAddContent(xmlNodePtr cur, const xmlChar *content) {
+    int len;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeAddContent : node == NULL\n");
+#endif
+	return;
+    }
+    if (content == NULL) return;
+    len = xmlStrlen(content);
+    xmlNodeAddContentLen(cur, content, len);
+}
+
+/**
+ * xmlTextMerge:
+ * @first:  the first text node
+ * @second:  the second text node being merged
+ * 
+ * Merge two text nodes into one
+ * Returns the first text node augmented
+ */
+xmlNodePtr
+xmlTextMerge(xmlNodePtr first, xmlNodePtr second) {
+    if (first == NULL) return(second);
+    if (second == NULL) return(first);
+    if (first->type != XML_TEXT_NODE) return(first);
+    if (second->type != XML_TEXT_NODE) return(first);
+    if (second->name != first->name)
+	return(first);
+#ifndef XML_USE_BUFFER_CONTENT
+    xmlNodeAddContent(first, second->content);
+#else
+    xmlNodeAddContent(first, xmlBufferContent(second->content));
+#endif
+    xmlUnlinkNode(second);
+    xmlFreeNode(second);
+    return(first);
+}
+
+/**
+ * xmlGetNsList:
+ * @doc:  the document
+ * @node:  the current node
+ *
+ * Search all the namespace applying to a given element.
+ * Returns an NULL terminated array of all the xmlNsPtr found
+ *         that need to be freed by the caller or NULL if no
+ *         namespace if defined
+ */
+xmlNsPtr *
+xmlGetNsList(xmlDocPtr doc, xmlNodePtr node) {
+    xmlNsPtr cur;
+    xmlNsPtr *ret = NULL;
+    int nbns = 0;
+    int maxns = 10;
+    int i;
+
+    while (node != NULL) {
+	cur = node->nsDef;
+	while (cur != NULL) {
+	    if (ret == NULL) {
+	        ret = (xmlNsPtr *) xmlMalloc((maxns + 1) * sizeof(xmlNsPtr));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlGetNsList : out of memory!\n");
+		    return(NULL);
+		}
+		ret[nbns] = NULL;
+	    }
+	    for (i = 0;i < nbns;i++) {
+	        if ((cur->prefix == ret[i]->prefix) ||
+		    (xmlStrEqual(cur->prefix, ret[i]->prefix))) break;
+	    }
+	    if (i >= nbns) {
+	        if (nbns >= maxns) {
+		    maxns *= 2;
+		    ret = (xmlNsPtr *) xmlRealloc(ret,
+		                         (maxns + 1) * sizeof(xmlNsPtr));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlGetNsList : realloc failed!\n");
+			return(NULL);
+		    }
+		}
+		ret[nbns++] = cur;
+		ret[nbns] = NULL;
+	    }
+
+	    cur = cur->next;
+	}
+	node = node->parent;
+    }
+    return(ret);
+}
+
+/**
+ * xmlSearchNs:
+ * @doc:  the document
+ * @node:  the current node
+ * @nameSpace:  the namespace string
+ *
+ * Search a Ns registered under a given name space for a document.
+ * recurse on the parents until it finds the defined namespace
+ * or return NULL otherwise.
+ * @nameSpace can be NULL, this is a search for the default namespace.
+ * We don't allow to cross entities boundaries. If you don't declare
+ * the namespace within those you will be in troubles !!! A warning
+ * is generated to cover this case.
+ *
+ * Returns the namespace pointer or NULL.
+ */
+xmlNsPtr
+xmlSearchNs(xmlDocPtr doc, xmlNodePtr node, const xmlChar *nameSpace) {
+    xmlNsPtr cur;
+
+    if (node == NULL) return(NULL);
+    if ((nameSpace != NULL) &&
+	(xmlStrEqual(nameSpace, (const xmlChar *)"xml"))) {
+	if (doc->oldNs == NULL) {
+	    /*
+	     * Allocate a new Namespace and fill the fields.
+	     */
+	    doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+	    if (doc->oldNs == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlSearchNsByHref : malloc failed\n");
+		return(NULL);
+	    }
+	    memset(doc->oldNs, 0, sizeof(xmlNs));
+	    doc->oldNs->type = XML_LOCAL_NAMESPACE;
+
+	    doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); 
+	    doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml"); 
+	}
+	return(doc->oldNs);
+    }
+    while (node != NULL) {
+	if ((node->type == XML_ENTITY_REF_NODE) ||
+	    (node->type == XML_ENTITY_NODE) ||
+	    (node->type == XML_ENTITY_DECL))
+	    return(NULL);
+	if (node->type == XML_ELEMENT_NODE) {
+	    cur = node->nsDef;
+	    while (cur != NULL) {
+		if ((cur->prefix == NULL) && (nameSpace == NULL) &&
+		    (cur->href != NULL))
+		    return(cur);
+		if ((cur->prefix != NULL) && (nameSpace != NULL) &&
+		    (cur->href != NULL) &&
+		    (xmlStrEqual(cur->prefix, nameSpace)))
+		    return(cur);
+		cur = cur->next;
+	    }
+	}
+	node = node->parent;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlSearchNsByHref:
+ * @doc:  the document
+ * @node:  the current node
+ * @href:  the namespace value
+ *
+ * Search a Ns aliasing a given URI. Recurse on the parents until it finds
+ * the defined namespace or return NULL otherwise.
+ * Returns the namespace pointer or NULL.
+ */
+xmlNsPtr
+xmlSearchNsByHref(xmlDocPtr doc, xmlNodePtr node, const xmlChar *href) {
+    xmlNsPtr cur;
+    xmlNodePtr orig = node;
+
+    if ((node == NULL) || (href == NULL)) return(NULL);
+    if (xmlStrEqual(href, XML_XML_NAMESPACE)) {
+	if (doc->oldNs == NULL) {
+	    /*
+	     * Allocate a new Namespace and fill the fields.
+	     */
+	    doc->oldNs = (xmlNsPtr) xmlMalloc(sizeof(xmlNs));
+	    if (doc->oldNs == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlSearchNsByHref : malloc failed\n");
+		return(NULL);
+	    }
+	    memset(doc->oldNs, 0, sizeof(xmlNs));
+	    doc->oldNs->type = XML_LOCAL_NAMESPACE;
+
+	    doc->oldNs->href = xmlStrdup(XML_XML_NAMESPACE); 
+	    doc->oldNs->prefix = xmlStrdup((const xmlChar *)"xml"); 
+	}
+	return(doc->oldNs);
+    }
+    while (node != NULL) {
+	cur = node->nsDef;
+	while (cur != NULL) {
+	    if ((cur->href != NULL) && (href != NULL) &&
+	        (xmlStrEqual(cur->href, href))) {
+		/*
+		 * Check that the prefix is not shadowed between orig and node
+		 */
+		xmlNodePtr check = orig;
+		xmlNsPtr tst;
+
+		while (check != node) {
+		    tst = check->nsDef;
+		    while (tst != NULL) {
+			if ((tst->prefix == NULL) && (cur->prefix == NULL))
+	                    goto shadowed;
+			if ((tst->prefix != NULL) && (cur->prefix != NULL) &&
+			    (xmlStrEqual(tst->prefix, cur->prefix)))
+	                    goto shadowed;
+		        tst = tst->next;
+		    }
+		    check = check->parent;
+		}
+		return(cur);
+	    }
+shadowed:		    
+	    cur = cur->next;
+	}
+	node = node->parent;
+    }
+    return(NULL);
+}
+
+/**
+ * xmlNewReconciliedNs
+ * @doc:  the document
+ * @tree:  a node expected to hold the new namespace
+ * @ns:  the original namespace
+ *
+ * This function tries to locate a namespace definition in a tree
+ * ancestors, or create a new namespace definition node similar to
+ * @ns trying to reuse the same prefix. However if the given prefix is
+ * null (default namespace) or reused within the subtree defined by
+ * @tree or on one of its ancestors then a new prefix is generated.
+ * Returns the (new) namespace definition or NULL in case of error
+ */
+xmlNsPtr
+xmlNewReconciliedNs(xmlDocPtr doc, xmlNodePtr tree, xmlNsPtr ns) {
+    xmlNsPtr def;
+    xmlChar prefix[50];
+    int counter = 1;
+
+    if (tree == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewReconciliedNs : tree == NULL\n");
+#endif
+	return(NULL);
+    }
+    if (ns == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNewReconciliedNs : ns == NULL\n");
+#endif
+	return(NULL);
+    }
+    /*
+     * Search an existing namespace definition inherited.
+     */
+    def = xmlSearchNsByHref(doc, tree, ns->href);
+    if (def != NULL)
+        return(def);
+
+    /*
+     * Find a close prefix which is not already in use.
+     * Let's strip namespace prefixes longer than 20 chars !
+     */
+    sprintf((char *) prefix, "%.20s", ns->prefix);
+    def = xmlSearchNs(doc, tree, prefix);
+    while (def != NULL) {
+        if (counter > 1000) return(NULL);
+        sprintf((char *) prefix, "%.20s%d", ns->prefix, counter++);
+	def = xmlSearchNs(doc, tree, prefix);
+    }
+
+    /*
+     * Ok, now we are ready to create a new one.
+     */
+    def = xmlNewNs(tree, ns->href, prefix);
+    return(def);
+}
+
+/**
+ * xmlReconciliateNs
+ * @doc:  the document
+ * @tree:  a node defining the subtree to reconciliate
+ *
+ * This function checks that all the namespaces declared within the given
+ * tree are properly declared. This is needed for example after Copy or Cut
+ * and then paste operations. The subtree may still hold pointers to
+ * namespace declarations outside the subtree or invalid/masked. As much
+ * as possible the function try tu reuse the existing namespaces found in
+ * the new environment. If not possible the new namespaces are redeclared
+ * on @tree at the top of the given subtree.
+ * Returns the number of namespace declarations created or -1 in case of error.
+ */
+int
+xmlReconciliateNs(xmlDocPtr doc, xmlNodePtr tree) {
+    xmlNsPtr *oldNs = NULL;
+    xmlNsPtr *newNs = NULL;
+    int sizeCache = 0;
+    int nbCache = 0;
+
+    xmlNsPtr n;
+    xmlNodePtr node = tree;
+    xmlAttrPtr attr;
+    int ret = 0, i;
+
+    while (node != NULL) {
+        /*
+	 * Reconciliate the node namespace
+	 */
+	if (node->ns != NULL) {
+	    /*
+	     * initialize the cache if needed
+	     */
+	    if (sizeCache == 0) {
+		sizeCache = 10;
+		oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+					       sizeof(xmlNsPtr));
+		if (oldNs == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlReconciliateNs : memory pbm\n");
+		    return(-1);
+		}
+		newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+					       sizeof(xmlNsPtr));
+		if (newNs == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlReconciliateNs : memory pbm\n");
+		    xmlFree(oldNs);
+		    return(-1);
+		}
+	    }
+	    for (i = 0;i < nbCache;i++) {
+	        if (oldNs[i] == node->ns) {
+		    node->ns = newNs[i];
+		    break;
+		}
+	    }
+	    if (i == nbCache) {
+	        /*
+		 * Ok we need to recreate a new namespace definition
+		 */
+		n = xmlNewReconciliedNs(doc, tree, node->ns);
+		if (n != NULL) { /* :-( what if else ??? */
+		    /*
+		     * check if we need to grow the cache buffers.
+		     */
+		    if (sizeCache <= nbCache) {
+		        sizeCache *= 2;
+			oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
+			                               sizeof(xmlNsPtr));
+		        if (oldNs == NULL) {
+			    xmlGenericError(xmlGenericErrorContext,
+				    "xmlReconciliateNs : memory pbm\n");
+			    xmlFree(newNs);
+			    return(-1);
+			}
+			newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
+			                               sizeof(xmlNsPtr));
+		        if (newNs == NULL) {
+			    xmlGenericError(xmlGenericErrorContext,
+				    "xmlReconciliateNs : memory pbm\n");
+			    xmlFree(oldNs);
+			    return(-1);
+			}
+		    }
+		    newNs[nbCache] = n;
+		    oldNs[nbCache++] = node->ns;
+		    node->ns = n;
+                }
+	    }
+	}
+	/*
+	 * now check for namespace hold by attributes on the node.
+	 */
+	attr = node->properties;
+	while (attr != NULL) {
+	    if (attr->ns != NULL) {
+		/*
+		 * initialize the cache if needed
+		 */
+		if (sizeCache == 0) {
+		    sizeCache = 10;
+		    oldNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+						   sizeof(xmlNsPtr));
+		    if (oldNs == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlReconciliateNs : memory pbm\n");
+			return(-1);
+		    }
+		    newNs = (xmlNsPtr *) xmlMalloc(sizeCache *
+						   sizeof(xmlNsPtr));
+		    if (newNs == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlReconciliateNs : memory pbm\n");
+			xmlFree(oldNs);
+			return(-1);
+		    }
+		}
+		for (i = 0;i < nbCache;i++) {
+		    if (oldNs[i] == attr->ns) {
+			node->ns = newNs[i];
+			break;
+		    }
+		}
+		if (i == nbCache) {
+		    /*
+		     * Ok we need to recreate a new namespace definition
+		     */
+		    n = xmlNewReconciliedNs(doc, tree, attr->ns);
+		    if (n != NULL) { /* :-( what if else ??? */
+			/*
+			 * check if we need to grow the cache buffers.
+			 */
+			if (sizeCache <= nbCache) {
+			    sizeCache *= 2;
+			    oldNs = (xmlNsPtr *) xmlRealloc(oldNs, sizeCache *
+							   sizeof(xmlNsPtr));
+			    if (oldNs == NULL) {
+				xmlGenericError(xmlGenericErrorContext,
+				        "xmlReconciliateNs : memory pbm\n");
+				xmlFree(newNs);
+				return(-1);
+			    }
+			    newNs = (xmlNsPtr *) xmlRealloc(newNs, sizeCache *
+							   sizeof(xmlNsPtr));
+			    if (newNs == NULL) {
+				xmlGenericError(xmlGenericErrorContext,
+				        "xmlReconciliateNs : memory pbm\n");
+				xmlFree(oldNs);
+				return(-1);
+			    }
+			}
+			newNs[nbCache] = n;
+			oldNs[nbCache++] = attr->ns;
+			attr->ns = n;
+		    }
+		}
+	    }
+	    attr = attr->next;
+	}
+
+	/*
+	 * Browse the full subtree, deep first
+	 */
+        if (node->children != NULL) {
+	    /* deep first */
+	    node = node->children;
+	} else if ((node != tree) && (node->next != NULL)) {
+	    /* then siblings */
+	    node = node->next;
+	} else if (node != tree) {
+	    /* go up to parents->next if needed */
+	    while (node != tree) {
+	        if (node->parent != NULL)
+		    node = node->parent;
+		if ((node != tree) && (node->next != NULL)) {
+		    node = node->next;
+		    break;
+		}
+		if (node->parent == NULL) {
+		    node = NULL;
+		    break;
+		}
+	    }
+	    /* exit condition */
+	    if (node == tree) 
+	        node = NULL;
+	}
+    }
+    return(ret);
+}
+
+/**
+ * xmlHasProp:
+ * @node:  the node
+ * @name:  the attribute name
+ *
+ * Search an attribute associated to a node
+ * This function also looks in DTD attribute declaration for #FIXED or
+ * default declaration values unless DTD use has been turned off.
+ *
+ * Returns the attribute or the attribute declaration or NULL if 
+ *         neither was found.
+ */
+xmlAttrPtr
+xmlHasProp(xmlNodePtr node, const xmlChar *name) {
+    xmlAttrPtr prop;
+    xmlDocPtr doc;
+
+    if ((node == NULL) || (name == NULL)) return(NULL);
+    /*
+     * Check on the properties attached to the node
+     */
+    prop = node->properties;
+    while (prop != NULL) {
+        if (xmlStrEqual(prop->name, name))  {
+	    return(prop);
+        }
+	prop = prop->next;
+    }
+    if (!xmlCheckDTD) return(NULL);
+
+    /*
+     * Check if there is a default declaration in the internal
+     * or external subsets
+     */
+    doc =  node->doc;
+    if (doc != NULL) {
+        xmlAttributePtr attrDecl;
+        if (doc->intSubset != NULL) {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
+	    if (attrDecl != NULL)
+		return((xmlAttrPtr) attrDecl);
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xmlGetProp:
+ * @node:  the node
+ * @name:  the attribute name
+ *
+ * Search and get the value of an attribute associated to a node
+ * This does the entity substitution.
+ * This function looks in DTD attribute declaration for #FIXED or
+ * default declaration values unless DTD use has been turned off.
+ *
+ * Returns the attribute value or NULL if not found.
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlGetProp(xmlNodePtr node, const xmlChar *name) {
+    xmlAttrPtr prop;
+    xmlDocPtr doc;
+
+    if ((node == NULL) || (name == NULL)) return(NULL);
+    /*
+     * Check on the properties attached to the node
+     */
+    prop = node->properties;
+    while (prop != NULL) {
+        if (xmlStrEqual(prop->name, name))  {
+	    xmlChar *ret;
+
+	    ret = xmlNodeListGetString(node->doc, prop->children, 1);
+	    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
+	    return(ret);
+        }
+	prop = prop->next;
+    }
+    if (!xmlCheckDTD) return(NULL);
+
+    /*
+     * Check if there is a default declaration in the internal
+     * or external subsets
+     */
+    doc =  node->doc;
+    if (doc != NULL) {
+        xmlAttributePtr attrDecl;
+        if (doc->intSubset != NULL) {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
+	    if (attrDecl != NULL)
+		return(xmlStrdup(attrDecl->defaultValue));
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xmlGetNsProp:
+ * @node:  the node
+ * @name:  the attribute name
+ * @namespace:  the URI of the namespace
+ *
+ * Search and get the value of an attribute associated to a node
+ * This attribute has to be anchored in the namespace specified.
+ * This does the entity substitution.
+ * This function looks in DTD attribute declaration for #FIXED or
+ * default declaration values unless DTD use has been turned off.
+ *
+ * Returns the attribute value or NULL if not found.
+ *     It's up to the caller to free the memory.
+ */
+xmlChar *
+xmlGetNsProp(xmlNodePtr node, const xmlChar *name, const xmlChar *namespace) {
+    xmlAttrPtr prop;
+    xmlDocPtr doc;
+    xmlNsPtr ns;
+
+    if (node == NULL)
+	return(NULL);
+
+    prop = node->properties;
+    if (namespace == NULL)
+	return(xmlGetProp(node, name));
+    while (prop != NULL) {
+	/*
+	 * One need to have
+	 *   - same attribute names
+	 *   - and the attribute carrying that namespace
+	 *         or
+	 *         no namespace on the attribute and the element carrying it
+	 */
+        if ((xmlStrEqual(prop->name, name)) &&
+	    (((prop->ns == NULL) && (node->ns != NULL) &&
+	      (xmlStrEqual(node->ns->href, namespace))) ||
+	     ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, namespace))))) {
+	    xmlChar *ret;
+
+	    ret = xmlNodeListGetString(node->doc, prop->children, 1);
+	    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
+	    return(ret);
+        }
+	prop = prop->next;
+    }
+    if (!xmlCheckDTD) return(NULL);
+
+    /*
+     * Check if there is a default declaration in the internal
+     * or external subsets
+     */
+    doc =  node->doc;
+    if (doc != NULL) {
+        xmlAttributePtr attrDecl;
+        if (doc->intSubset != NULL) {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, node->name, name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset, node->name, name);
+		
+	    if ((attrDecl != NULL) && (attrDecl->prefix != NULL)) {
+	        /*
+		 * The DTD declaration only allows a prefix search
+		 */
+		ns = xmlSearchNs(doc, node, attrDecl->prefix);
+		if ((ns != NULL) && (xmlStrEqual(ns->href, namespace)))
+		    return(xmlStrdup(attrDecl->defaultValue));
+	    }
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xmlSetProp:
+ * @node:  the node
+ * @name:  the attribute name
+ * @value:  the attribute value
+ *
+ * Set (or reset) an attribute carried by a node.
+ * Returns the attribute pointer.
+ */
+xmlAttrPtr
+xmlSetProp(xmlNodePtr node, const xmlChar *name, const xmlChar *value) {
+    xmlAttrPtr prop = node->properties;
+    xmlDocPtr doc = NULL;
+
+    if ((node == NULL) || (name == NULL))
+	return(NULL);
+    doc = node->doc;
+    while (prop != NULL) {
+        if (xmlStrEqual(prop->name, name)) {
+	    if (prop->children != NULL) 
+	        xmlFreeNodeList(prop->children);
+	    prop->children = NULL;
+	    prop->last = NULL;
+	    if (value != NULL) {
+	        xmlChar *buffer;
+		xmlNodePtr tmp;
+
+		buffer = xmlEncodeEntitiesReentrant(node->doc, value);
+		prop->children = xmlStringGetNodeList(node->doc, buffer);
+		prop->last = NULL;
+		prop->doc = doc;
+		tmp = prop->children;
+		while (tmp != NULL) {
+		    tmp->parent = (xmlNodePtr) prop;
+		    tmp->doc = doc;
+		    if (tmp->next == NULL)
+			prop->last = tmp;
+		    tmp = tmp->next;
+		}
+		xmlFree(buffer);
+	    }	
+	    return(prop);
+	}
+	prop = prop->next;
+    }
+    prop = xmlNewProp(node, name, value);
+    return(prop);
+}
+
+/**
+ * xmlSetNsProp:
+ * @node:  the node
+ * @ns:  the namespace definition
+ * @name:  the attribute name
+ * @value:  the attribute value
+ *
+ * Set (or reset) an attribute carried by a node.
+ * The ns structure must be in scope, this is not checked.
+ *
+ * Returns the attribute pointer.
+ */
+xmlAttrPtr
+xmlSetNsProp(xmlNodePtr node, xmlNsPtr ns, const xmlChar *name,
+	     const xmlChar *value) {
+    xmlAttrPtr prop;
+    
+    if ((node == NULL) || (name == NULL))
+	return(NULL);
+
+    if (ns == NULL)
+	return(xmlSetProp(node, name, value));
+    if (ns->href == NULL)
+	return(NULL);
+    prop = node->properties;
+
+    while (prop != NULL) {
+	/*
+	 * One need to have
+	 *   - same attribute names
+	 *   - and the attribute carrying that namespace
+	 *         or
+	 *         no namespace on the attribute and the element carrying it
+	 */
+        if ((xmlStrEqual(prop->name, name)) &&
+	    (((prop->ns == NULL) && (node->ns != NULL) &&
+	      (xmlStrEqual(node->ns->href, ns->href))) ||
+	     ((prop->ns != NULL) && (xmlStrEqual(prop->ns->href, ns->href))))) {
+	    if (prop->children != NULL) 
+	        xmlFreeNodeList(prop->children);
+	    prop->children = NULL;
+	    prop->last = NULL;
+	    prop->ns = ns;
+	    if (value != NULL) {
+	        xmlChar *buffer;
+		xmlNodePtr tmp;
+
+		buffer = xmlEncodeEntitiesReentrant(node->doc, value);
+		prop->children = xmlStringGetNodeList(node->doc, buffer);
+		prop->last = NULL;
+		tmp = prop->children;
+		while (tmp != NULL) {
+		    tmp->parent = (xmlNodePtr) prop;
+		    if (tmp->next == NULL)
+			prop->last = tmp;
+		    tmp = tmp->next;
+		}
+		xmlFree(buffer);
+	    }	
+	    return(prop);
+        }
+	prop = prop->next;
+    }
+    prop = xmlNewNsProp(node, ns, name, value);
+    return(prop);
+}
+
+/**
+ * xmlNodeIsText:
+ * @node:  the node
+ * 
+ * Is this node a Text node ?
+ * Returns 1 yes, 0 no
+ */
+int
+xmlNodeIsText(xmlNodePtr node) {
+    if (node == NULL) return(0);
+
+    if (node->type == XML_TEXT_NODE) return(1);
+    return(0);
+}
+
+/**
+ * xmlIsBlankNode:
+ * @node:  the node
+ * 
+ * Checks whether this node is an empty or whitespace only
+ * (and possibly ignorable) text-node.
+ *
+ * Returns 1 yes, 0 no
+ */
+int
+xmlIsBlankNode(xmlNodePtr node) {
+    const xmlChar *cur;
+    if (node == NULL) return(0);
+
+    if (node->type != XML_TEXT_NODE) return(0);
+    if (node->content == NULL) return(1);
+#ifndef XML_USE_BUFFER_CONTENT
+    cur = node->content;
+#else
+    cur = xmlBufferContent(node->content);
+#endif
+    while (*cur != 0) {
+	if (!IS_BLANK(*cur)) return(0);
+	cur++;
+    }
+
+    return(1);
+}
+
+/**
+ * xmlTextConcat:
+ * @node:  the node
+ * @content:  the content
+ * @len:  @content lenght
+ * 
+ * Concat the given string at the end of the existing node content
+ */
+
+void
+xmlTextConcat(xmlNodePtr node, const xmlChar *content, int len) {
+    if (node == NULL) return;
+
+    if ((node->type != XML_TEXT_NODE) &&
+        (node->type != XML_CDATA_SECTION_NODE)) {
+#ifdef DEBUG_TREE
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlTextConcat: node is not text nor cdata\n");
+#endif
+        return;
+    }
+#ifndef XML_USE_BUFFER_CONTENT
+    node->content = xmlStrncat(node->content, content, len);
+#else
+    xmlBufferAdd(node->content, content, len);
+#endif
+}
+
+/************************************************************************
+ *									*
+ *			Output : to a FILE or in memory			*
+ *									*
+ ************************************************************************/
+
+#define BASE_BUFFER_SIZE 4000
+
+/**
+ * xmlBufferCreate:
+ *
+ * routine to create an XML buffer.
+ * returns the new structure.
+ */
+xmlBufferPtr
+xmlBufferCreate(void) {
+    xmlBufferPtr ret;
+
+    ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferCreate : out of memory!\n");
+        return(NULL);
+    }
+    ret->use = 0;
+    ret->size = BASE_BUFFER_SIZE;
+    ret->alloc = xmlBufferAllocScheme;
+    ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
+    if (ret->content == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferCreate : out of memory!\n");
+	xmlFree(ret);
+        return(NULL);
+    }
+    ret->content[0] = 0;
+    return(ret);
+}
+
+/**
+ * xmlBufferCreateSize:
+ * @size: initial size of buffer
+ *
+ * routine to create an XML buffer.
+ * returns the new structure.
+ */
+xmlBufferPtr
+xmlBufferCreateSize(size_t size) {
+    xmlBufferPtr ret;
+
+    ret = (xmlBufferPtr) xmlMalloc(sizeof(xmlBuffer));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferCreate : out of memory!\n");
+        return(NULL);
+    }
+    ret->use = 0;
+    ret->alloc = xmlBufferAllocScheme;
+    ret->size = (size ? size+2 : 0);         /* +1 for ending null */
+    if (ret->size){
+        ret->content = (xmlChar *) xmlMalloc(ret->size * sizeof(xmlChar));
+        if (ret->content == NULL) {
+            xmlGenericError(xmlGenericErrorContext,
+		    "xmlBufferCreate : out of memory!\n");
+            xmlFree(ret);
+            return(NULL);
+        }
+        ret->content[0] = 0;
+    } else
+	ret->content = NULL;
+    return(ret);
+}
+
+/**
+ * xmlBufferSetAllocationScheme:
+ * @buf:  the buffer to free
+ * @scheme:  allocation scheme to use
+ *
+ * Sets the allocation scheme for this buffer
+ */
+void
+xmlBufferSetAllocationScheme(xmlBufferPtr buf, 
+                             xmlBufferAllocationScheme scheme) {
+    if (buf == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferSetAllocationScheme: buf == NULL\n");
+#endif
+        return;
+    }
+
+    buf->alloc = scheme;
+}
+
+/**
+ * xmlBufferFree:
+ * @buf:  the buffer to free
+ *
+ * Frees an XML buffer.
+ */
+void
+xmlBufferFree(xmlBufferPtr buf) {
+    if (buf == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferFree: buf == NULL\n");
+#endif
+	return;
+    }
+    if (buf->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+        memset(buf->content, -1, BASE_BUFFER_SIZE);
+#else
+        memset(buf->content, -1, buf->size);
+#endif
+        xmlFree(buf->content);
+    }
+    memset(buf, -1, sizeof(xmlBuffer));
+    xmlFree(buf);
+}
+
+/**
+ * xmlBufferEmpty:
+ * @buf:  the buffer
+ *
+ * empty a buffer.
+ */
+void
+xmlBufferEmpty(xmlBufferPtr buf) {
+    if (buf->content == NULL) return;
+    buf->use = 0;
+    memset(buf->content, -1, buf->size);/* just for debug */
+}
+
+/**
+ * xmlBufferShrink:
+ * @buf:  the buffer to dump
+ * @len:  the number of xmlChar to remove
+ *
+ * Remove the beginning of an XML buffer.
+ *
+ * Returns the number of xmlChar removed, or -1 in case of failure.
+ */
+int
+xmlBufferShrink(xmlBufferPtr buf, unsigned int len) {
+    if (len == 0) return(0);
+    if (len > buf->use) return(-1);
+
+    buf->use -= len;
+    memmove(buf->content, &buf->content[len], buf->use * sizeof(xmlChar));
+
+    buf->content[buf->use] = 0;
+    return(len);
+}
+
+/**
+ * xmlBufferGrow:
+ * @buf:  the buffer
+ * @len:  the minimum free size to allocate
+ *
+ * Grow the available space of an XML buffer.
+ *
+ * Returns the new available space or -1 in case of error
+ */
+int
+xmlBufferGrow(xmlBufferPtr buf, unsigned int len) {
+    int size;
+    xmlChar *newbuf;
+
+    if (len + buf->use < buf->size) return(0);
+
+    size = buf->use + len + 100;
+
+    newbuf = (xmlChar *) xmlRealloc(buf->content, size);
+    if (newbuf == NULL) return(-1);
+    buf->content = newbuf;
+    buf->size = size;
+    return(buf->size - buf->use);
+}
+
+/**
+ * xmlBufferDump:
+ * @file:  the file output
+ * @buf:  the buffer to dump
+ *
+ * Dumps an XML buffer to  a FILE *.
+ * Returns the number of xmlChar written
+ */
+int
+xmlBufferDump(FILE *file, xmlBufferPtr buf) {
+    int ret;
+
+    if (buf == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferDump: buf == NULL\n");
+#endif
+	return(0);
+    }
+    if (buf->content == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferDump: buf->content == NULL\n");
+#endif
+	return(0);
+    }
+    if (file == NULL) file = stdout;
+    ret = fwrite(buf->content, sizeof(xmlChar), buf->use, file);
+    return(ret);
+}
+
+/**
+ * xmlBufferContent:
+ * @buf:  the buffer
+ *
+ * Returns the internal content
+ */
+
+const xmlChar* 
+xmlBufferContent(const xmlBufferPtr buf)
+{
+    if(!buf)
+        return NULL;
+
+    return buf->content;
+}
+
+/**
+ * xmlBufferLength:
+ * @buf:  the buffer 
+ *
+ * Returns the length of data in the internal content
+ */
+
+int
+xmlBufferLength(const xmlBufferPtr buf)
+{
+    if(!buf)
+        return 0;
+
+    return buf->use;
+}
+
+/**
+ * xmlBufferResize:
+ * @buf:  the buffer to resize
+ * @size:  the desired size
+ *
+ * Resize a buffer to accomodate minimum size of @size.
+ *
+ * Returns  0 in case of problems, 1 otherwise
+ */
+int
+xmlBufferResize(xmlBufferPtr buf, unsigned int size)
+{
+    unsigned int newSize;
+    xmlChar* rebuf = NULL;
+
+    /*take care of empty case*/
+    newSize = (buf->size ? buf->size*2 : size);
+
+    /* Don't resize if we don't have to */
+    if (size < buf->size)
+        return 1;
+
+    /* figure out new size */
+    switch (buf->alloc){
+    case XML_BUFFER_ALLOC_DOUBLEIT:
+        while (size > newSize) newSize *= 2;
+        break;
+    case XML_BUFFER_ALLOC_EXACT:
+        newSize = size+10;
+        break;
+    default:
+        newSize = size+10;
+        break;
+    }
+
+    if (buf->content == NULL)
+	rebuf = (xmlChar *) xmlMalloc(newSize * sizeof(xmlChar));
+    else
+	rebuf = (xmlChar *) xmlRealloc(buf->content, 
+				       newSize * sizeof(xmlChar));
+    if (rebuf == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferAdd : out of memory!\n");
+        return 0;
+    }
+    buf->content = rebuf;
+    buf->size = newSize;
+
+    return 1;
+}
+
+/**
+ * xmlBufferAdd:
+ * @buf:  the buffer to dump
+ * @str:  the xmlChar string
+ * @len:  the number of xmlChar to add
+ *
+ * Add a string range to an XML buffer. if len == -1, the lenght of
+ * str is recomputed.
+ */
+void
+xmlBufferAdd(xmlBufferPtr buf, const xmlChar *str, int len) {
+    unsigned int needSize;
+
+    if (str == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferAdd: str == NULL\n");
+#endif
+	return;
+    }
+    if (len < -1) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferAdd: len < 0\n");
+#endif
+	return;
+    }
+    if (len == 0) return;
+
+    if (len < 0)
+        len = xmlStrlen(str);
+
+    if (len <= 0) return;
+
+    needSize = buf->use + len + 2;
+    if (needSize > buf->size){
+        if (!xmlBufferResize(buf, needSize)){
+            xmlGenericError(xmlGenericErrorContext,
+		    "xmlBufferAdd : out of memory!\n");
+            return;
+        }
+    }
+
+    memmove(&buf->content[buf->use], str, len*sizeof(xmlChar));
+    buf->use += len;
+    buf->content[buf->use] = 0;
+}
+
+/**
+ * xmlBufferAddHead:
+ * @buf:  the buffer
+ * @str:  the xmlChar string
+ * @len:  the number of xmlChar to add
+ *
+ * Add a string range to the beginning of an XML buffer.
+ * if len == -1, the lenght of @str is recomputed.
+ */
+void
+xmlBufferAddHead(xmlBufferPtr buf, const xmlChar *str, int len) {
+    unsigned int needSize;
+
+    if (str == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferAdd: str == NULL\n");
+#endif
+	return;
+    }
+    if (len < -1) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferAdd: len < 0\n");
+#endif
+	return;
+    }
+    if (len == 0) return;
+
+    if (len < 0)
+        len = xmlStrlen(str);
+
+    if (len <= 0) return;
+
+    needSize = buf->use + len + 2;
+    if (needSize > buf->size){
+        if (!xmlBufferResize(buf, needSize)){
+            xmlGenericError(xmlGenericErrorContext,
+		    "xmlBufferAddHead : out of memory!\n");
+            return;
+        }
+    }
+
+    memmove(&buf->content[len], &buf->content[0], buf->use * sizeof(xmlChar));
+    memmove(&buf->content[0], str, len * sizeof(xmlChar));
+    buf->use += len;
+    buf->content[buf->use] = 0;
+}
+
+/**
+ * xmlBufferCat:
+ * @buf:  the buffer to dump
+ * @str:  the xmlChar string
+ *
+ * Append a zero terminated string to an XML buffer.
+ */
+void
+xmlBufferCat(xmlBufferPtr buf, const xmlChar *str) {
+    if (str != NULL)
+	xmlBufferAdd(buf, str, -1);
+}
+
+/**
+ * xmlBufferCCat:
+ * @buf:  the buffer to dump
+ * @str:  the C char string
+ *
+ * Append a zero terminated C string to an XML buffer.
+ */
+void
+xmlBufferCCat(xmlBufferPtr buf, const char *str) {
+    const char *cur;
+
+    if (str == NULL) {
+#ifdef DEBUG_BUFFER
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlBufferAdd: str == NULL\n");
+#endif
+	return;
+    }
+    for (cur = str;*cur != 0;cur++) {
+        if (buf->use  + 10 >= buf->size) {
+            if (!xmlBufferResize(buf, buf->use+10)){
+                xmlGenericError(xmlGenericErrorContext,
+			"xmlBufferCCat : out of memory!\n");
+                return;
+            }
+        }
+        buf->content[buf->use++] = *cur;
+    }
+    buf->content[buf->use] = 0;
+}
+
+/**
+ * xmlBufferWriteCHAR:
+ * @buf:  the XML buffer
+ * @string:  the string to add
+ *
+ * routine which manages and grows an output buffer. This one adds
+ * xmlChars at the end of the buffer.
+ */
+void
+#ifdef VMS
+xmlBufferWriteXmlCHAR
+#else
+xmlBufferWriteCHAR
+#endif
+(xmlBufferPtr buf, const xmlChar *string) {
+    xmlBufferCat(buf, string);
+}
+
+/**
+ * xmlBufferWriteChar:
+ * @buf:  the XML buffer output
+ * @string:  the string to add
+ *
+ * routine which manage and grows an output buffer. This one add
+ * C chars at the end of the array.
+ */
+void
+xmlBufferWriteChar(xmlBufferPtr buf, const char *string) {
+    xmlBufferCCat(buf, string);
+}
+
+
+/**
+ * xmlBufferWriteQuotedString:
+ * @buf:  the XML buffer output
+ * @string:  the string to add
+ *
+ * routine which manage and grows an output buffer. This one writes
+ * a quoted or double quoted xmlChar string, checking first if it holds
+ * quote or double-quotes internally
+ */
+void
+xmlBufferWriteQuotedString(xmlBufferPtr buf, const xmlChar *string) {
+    if (xmlStrchr(string, '"')) {
+        if (xmlStrchr(string, '\'')) {
+#ifdef DEBUG_BUFFER
+	    xmlGenericError(xmlGenericErrorContext,
+ "xmlBufferWriteQuotedString: string contains quote and double-quotes !\n");
+#endif
+	}
+        xmlBufferCCat(buf, "'");
+        xmlBufferCat(buf, string);
+        xmlBufferCCat(buf, "'");
+    } else {
+        xmlBufferCCat(buf, "\"");
+        xmlBufferCat(buf, string);
+        xmlBufferCCat(buf, "\"");
+    }
+}
+
+
+/************************************************************************
+ *									*
+ *   		Dumping XML tree content to a simple buffer		*
+ *									*
+ ************************************************************************/
+
+void
+xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
+            int format);
+static void
+xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
+                int format);
+void
+htmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur);
+
+/**
+ * xmlNsDump:
+ * @buf:  the XML buffer output
+ * @cur:  a namespace
+ *
+ * Dump a local Namespace definition.
+ * Should be called in the context of attributes dumps.
+ */
+static void
+xmlNsDump(xmlBufferPtr buf, xmlNsPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNsDump : Ns == NULL\n");
+#endif
+	return;
+    }
+    if (cur->type == XML_LOCAL_NAMESPACE) {
+        /* Within the context of an element attributes */
+	if (cur->prefix != NULL) {
+	    xmlBufferWriteChar(buf, " xmlns:");
+	    xmlBufferWriteCHAR(buf, cur->prefix);
+	} else
+	    xmlBufferWriteChar(buf, " xmlns");
+	xmlBufferWriteChar(buf, "=");
+	xmlBufferWriteQuotedString(buf, cur->href);
+    }
+}
+
+/**
+ * xmlNsListDump:
+ * @buf:  the XML buffer output
+ * @cur:  the first namespace
+ *
+ * Dump a list of local Namespace definitions.
+ * Should be called in the context of attributes dumps.
+ */
+static void
+xmlNsListDump(xmlBufferPtr buf, xmlNsPtr cur) {
+    while (cur != NULL) {
+        xmlNsDump(buf, cur);
+	cur = cur->next;
+    }
+}
+
+/**
+ * xmlDtdDump:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * 
+ * Dump the XML document DTD, if any.
+ */
+static void
+xmlDtdDump(xmlBufferPtr buf, xmlDtdPtr dtd) {
+    if (dtd == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlDtdDump : no internal subset\n");
+#endif
+	return;
+    }
+    xmlBufferWriteChar(buf, "<!DOCTYPE ");
+    xmlBufferWriteCHAR(buf, dtd->name);
+    if (dtd->ExternalID != NULL) {
+	xmlBufferWriteChar(buf, " PUBLIC ");
+	xmlBufferWriteQuotedString(buf, dtd->ExternalID);
+	xmlBufferWriteChar(buf, " ");
+	xmlBufferWriteQuotedString(buf, dtd->SystemID);
+    }  else if (dtd->SystemID != NULL) {
+	xmlBufferWriteChar(buf, " SYSTEM ");
+	xmlBufferWriteQuotedString(buf, dtd->SystemID);
+    }
+    if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
+        (dtd->attributes == NULL) && (dtd->notations == NULL)) {
+	xmlBufferWriteChar(buf, ">");
+	return;
+    }
+    xmlBufferWriteChar(buf, " [\n");
+    xmlNodeListDump(buf, dtd->doc, dtd->children, -1, 0);
+#if 0
+    if (dtd->entities != NULL)
+	xmlDumpEntitiesTable(buf, (xmlEntitiesTablePtr) dtd->entities);
+    if (dtd->notations != NULL)
+	xmlDumpNotationTable(buf, (xmlNotationTablePtr) dtd->notations);
+    if (dtd->elements != NULL)
+	xmlDumpElementTable(buf, (xmlElementTablePtr) dtd->elements);
+    if (dtd->attributes != NULL)
+	xmlDumpAttributeTable(buf, (xmlAttributeTablePtr) dtd->attributes);
+#endif
+    xmlBufferWriteChar(buf, "]>");
+}
+
+/**
+ * xmlAttrDump:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the attribute pointer
+ *
+ * Dump an XML attribute
+ */
+static void
+xmlAttrDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
+    xmlChar *value;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAttrDump : property == NULL\n");
+#endif
+	return;
+    }
+    xmlBufferWriteChar(buf, " ");
+    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+        xmlBufferWriteCHAR(buf, cur->ns->prefix);
+	xmlBufferWriteChar(buf, ":");
+    }
+    xmlBufferWriteCHAR(buf, cur->name);
+    value = xmlNodeListGetString(doc, cur->children, 0);
+    if (value != NULL) {
+	xmlBufferWriteChar(buf, "=");
+	xmlBufferWriteQuotedString(buf, value);
+	xmlFree(value);
+    } else  {
+	xmlBufferWriteChar(buf, "=\"\"");
+    }
+}
+
+/**
+ * xmlAttrListDump:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the first attribute pointer
+ *
+ * Dump a list of XML attributes
+ */
+static void
+xmlAttrListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAttrListDump : property == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+        xmlAttrDump(buf, doc, cur);
+	cur = cur->next;
+    }
+}
+
+
+
+/**
+ * xmlNodeListDump:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the first node
+ * @level: the imbrication level for indenting
+ * @format: is formatting allowed
+ *
+ * Dump an XML node list, recursive behaviour,children are printed too.
+ */
+static void
+xmlNodeListDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
+                int format) {
+    int i;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeListDump : node == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+	if ((format) && (xmlIndentTreeOutput) &&
+	    (cur->type == XML_ELEMENT_NODE))
+	    for (i = 0;i < level;i++)
+		xmlBufferWriteChar(buf, "  ");
+        xmlNodeDump(buf, doc, cur, level, format);
+	if (format) {
+	    xmlBufferWriteChar(buf, "\n");
+	}
+	cur = cur->next;
+    }
+}
+
+/**
+ * xmlNodeDump:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the current node
+ * @level: the imbrication level for indenting
+ * @format: is formatting allowed
+ *
+ * Dump an XML node, recursive behaviour,children are printed too.
+ */
+void
+xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level,
+            int format) {
+    int i;
+    xmlNodePtr tmp;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeDump : node == NULL\n");
+#endif
+	return;
+    }
+    if (cur->type == XML_XINCLUDE_START)
+	return;
+    if (cur->type == XML_XINCLUDE_END)
+	return;
+    if (cur->type == XML_DTD_NODE) {
+        xmlDtdDump(buf, (xmlDtdPtr) cur);
+	return;
+    }
+    if (cur->type == XML_ELEMENT_DECL) {
+        xmlDumpElementDecl(buf, (xmlElementPtr) cur);
+	return;
+    }
+    if (cur->type == XML_ATTRIBUTE_DECL) {
+        xmlDumpAttributeDecl(buf, (xmlAttributePtr) cur);
+	return;
+    }
+    if (cur->type == XML_ENTITY_DECL) {
+        xmlDumpEntityDecl(buf, (xmlEntityPtr) cur);
+	return;
+    }
+    if (cur->type == XML_TEXT_NODE) {
+	if (cur->content != NULL) {
+	    if ((cur->name == xmlStringText) ||
+		(cur->name != xmlStringTextNoenc)) {
+		xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+		buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+#else
+		buffer = xmlEncodeEntitiesReentrant(doc, 
+						xmlBufferContent(cur->content));
+#endif
+		if (buffer != NULL) {
+		    xmlBufferWriteCHAR(buf, buffer);
+		    xmlFree(buffer);
+		}
+	    } else {
+		/*
+		 * Disable escaping, needed for XSLT
+		 */
+#ifndef XML_USE_BUFFER_CONTENT
+		xmlBufferWriteCHAR(buf, cur->content);
+#else
+		xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
+#endif
+	    }
+	}
+	return;
+    }
+    if (cur->type == XML_PI_NODE) {
+	if (cur->content != NULL) {
+	    xmlBufferWriteChar(buf, "<?");
+	    xmlBufferWriteCHAR(buf, cur->name);
+	    if (cur->content != NULL) {
+		xmlBufferWriteChar(buf, " ");
+#ifndef XML_USE_BUFFER_CONTENT
+		xmlBufferWriteCHAR(buf, cur->content);
+#else
+		xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
+#endif
+	    }
+	    xmlBufferWriteChar(buf, "?>");
+	} else {
+	    xmlBufferWriteChar(buf, "<?");
+	    xmlBufferWriteCHAR(buf, cur->name);
+	    xmlBufferWriteChar(buf, "?>");
+	}
+	return;
+    }
+    if (cur->type == XML_COMMENT_NODE) {
+	if (cur->content != NULL) {
+	    xmlBufferWriteChar(buf, "<!--");
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlBufferWriteCHAR(buf, cur->content);
+#else
+	    xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
+#endif
+	    xmlBufferWriteChar(buf, "-->");
+	}
+	return;
+    }
+    if (cur->type == XML_ENTITY_REF_NODE) {
+        xmlBufferWriteChar(buf, "&");
+	xmlBufferWriteCHAR(buf, cur->name);
+        xmlBufferWriteChar(buf, ";");
+	return;
+    }
+    if (cur->type == XML_CDATA_SECTION_NODE) {
+        xmlBufferWriteChar(buf, "<![CDATA[");
+	if (cur->content != NULL)
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlBufferWriteCHAR(buf, cur->content);
+#else
+	    xmlBufferWriteCHAR(buf, xmlBufferContent(cur->content));
+#endif
+        xmlBufferWriteChar(buf, "]]>");
+	return;
+    }
+
+    if (format == 1) {
+	tmp = cur->children;
+	while (tmp != NULL) {
+	    if ((tmp->type == XML_TEXT_NODE) || 
+		(tmp->type == XML_ENTITY_REF_NODE)) {
+		format = 0;
+		break;
+	    }
+	    tmp = tmp->next;
+	}
+    }
+    xmlBufferWriteChar(buf, "<");
+    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+        xmlBufferWriteCHAR(buf, cur->ns->prefix);
+	xmlBufferWriteChar(buf, ":");
+    }
+
+    xmlBufferWriteCHAR(buf, cur->name);
+    if (cur->nsDef)
+        xmlNsListDump(buf, cur->nsDef);
+    if (cur->properties != NULL)
+        xmlAttrListDump(buf, doc, cur->properties);
+
+    if ((cur->content == NULL) && (cur->children == NULL) &&
+	(!xmlSaveNoEmptyTags)) {
+        xmlBufferWriteChar(buf, "/>");
+	return;
+    }
+    xmlBufferWriteChar(buf, ">");
+    if (cur->content != NULL) {
+	xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+	buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+#else
+	buffer = xmlEncodeEntitiesReentrant(doc, 
+		                            xmlBufferContent(cur->content));
+#endif
+	if (buffer != NULL) {
+	    xmlBufferWriteCHAR(buf, buffer);
+	    xmlFree(buffer);
+	}
+    }
+    if (cur->children != NULL) {
+	if (format) xmlBufferWriteChar(buf, "\n");
+	xmlNodeListDump(buf, doc, cur->children,
+		        (level >= 0?level+1:-1), format);
+	if ((xmlIndentTreeOutput) && (format))
+	    for (i = 0;i < level;i++)
+		xmlBufferWriteChar(buf, "  ");
+    }
+    xmlBufferWriteChar(buf, "</");
+    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+        xmlBufferWriteCHAR(buf, cur->ns->prefix);
+	xmlBufferWriteChar(buf, ":");
+    }
+
+    xmlBufferWriteCHAR(buf, cur->name);
+    xmlBufferWriteChar(buf, ">");
+}
+
+/**
+ * xmlElemDump:
+ * @f:  the FILE * for the output
+ * @doc:  the document
+ * @cur:  the current node
+ *
+ * Dump an XML/HTML node, recursive behaviour,children are printed too.
+ */
+void
+xmlElemDump(FILE *f, xmlDocPtr doc, xmlNodePtr cur) {
+    xmlBufferPtr buf;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlElemDump : cur == NULL\n");
+#endif
+	return;
+    }
+    if (doc == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlElemDump : doc == NULL\n");
+#endif
+    }
+    buf = xmlBufferCreate();
+    if (buf == NULL) return;
+    if ((doc != NULL) && 
+        (doc->type == XML_HTML_DOCUMENT_NODE)) {
+#ifdef LIBXML_HTML_ENABLED
+        htmlNodeDump(buf, doc, cur);
+#else	
+	xmlGenericError(xmlGenericErrorContext,
+		"HTML support not compiled in\n");
+#endif /* LIBXML_HTML_ENABLED */
+    } else
+        xmlNodeDump(buf, doc, cur, 0, 1);
+    xmlBufferDump(f, buf);
+    xmlBufferFree(buf);
+}
+
+/************************************************************************
+ *									*
+ *   		Dumping XML tree content to an I/O output buffer	*
+ *									*
+ ************************************************************************/
+
+void
+xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
+                  int level, int format, const char *encoding);
+static void
+xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
+                  int level, int format, const char *encoding);
+/**
+ * xmlNsDumpOutput:
+ * @buf:  the XML buffer output
+ * @cur:  a namespace
+ *
+ * Dump a local Namespace definition.
+ * Should be called in the context of attributes dumps.
+ */
+static void
+xmlNsDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNsDump : Ns == NULL\n");
+#endif
+	return;
+    }
+    if ((cur->type == XML_LOCAL_NAMESPACE) && (cur->href != NULL)) {
+        /* Within the context of an element attributes */
+	if (cur->prefix != NULL) {
+	    xmlOutputBufferWriteString(buf, " xmlns:");
+	    xmlOutputBufferWriteString(buf, (const char *)cur->prefix);
+	} else
+	    xmlOutputBufferWriteString(buf, " xmlns");
+	xmlOutputBufferWriteString(buf, "=");
+	xmlBufferWriteQuotedString(buf->buffer, cur->href);
+    }
+}
+
+/**
+ * xmlNsListDumpOutput:
+ * @buf:  the XML buffer output
+ * @cur:  the first namespace
+ *
+ * Dump a list of local Namespace definitions.
+ * Should be called in the context of attributes dumps.
+ */
+static void
+xmlNsListDumpOutput(xmlOutputBufferPtr buf, xmlNsPtr cur) {
+    while (cur != NULL) {
+        xmlNsDumpOutput(buf, cur);
+	cur = cur->next;
+    }
+}
+
+/**
+ * xmlDtdDumpOutput:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @encoding:  an optional encoding string
+ * 
+ * Dump the XML document DTD, if any.
+ */
+static void
+xmlDtdDumpOutput(xmlOutputBufferPtr buf, xmlDtdPtr dtd, const char *encoding) {
+    if (dtd == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlDtdDump : no internal subset\n");
+#endif
+	return;
+    }
+    xmlOutputBufferWriteString(buf, "<!DOCTYPE ");
+    xmlOutputBufferWriteString(buf, (const char *)dtd->name);
+    if (dtd->ExternalID != NULL) {
+	xmlOutputBufferWriteString(buf, " PUBLIC ");
+	xmlBufferWriteQuotedString(buf->buffer, dtd->ExternalID);
+	xmlOutputBufferWriteString(buf, " ");
+	xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
+    }  else if (dtd->SystemID != NULL) {
+	xmlOutputBufferWriteString(buf, " SYSTEM ");
+	xmlBufferWriteQuotedString(buf->buffer, dtd->SystemID);
+    }
+    if ((dtd->entities == NULL) && (dtd->elements == NULL) &&
+        (dtd->attributes == NULL) && (dtd->notations == NULL)) {
+	xmlOutputBufferWriteString(buf, ">");
+	return;
+    }
+    xmlOutputBufferWriteString(buf, " [\n");
+    xmlNodeListDumpOutput(buf, dtd->doc, dtd->children, -1, 0, encoding);
+    xmlOutputBufferWriteString(buf, "]>");
+}
+
+/**
+ * xmlAttrDumpOutput:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the attribute pointer
+ * @encoding:  an optional encoding string
+ *
+ * Dump an XML attribute
+ */
+static void
+xmlAttrDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlAttrPtr cur,
+	          const char *encoding) {
+    xmlChar *value;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAttrDump : property == NULL\n");
+#endif
+	return;
+    }
+    xmlOutputBufferWriteString(buf, " ");
+    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+	xmlOutputBufferWriteString(buf, ":");
+    }
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    value = xmlNodeListGetString(doc, cur->children, 0);
+    if (value) {
+	xmlOutputBufferWriteString(buf, "=");
+	xmlBufferWriteQuotedString(buf->buffer, value);
+	xmlFree(value);
+    } else  {
+	xmlOutputBufferWriteString(buf, "=\"\"");
+    }
+}
+
+/**
+ * xmlAttrListDumpOutput:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the first attribute pointer
+ * @encoding:  an optional encoding string
+ *
+ * Dump a list of XML attributes
+ */
+static void
+xmlAttrListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
+	              xmlAttrPtr cur, const char *encoding) {
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAttrListDump : property == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+        xmlAttrDumpOutput(buf, doc, cur, encoding);
+	cur = cur->next;
+    }
+}
+
+
+
+/**
+ * xmlNodeListDumpOutput:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the first node
+ * @level: the imbrication level for indenting
+ * @format: is formatting allowed
+ * @encoding:  an optional encoding string
+ *
+ * Dump an XML node list, recursive behaviour,children are printed too.
+ */
+static void
+xmlNodeListDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc,
+                xmlNodePtr cur, int level, int format, const char *encoding) {
+    int i;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeListDump : node == NULL\n");
+#endif
+	return;
+    }
+    while (cur != NULL) {
+	if ((format) && (xmlIndentTreeOutput) &&
+	    (cur->type == XML_ELEMENT_NODE))
+	    for (i = 0;i < level;i++)
+		xmlOutputBufferWriteString(buf, "  ");
+        xmlNodeDumpOutput(buf, doc, cur, level, format, encoding);
+	if (format) {
+	    xmlOutputBufferWriteString(buf, "\n");
+	}
+	cur = cur->next;
+    }
+}
+
+/**
+ * xmlNodeDumpOutput:
+ * @buf:  the XML buffer output
+ * @doc:  the document
+ * @cur:  the current node
+ * @level: the imbrication level for indenting
+ * @format: is formatting allowed
+ * @encoding:  an optional encoding string
+ *
+ * Dump an XML node, recursive behaviour,children are printed too.
+ */
+void
+xmlNodeDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur,
+            int level, int format, const char *encoding) {
+    int i;
+    xmlNodePtr tmp;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlNodeDump : node == NULL\n");
+#endif
+	return;
+    }
+    if (cur->type == XML_XINCLUDE_START)
+	return;
+    if (cur->type == XML_XINCLUDE_END)
+	return;
+    if (cur->type == XML_DTD_NODE) {
+        xmlDtdDumpOutput(buf, (xmlDtdPtr) cur, encoding);
+	return;
+    }
+    if (cur->type == XML_ELEMENT_DECL) {
+        xmlDumpElementDecl(buf->buffer, (xmlElementPtr) cur);
+	return;
+    }
+    if (cur->type == XML_ATTRIBUTE_DECL) {
+        xmlDumpAttributeDecl(buf->buffer, (xmlAttributePtr) cur);
+	return;
+    }
+    if (cur->type == XML_ENTITY_DECL) {
+        xmlDumpEntityDecl(buf->buffer, (xmlEntityPtr) cur);
+	return;
+    }
+    if (cur->type == XML_TEXT_NODE) {
+	if (cur->content != NULL) {
+	    if ((cur->name == xmlStringText) ||
+		(cur->name != xmlStringTextNoenc)) {
+		xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+		if (encoding == NULL)
+		    buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+		else
+		    buffer = xmlEncodeSpecialChars(doc, cur->content);
+#else
+		if (encoding == NULL)
+		    buffer = xmlEncodeEntitiesReentrant(doc, 
+					xmlBufferContent(cur->content));
+		else
+		    buffer = xmlEncodeSpecialChars(doc, 
+					xmlBufferContent(cur->content));
+#endif
+		if (buffer != NULL) {
+		    xmlOutputBufferWriteString(buf, (const char *)buffer);
+		    xmlFree(buffer);
+		}
+	    } else {
+		/*
+		 * Disable escaping, needed for XSLT
+		 */
+#ifndef XML_USE_BUFFER_CONTENT
+		xmlOutputBufferWriteString(buf, (const char *) cur->content);
+#else
+		xmlOutputBufferWriteString(buf, xmlBufferContent(cur->content));
+#endif
+	    }
+	}
+
+	return;
+    }
+    if (cur->type == XML_PI_NODE) {
+	if (cur->content != NULL) {
+	    xmlOutputBufferWriteString(buf, "<?");
+	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+	    if (cur->content != NULL) {
+		xmlOutputBufferWriteString(buf, " ");
+#ifndef XML_USE_BUFFER_CONTENT
+		xmlOutputBufferWriteString(buf, (const char *)cur->content);
+#else
+		xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
+#endif
+	    }
+	    xmlOutputBufferWriteString(buf, "?>");
+	} else {
+	    xmlOutputBufferWriteString(buf, "<?");
+	    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+	    xmlOutputBufferWriteString(buf, "?>");
+	}
+	return;
+    }
+    if (cur->type == XML_COMMENT_NODE) {
+	if (cur->content != NULL) {
+	    xmlOutputBufferWriteString(buf, "<!--");
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
+#else
+	    xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
+#endif
+	    xmlOutputBufferWriteString(buf, "-->");
+	}
+	return;
+    }
+    if (cur->type == XML_ENTITY_REF_NODE) {
+        xmlOutputBufferWriteString(buf, "&");
+	xmlOutputBufferWriteString(buf, (const char *)cur->name);
+        xmlOutputBufferWriteString(buf, ";");
+	return;
+    }
+    if (cur->type == XML_CDATA_SECTION_NODE) {
+        xmlOutputBufferWriteString(buf, "<![CDATA[");
+	if (cur->content != NULL)
+#ifndef XML_USE_BUFFER_CONTENT
+	    xmlOutputBufferWriteString(buf, (const char *)cur->content);
+#else
+	    xmlOutputBufferWriteString(buf, (const char *)xmlBufferContent(cur->content));
+#endif
+        xmlOutputBufferWriteString(buf, "]]>");
+	return;
+    }
+
+    if (format == 1) {
+	tmp = cur->children;
+	while (tmp != NULL) {
+	    if ((tmp->type == XML_TEXT_NODE) || 
+		(tmp->type == XML_ENTITY_REF_NODE)) {
+		format = 0;
+		break;
+	    }
+	    tmp = tmp->next;
+	}
+    }
+    xmlOutputBufferWriteString(buf, "<");
+    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+	xmlOutputBufferWriteString(buf, ":");
+    }
+
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    if (cur->nsDef)
+        xmlNsListDumpOutput(buf, cur->nsDef);
+    if (cur->properties != NULL)
+        xmlAttrListDumpOutput(buf, doc, cur->properties, encoding);
+
+    if ((cur->content == NULL) && (cur->children == NULL) &&
+	(!xmlSaveNoEmptyTags)) {
+        xmlOutputBufferWriteString(buf, "/>");
+	return;
+    }
+    xmlOutputBufferWriteString(buf, ">");
+    if (cur->content != NULL) {
+	xmlChar *buffer;
+
+#ifndef XML_USE_BUFFER_CONTENT
+	if (encoding == NULL)
+	    buffer = xmlEncodeEntitiesReentrant(doc, cur->content);
+	else
+	    buffer = xmlEncodeSpecialChars(doc, cur->content);
+#else
+	if (encoding == NULL)
+	    buffer = xmlEncodeEntitiesReentrant(doc, 
+				xmlBufferContent(cur->content));
+	else
+	    buffer = xmlEncodeSpecialChars(doc, 
+				xmlBufferContent(cur->content));
+#endif
+	if (buffer != NULL) {
+	    xmlOutputBufferWriteString(buf, (const char *)buffer);
+	    xmlFree(buffer);
+	}
+    }
+    if (cur->children != NULL) {
+	if (format) xmlOutputBufferWriteString(buf, "\n");
+	xmlNodeListDumpOutput(buf, doc, cur->children,
+		        (level >= 0?level+1:-1), format, encoding);
+	if ((xmlIndentTreeOutput) && (format))
+	    for (i = 0;i < level;i++)
+		xmlOutputBufferWriteString(buf, "  ");
+    }
+    xmlOutputBufferWriteString(buf, "</");
+    if ((cur->ns != NULL) && (cur->ns->prefix != NULL)) {
+        xmlOutputBufferWriteString(buf, (const char *)cur->ns->prefix);
+	xmlOutputBufferWriteString(buf, ":");
+    }
+
+    xmlOutputBufferWriteString(buf, (const char *)cur->name);
+    xmlOutputBufferWriteString(buf, ">");
+}
+
+/**
+ * xmlDocContentDumpOutput:
+ * @buf:  the XML buffer output
+ * @cur:  the document
+ * @encoding:  an optional encoding string
+ * @format:  should formatting spaces been added
+ *
+ * Dump an XML document.
+ */
+static void
+xmlDocContentDumpOutput(xmlOutputBufferPtr buf, xmlDocPtr cur,
+	                const char *encoding, int format) {
+    xmlOutputBufferWriteString(buf, "<?xml version=");
+    if (cur->version != NULL) 
+	xmlBufferWriteQuotedString(buf->buffer, cur->version);
+    else
+	xmlOutputBufferWriteString(buf, "\"1.0\"");
+    if (encoding == NULL) {
+	if (cur->encoding != NULL)
+	    encoding = (const char *) cur->encoding;
+	else if (cur->charset != XML_CHAR_ENCODING_UTF8)
+	    encoding = xmlGetCharEncodingName((xmlCharEncoding) cur->charset);
+    }
+    if (encoding != NULL) {
+        xmlOutputBufferWriteString(buf, " encoding=");
+	xmlBufferWriteQuotedString(buf->buffer, (xmlChar *) encoding);
+    }
+    switch (cur->standalone) {
+        case 0:
+	    xmlOutputBufferWriteString(buf, " standalone=\"no\"");
+	    break;
+        case 1:
+	    xmlOutputBufferWriteString(buf, " standalone=\"yes\"");
+	    break;
+    }
+    xmlOutputBufferWriteString(buf, "?>\n");
+    if (cur->children != NULL) {
+        xmlNodePtr child = cur->children;
+
+	while (child != NULL) {
+	    xmlNodeDumpOutput(buf, cur, child, 0, format, encoding);
+	    xmlOutputBufferWriteString(buf, "\n");
+	    child = child->next;
+	}
+    }
+}
+
+/************************************************************************
+ *									*
+ *		Saving functions front-ends				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlDocDumpMemoryEnc:
+ * @out_doc:  Document to generate XML text from
+ * @doc_txt_ptr:  Memory pointer for allocated XML text
+ * @doc_txt_len:  Length of the generated XML text
+ * @txt_encoding:  Character encoding to use when generating XML text
+ * @format:  should formatting spaces been added
+ *
+ * Dump the current DOM tree into memory using the character encoding specified
+ * by the caller.  Note it is up to the caller of this function to free the
+ * allocated memory.
+ */
+
+void
+xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
+		int * doc_txt_len, const char * txt_encoding, int format) {
+    int                         dummy = 0;
+
+    xmlCharEncoding             doc_charset;
+    xmlOutputBufferPtr          out_buff = NULL;
+    xmlCharEncodingHandlerPtr   conv_hdlr = NULL;
+
+    if (doc_txt_len == NULL) {
+        doc_txt_len = &dummy;   /*  Continue, caller just won't get length */
+    }
+
+    if (doc_txt_ptr == NULL) {
+        *doc_txt_len = 0;
+        xmlGenericError(xmlGenericErrorContext,
+                    "xmlDocDumpFormatMemoryEnc:  Null return buffer pointer.");
+        return;
+    }
+
+    *doc_txt_ptr = NULL;
+    *doc_txt_len = 0;
+
+    if (out_doc == NULL) {
+        /*  No document, no output  */
+        xmlGenericError(xmlGenericErrorContext,
+                "xmlDocDumpFormatMemoryEnc:  Null DOM tree document pointer.\n");
+        return;
+    }
+
+    /*
+     *  Validate the encoding value, if provided.
+     *  This logic is copied from xmlSaveFileEnc.
+     */
+
+    if (txt_encoding == NULL)
+	txt_encoding = (const char *) out_doc->encoding;
+    if (txt_encoding != NULL) {
+        doc_charset = xmlParseCharEncoding(txt_encoding);
+
+        if (out_doc->charset != XML_CHAR_ENCODING_UTF8) {
+            xmlGenericError(xmlGenericErrorContext,
+                    "xmlDocDumpFormatMemoryEnc: Source document not in UTF8\n");
+            return;
+
+        } else if (doc_charset != XML_CHAR_ENCODING_UTF8) {
+            conv_hdlr = xmlFindCharEncodingHandler(txt_encoding);
+            if ( conv_hdlr == NULL ) {
+                xmlGenericError(xmlGenericErrorContext,
+                                "%s:  %s %s '%s'\n",
+                                "xmlDocDumpFormatMemoryEnc",
+                                "Failed to identify encoding handler for",
+                                "character set",
+                                txt_encoding);
+                return;
+            }
+        }
+    }
+
+    if ((out_buff = xmlAllocOutputBuffer(conv_hdlr)) == NULL ) {
+        xmlGenericError(xmlGenericErrorContext,
+	    "xmlDocDumpFormatMemoryEnc: Failed to allocate output buffer.\n");
+        return;
+    }
+
+    xmlDocContentDumpOutput(out_buff, out_doc, txt_encoding, 1);
+    xmlOutputBufferFlush(out_buff);
+    if (out_buff->conv != NULL) {
+	*doc_txt_len = out_buff->conv->use;
+	*doc_txt_ptr = xmlStrndup(out_buff->conv->content, *doc_txt_len);
+    } else {
+	*doc_txt_len = out_buff->buffer->use;
+	*doc_txt_ptr = xmlStrndup(out_buff->buffer->content, *doc_txt_len);
+    }
+    (void)xmlOutputBufferClose(out_buff);
+
+    if ((*doc_txt_ptr == NULL) && (*doc_txt_len > 0)) {
+        *doc_txt_len = 0;
+        xmlGenericError(xmlGenericErrorContext,
+                "xmlDocDumpFormatMemoryEnc:  %s\n",
+                "Failed to allocate memory for document text representation.");
+    }
+
+    return;
+}
+
+/**
+ * xmlDocDumpMemory:
+ * @cur:  the document
+ * @mem:  OUT: the memory pointer
+ * @size:  OUT: the memory lenght
+ *
+ * Dump an XML document in memory and return the xmlChar * and it's size.
+ * It's up to the caller to free the memory.
+ */
+void
+xmlDocDumpMemory(xmlDocPtr cur, xmlChar**mem, int *size) {
+    xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, 0);
+}
+
+/**
+ * xmlDocDumpFormatMemory:
+ * @cur:  the document
+ * @mem:  OUT: the memory pointer
+ * @size:  OUT: the memory lenght
+ * @format:  should formatting spaces been added
+ *
+ *
+ * Dump an XML document in memory and return the xmlChar * and it's size.
+ * It's up to the caller to free the memory.
+ */
+void
+xmlDocDumpFormatMemory(xmlDocPtr cur, xmlChar**mem, int *size, int format) {
+    xmlDocDumpFormatMemoryEnc(cur, mem, size, NULL, format);
+}
+
+/**
+ * xmlDocDumpMemoryEnc:
+ * @out_doc:  Document to generate XML text from
+ * @doc_txt_ptr:  Memory pointer for allocated XML text
+ * @doc_txt_len:  Length of the generated XML text
+ * @txt_encoding:  Character encoding to use when generating XML text
+ *
+ * Dump the current DOM tree into memory using the character encoding specified
+ * by the caller.  Note it is up to the caller of this function to free the
+ * allocated memory.
+ */
+
+void
+xmlDocDumpMemoryEnc(xmlDocPtr out_doc, xmlChar **doc_txt_ptr,
+	            int * doc_txt_len, const char * txt_encoding) {
+    xmlDocDumpFormatMemoryEnc(out_doc, doc_txt_ptr, doc_txt_len,
+	                      txt_encoding, 1);
+}
+
+/**
+ * xmlGetDocCompressMode:
+ * @doc:  the document
+ *
+ * get the compression ratio for a document, ZLIB based
+ * Returns 0 (uncompressed) to 9 (max compression)
+ */
+int
+xmlGetDocCompressMode (xmlDocPtr doc) {
+    if (doc == NULL) return(-1);
+    return(doc->compression);
+}
+
+/**
+ * xmlSetDocCompressMode:
+ * @doc:  the document
+ * @mode:  the compression ratio
+ *
+ * set the compression ratio for a document, ZLIB based
+ * Correct values: 0 (uncompressed) to 9 (max compression)
+ */
+void
+xmlSetDocCompressMode (xmlDocPtr doc, int mode) {
+    if (doc == NULL) return;
+    if (mode < 0) doc->compression = 0;
+    else if (mode > 9) doc->compression = 9;
+    else doc->compression = mode;
+}
+
+/**
+ * xmlGetCompressMode:
+ *
+ * get the default compression mode used, ZLIB based.
+ * Returns 0 (uncompressed) to 9 (max compression)
+ */
+int
+ xmlGetCompressMode(void) {
+    return(xmlCompressMode);
+}
+
+/**
+ * xmlSetCompressMode:
+ * @mode:  the compression ratio
+ *
+ * set the default compression mode used, ZLIB based
+ * Correct values: 0 (uncompressed) to 9 (max compression)
+ */
+void
+xmlSetCompressMode(int mode) {
+    if (mode < 0) xmlCompressMode = 0;
+    else if (mode > 9) xmlCompressMode = 9;
+    else xmlCompressMode = mode;
+}
+
+/**
+ * xmlDocDump:
+ * @f:  the FILE*
+ * @cur:  the document
+ *
+ * Dump an XML document to an open FILE.
+ *
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+xmlDocDump(FILE *f, xmlDocPtr cur) {
+    xmlOutputBufferPtr buf;
+    const char * encoding;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    int ret;
+
+    if (cur == NULL) {
+#ifdef DEBUG_TREE
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlDocDump : document == NULL\n");
+#endif
+	return(-1);
+    }
+    encoding = (const char *) cur->encoding;
+
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+
+	if (cur->charset != XML_CHAR_ENCODING_UTF8) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlDocDump: document not in UTF8\n");
+	    return(-1);
+	}
+	if (enc != XML_CHAR_ENCODING_UTF8) {
+	    handler = xmlFindCharEncodingHandler(encoding);
+	    if (handler == NULL) {
+		xmlFree((char *) cur->encoding);
+		cur->encoding = NULL;
+	    }
+	}
+    }
+    buf = xmlOutputBufferCreateFile(f, handler);
+    if (buf == NULL) return(-1);
+    xmlDocContentDumpOutput(buf, cur, NULL, 1);
+
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * xmlSaveFileTo:
+ * @buf:  an output I/O buffer
+ * @cur:  the document
+ * @encoding:  the encoding if any assuming the i/O layer handles the trancoding
+ *
+ * Dump an XML document to an I/O buffer.
+ *
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+xmlSaveFileTo(xmlOutputBuffer *buf, xmlDocPtr cur, const char *encoding) {
+    int ret;
+
+    if (buf == NULL) return(0);
+    xmlDocContentDumpOutput(buf, cur, encoding, 1);
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * xmlSaveFileEnc:
+ * @filename:  the filename (or URL)
+ * @cur:  the document
+ * @encoding:  the name of an encoding (or NULL)
+ *
+ * Dump an XML document, converting it to the given encoding
+ *
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+xmlSaveFileEnc(const char *filename, xmlDocPtr cur, const char *encoding) {
+    xmlOutputBufferPtr buf;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    int ret;
+
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+	if (cur->charset != XML_CHAR_ENCODING_UTF8) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlSaveFileEnc: document not in UTF8\n");
+	    return(-1);
+	}
+	if (enc != XML_CHAR_ENCODING_UTF8) {
+	    handler = xmlFindCharEncodingHandler(encoding);
+	    if (handler == NULL) {
+		return(-1);
+	    }
+	}
+    }
+
+    /* 
+     * save the content to a temp buffer.
+     */
+    buf = xmlOutputBufferCreateFilename(filename, handler, 0);
+    if (buf == NULL) return(-1);
+
+    xmlDocContentDumpOutput(buf, cur, encoding, 1);
+
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
+/**
+ * xmlSaveFile:
+ * @filename:  the filename (or URL)
+ * @cur:  the document
+ *
+ * Dump an XML document to a file. Will use compression if
+ * compiled in and enabled. If @filename is "-" the stdout file is
+ * used.
+ * returns: the number of byte written or -1 in case of failure.
+ */
+int
+xmlSaveFile(const char *filename, xmlDocPtr cur) {
+    xmlOutputBufferPtr buf;
+    const char *encoding;
+    xmlCharEncodingHandlerPtr handler = NULL;
+    int ret;
+
+    if (cur == NULL)
+	return(-1);
+    encoding = (const char *) cur->encoding;
+
+    /* 
+     * save the content to a temp buffer.
+     */
+#ifdef HAVE_ZLIB_H
+    if (cur->compression < 0) cur->compression = xmlCompressMode;
+#endif
+    if (encoding != NULL) {
+	xmlCharEncoding enc;
+
+	enc = xmlParseCharEncoding(encoding);
+
+	if (cur->charset != XML_CHAR_ENCODING_UTF8) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlSaveFile: document not in UTF8\n");
+	    return(-1);
+	}
+	if (enc != XML_CHAR_ENCODING_UTF8) {
+	    handler = xmlFindCharEncodingHandler(encoding);
+	    if (handler == NULL) {
+		xmlFree((char *) cur->encoding);
+		cur->encoding = NULL;
+	    }
+	}
+    }
+
+    buf = xmlOutputBufferCreateFilename(filename, handler, cur->compression);
+    if (buf == NULL) return(-1);
+
+    xmlDocContentDumpOutput(buf, cur, NULL, 1);
+
+    ret = xmlOutputBufferClose(buf);
+    return(ret);
+}
+
diff --git a/tree.h b/tree.h
new file mode 100644
index 0000000..648817d
--- /dev/null
+++ b/tree.h
@@ -0,0 +1,701 @@
+/*
+ * tree.h : describes the structures found in an tree resulting
+ *          from an XML parsing.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - added redefinition of xmlBufferWriteChar for VMS
+ *
+ */
+
+#ifndef __XML_TREE_H__
+#define __XML_TREE_H__
+
+#include <stdio.h>
+#include <libxml/xmlversion.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define XML_XML_NAMESPACE \
+    (const xmlChar *) "http://www.w3.org/XML/1998/namespace"
+
+/*
+ * The different element types carried by an XML tree
+ *
+ * NOTE: This is synchronized with DOM Level1 values
+ *       See http://www.w3.org/TR/REC-DOM-Level-1/
+ *
+ * Actually this had diverged a bit, and now XML_DOCUMENT_TYPE_NODE should
+ * be deprecated to use an XML_DTD_NODE.
+ */
+typedef enum {
+    XML_ELEMENT_NODE=		1,
+    XML_ATTRIBUTE_NODE=		2,
+    XML_TEXT_NODE=		3,
+    XML_CDATA_SECTION_NODE=	4,
+    XML_ENTITY_REF_NODE=	5,
+    XML_ENTITY_NODE=		6,
+    XML_PI_NODE=		7,
+    XML_COMMENT_NODE=		8,
+    XML_DOCUMENT_NODE=		9,
+    XML_DOCUMENT_TYPE_NODE=	10,
+    XML_DOCUMENT_FRAG_NODE=	11,
+    XML_NOTATION_NODE=		12,
+    XML_HTML_DOCUMENT_NODE=	13,
+    XML_DTD_NODE=		14,
+    XML_ELEMENT_DECL=		15,
+    XML_ATTRIBUTE_DECL=		16,
+    XML_ENTITY_DECL=		17,
+    XML_NAMESPACE_DECL=		18,
+    XML_XINCLUDE_START=		19,
+    XML_XINCLUDE_END=		20
+#ifdef LIBXML_SGML_ENABLED
+   ,XML_SGML_DOCUMENT_NODE=	21
+#endif
+} xmlElementType;
+
+/*
+ * Size of an internal character representation.
+ *
+ * We use 8bit chars internal representation for memory efficiency,
+ * Note that with 8 bits wide xmlChars one can still use UTF-8 to handle
+ * correctly non ISO-Latin input.
+ */
+
+typedef unsigned char xmlChar;
+
+#ifndef WIN32
+#ifndef CHAR
+#define CHAR xmlChar
+#endif
+#endif
+
+#define BAD_CAST (xmlChar *)
+
+/*
+ * a DTD Notation definition
+ */
+
+typedef struct _xmlNotation xmlNotation;
+typedef xmlNotation *xmlNotationPtr;
+struct _xmlNotation {
+    const xmlChar               *name;	/* Notation name */
+    const xmlChar               *PublicID;	/* Public identifier, if any */
+    const xmlChar               *SystemID;	/* System identifier, if any */
+};
+
+/*
+ * a DTD Attribute definition
+ */
+
+typedef enum {
+    XML_ATTRIBUTE_CDATA = 1,
+    XML_ATTRIBUTE_ID,
+    XML_ATTRIBUTE_IDREF	,
+    XML_ATTRIBUTE_IDREFS,
+    XML_ATTRIBUTE_ENTITY,
+    XML_ATTRIBUTE_ENTITIES,
+    XML_ATTRIBUTE_NMTOKEN,
+    XML_ATTRIBUTE_NMTOKENS,
+    XML_ATTRIBUTE_ENUMERATION,
+    XML_ATTRIBUTE_NOTATION
+} xmlAttributeType;
+
+typedef enum {
+    XML_ATTRIBUTE_NONE = 1,
+    XML_ATTRIBUTE_REQUIRED,
+    XML_ATTRIBUTE_IMPLIED,
+    XML_ATTRIBUTE_FIXED
+} xmlAttributeDefault;
+
+typedef struct _xmlEnumeration xmlEnumeration;
+typedef xmlEnumeration *xmlEnumerationPtr;
+struct _xmlEnumeration {
+    struct _xmlEnumeration    *next;	/* next one */
+    const xmlChar            *name;	/* Enumeration name */
+};
+
+typedef struct _xmlAttribute xmlAttribute;
+typedef xmlAttribute *xmlAttributePtr;
+struct _xmlAttribute {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	        /* for Corba, must be first ! */
+#endif
+    xmlElementType          type;       /* XML_ATTRIBUTE_DECL, must be second ! */
+    const xmlChar          *name;	/* Attribute name */
+    struct _xmlNode    *children;	/* NULL */
+    struct _xmlNode        *last;	/* NULL */
+    struct _xmlDtd       *parent;	/* -> DTD */
+    struct _xmlNode        *next;	/* next sibling link  */
+    struct _xmlNode        *prev;	/* previous sibling link  */
+    struct _xmlDoc          *doc;       /* the containing document */
+
+    struct _xmlAttribute  *nexth;	/* next in hash table */
+    xmlAttributeType       atype;	/* The attribute type */
+    xmlAttributeDefault      def;	/* the default */
+    const xmlChar  *defaultValue;	/* or the default value */
+    xmlEnumerationPtr       tree;       /* or the enumeration tree if any */
+    const xmlChar        *prefix;	/* the namespace prefix if any */
+    const xmlChar          *elem;	/* Element holding the attribute */
+};
+
+/*
+ * a DTD Element definition.
+ */
+typedef enum {
+    XML_ELEMENT_CONTENT_PCDATA = 1,
+    XML_ELEMENT_CONTENT_ELEMENT,
+    XML_ELEMENT_CONTENT_SEQ,
+    XML_ELEMENT_CONTENT_OR
+} xmlElementContentType;
+
+typedef enum {
+    XML_ELEMENT_CONTENT_ONCE = 1,
+    XML_ELEMENT_CONTENT_OPT,
+    XML_ELEMENT_CONTENT_MULT,
+    XML_ELEMENT_CONTENT_PLUS
+} xmlElementContentOccur;
+
+typedef struct _xmlElementContent xmlElementContent;
+typedef xmlElementContent *xmlElementContentPtr;
+struct _xmlElementContent {
+    xmlElementContentType     type;	/* PCDATA, ELEMENT, SEQ or OR */
+    xmlElementContentOccur    ocur;	/* ONCE, OPT, MULT or PLUS */
+    const xmlChar            *name;	/* Element name */
+    struct _xmlElementContent *c1;	/* first child */
+    struct _xmlElementContent *c2;	/* second child */
+};
+
+typedef enum {
+    XML_ELEMENT_TYPE_EMPTY = 1,
+    XML_ELEMENT_TYPE_ANY,
+    XML_ELEMENT_TYPE_MIXED,
+    XML_ELEMENT_TYPE_ELEMENT
+} xmlElementTypeVal;
+
+typedef struct _xmlElement xmlElement;
+typedef xmlElement *xmlElementPtr;
+struct _xmlElement {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	        /* for Corba, must be first ! */
+#endif
+    xmlElementType          type;       /* XML_ELEMENT_DECL, must be second ! */
+    const xmlChar          *name;	/* Element name */
+    struct _xmlNode    *children;	/* NULL */
+    struct _xmlNode        *last;	/* NULL */
+    struct _xmlDtd       *parent;	/* -> DTD */
+    struct _xmlNode        *next;	/* next sibling link  */
+    struct _xmlNode        *prev;	/* previous sibling link  */
+    struct _xmlDoc          *doc;       /* the containing document */
+
+    xmlElementTypeVal      etype;	/* The type */
+    xmlElementContentPtr content;	/* the allowed element content */
+    xmlAttributePtr   attributes;	/* List of the declared attributes */
+    const xmlChar        *prefix;	/* the namespace prefix if any */
+};
+
+/*
+ * An XML namespace.
+ * Note that prefix == NULL is valid, it defines the default namespace
+ * within the subtree (until overriden).
+ *
+ * XML_GLOBAL_NAMESPACE is now deprecated for good
+ * xmlNsType is unified with xmlElementType
+ */
+
+#define XML_LOCAL_NAMESPACE XML_NAMESPACE_DECL
+typedef xmlElementType xmlNsType;
+
+typedef struct _xmlNs xmlNs;
+typedef xmlNs *xmlNsPtr;
+struct _xmlNs {
+    struct _xmlNs  *next;	/* next Ns link for this node  */
+    xmlNsType      type;	/* global or local */
+    const xmlChar *href;	/* URL for the namespace */
+    const xmlChar *prefix;	/* prefix for the namespace */
+};
+
+/*
+ * An XML DtD, as defined by <!DOCTYPE.
+ */
+typedef struct _xmlDtd xmlDtd;
+typedef xmlDtd *xmlDtdPtr;
+struct _xmlDtd {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType  type;       /* XML_DTD_NODE, must be second ! */
+    const xmlChar *name;	/* Name of the DTD */
+    struct _xmlNode *children;	/* the value of the property link */
+    struct _xmlNode *last;	/* last child link */
+    struct _xmlDoc  *parent;	/* child->parent link */
+    struct _xmlNode *next;	/* next sibling link  */
+    struct _xmlNode *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* the containing document */
+
+    /* End of common part */
+    void          *notations;   /* Hash table for notations if any */
+    void          *elements;    /* Hash table for elements if any */
+    void          *attributes;  /* Hash table for attributes if any */
+    void          *entities;    /* Hash table for entities if any */
+    const xmlChar *ExternalID;	/* External identifier for PUBLIC DTD */
+    const xmlChar *SystemID;	/* URI for a SYSTEM or PUBLIC DTD */
+    void          *pentities;   /* Hash table for param entities if any */
+};
+
+/*
+ * A attribute of an XML node.
+ */
+typedef struct _xmlAttr xmlAttr;
+typedef xmlAttr *xmlAttrPtr;
+struct _xmlAttr {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType   type;      /* XML_ATTRIBUTE_NODE, must be second ! */
+    const xmlChar   *name;      /* the name of the property */
+    struct _xmlNode *children;	/* the value of the property */
+    struct _xmlNode *last;	/* NULL */
+    struct _xmlNode *parent;	/* child->parent link */
+    struct _xmlAttr *next;	/* next sibling link  */
+    struct _xmlAttr *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* the containing document */
+    xmlNs           *ns;        /* pointer to the associated namespace */
+    xmlAttributeType atype;     /* the attribute type if validating */
+};
+
+/*
+ * An XML ID instance.
+ */
+
+typedef struct _xmlID xmlID;
+typedef xmlID *xmlIDPtr;
+struct _xmlID {
+    struct _xmlID    *next;	/* next ID */
+    const xmlChar    *value;	/* The ID name */
+    xmlAttrPtr        attr;	/* The attribut holding it */
+};
+
+/*
+ * An XML IDREF instance.
+ */
+
+typedef struct _xmlRef xmlRef;
+typedef xmlRef *xmlRefPtr;
+struct _xmlRef {
+    struct _xmlRef    *next;	/* next Ref */
+    const xmlChar     *value;	/* The Ref name */
+    xmlAttrPtr        attr;	/* The attribut holding it */
+};
+
+/*
+ * A buffer structure
+ */
+
+typedef enum {
+    XML_BUFFER_ALLOC_DOUBLEIT,
+    XML_BUFFER_ALLOC_EXACT
+} xmlBufferAllocationScheme;
+
+typedef struct _xmlBuffer xmlBuffer;
+typedef xmlBuffer *xmlBufferPtr;
+struct _xmlBuffer {
+    xmlChar *content;		/* The buffer content UTF8 */
+    unsigned int use;		/* The buffer size used */
+    unsigned int size;		/* The buffer size */
+    xmlBufferAllocationScheme alloc; /* The realloc method */
+};
+
+/*
+ * A node in an XML tree.
+ */
+typedef struct _xmlNode xmlNode;
+typedef xmlNode *xmlNodePtr;
+struct _xmlNode {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType   type;	/* type number, must be second ! */
+    const xmlChar   *name;      /* the name of the node, or the entity */
+    struct _xmlNode *children;	/* parent->childs link */
+    struct _xmlNode *last;	/* last child link */
+    struct _xmlNode *parent;	/* child->parent link */
+    struct _xmlNode *next;	/* next sibling link  */
+    struct _xmlNode *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* the containing document */
+    xmlNs           *ns;        /* pointer to the associated namespace */
+#ifndef XML_USE_BUFFER_CONTENT    
+    xmlChar         *content;   /* the content */
+#else
+    xmlBufferPtr     content;   /* the content in a buffer */
+#endif
+
+    /* End of common part */
+    struct _xmlAttr *properties;/* properties list */
+    xmlNs           *nsDef;     /* namespace definitions on this node */
+};
+
+/*
+ * An XML document.
+ */
+typedef struct _xmlDoc xmlDoc;
+typedef xmlDoc *xmlDocPtr;
+struct _xmlDoc {
+#ifndef XML_WITHOUT_CORBA
+    void           *_private;	/* for Corba, must be first ! */
+#endif
+    xmlElementType  type;       /* XML_DOCUMENT_NODE, must be second ! */
+    char           *name;	/* name/filename/URI of the document */
+    struct _xmlNode *children;	/* the document tree */
+    struct _xmlNode *last;	/* last child link */
+    struct _xmlNode *parent;	/* child->parent link */
+    struct _xmlNode *next;	/* next sibling link  */
+    struct _xmlNode *prev;	/* previous sibling link  */
+    struct _xmlDoc  *doc;	/* autoreference to itself */
+
+    /* End of common part */
+    int             compression;/* level of zlib compression */
+    int             standalone; /* standalone document (no external refs) */
+    struct _xmlDtd  *intSubset;	/* the document internal subset */
+    struct _xmlDtd  *extSubset;	/* the document external subset */
+    struct _xmlNs   *oldNs;	/* Global namespace, the old way */
+    const xmlChar  *version;	/* the XML version string */
+    const xmlChar  *encoding;   /* external initial encoding, if any */
+    void           *ids;        /* Hash table for ID attributes if any */
+    void           *refs;       /* Hash table for IDREFs attributes if any */
+    const xmlChar  *URL;	/* The URI for that document */
+    int             charset;    /* encoding of the in-memory content
+				   actually an xmlCharEncoding */
+};
+
+/*
+ * Compatibility naming layer with libxml1
+ */
+#ifndef xmlChildrenNode
+#define xmlChildrenNode children
+#define xmlRootNode children
+#endif
+
+/*
+ * Variables.
+ */
+LIBXML_DLL_IMPORT extern xmlNsPtr baseDTD;
+LIBXML_DLL_IMPORT extern int oldXMLWDcompatibility;/* maintain compatibility with old WD */
+LIBXML_DLL_IMPORT extern int xmlIndentTreeOutput;  /* try to indent the tree dumps */
+LIBXML_DLL_IMPORT extern xmlBufferAllocationScheme xmlBufferAllocScheme; /* alloc scheme to use */
+LIBXML_DLL_IMPORT extern int xmlSaveNoEmptyTags;   /* save empty tags as <empty></empty> */
+
+/*
+ * Handling Buffers.
+ */
+
+xmlBufferPtr	xmlBufferCreate		(void);
+xmlBufferPtr	xmlBufferCreateSize	(size_t size);
+void		xmlBufferFree		(xmlBufferPtr buf);
+int		xmlBufferDump		(FILE *file,
+					 xmlBufferPtr buf);
+void		xmlBufferAdd		(xmlBufferPtr buf,
+					 const xmlChar *str,
+					 int len);
+void		xmlBufferAddHead	(xmlBufferPtr buf,
+					 const xmlChar *str,
+					 int len);
+void		xmlBufferCat		(xmlBufferPtr buf,
+					 const xmlChar *str);
+void		xmlBufferCCat		(xmlBufferPtr buf,
+					 const char *str);
+int		xmlBufferShrink		(xmlBufferPtr buf,
+					 unsigned int len);
+int		xmlBufferGrow		(xmlBufferPtr buf,
+					 unsigned int len);
+void		xmlBufferEmpty		(xmlBufferPtr buf);
+const xmlChar*	xmlBufferContent	(const xmlBufferPtr buf);
+int		xmlBufferUse		(const xmlBufferPtr buf);
+void		xmlBufferSetAllocationScheme(xmlBufferPtr buf,
+					 xmlBufferAllocationScheme scheme);
+int		xmlBufferLength		(const xmlBufferPtr buf);
+
+/*
+ * Creating/freeing new structures
+ */
+xmlDtdPtr	xmlCreateIntSubset	(xmlDocPtr doc,
+					 const xmlChar *name,
+					 const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlNewDtd		(xmlDocPtr doc,
+					 const xmlChar *name,
+					 const xmlChar *ExternalID,
+					 const xmlChar *SystemID);
+xmlDtdPtr	xmlGetIntSubset		(xmlDocPtr doc);
+void		xmlFreeDtd		(xmlDtdPtr cur);
+xmlNsPtr	xmlNewGlobalNs		(xmlDocPtr doc,
+					 const xmlChar *href,
+					 const xmlChar *prefix);
+xmlNsPtr	xmlNewNs		(xmlNodePtr node,
+					 const xmlChar *href,
+					 const xmlChar *prefix);
+void		xmlFreeNs		(xmlNsPtr cur);
+xmlDocPtr 	xmlNewDoc		(const xmlChar *version);
+void		xmlFreeDoc		(xmlDocPtr cur);
+xmlAttrPtr	xmlNewDocProp		(xmlDocPtr doc,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlAttrPtr	xmlNewProp		(xmlNodePtr node,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlAttrPtr	xmlNewNsProp		(xmlNodePtr node,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *value);
+void		xmlFreePropList		(xmlAttrPtr cur);
+void		xmlFreeProp		(xmlAttrPtr cur);
+xmlAttrPtr	xmlCopyProp		(xmlNodePtr target,
+					 xmlAttrPtr cur);
+xmlAttrPtr	xmlCopyPropList		(xmlNodePtr target,
+					 xmlAttrPtr cur);
+xmlDtdPtr	xmlCopyDtd		(xmlDtdPtr dtd);
+xmlDocPtr	xmlCopyDoc		(xmlDocPtr doc,
+					 int recursive);
+
+/*
+ * Creating new nodes
+ */
+xmlNodePtr	xmlNewDocNode		(xmlDocPtr doc,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewDocRawNode	(xmlDocPtr doc,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewNode		(xmlNsPtr ns,
+					 const xmlChar *name);
+xmlNodePtr	xmlNewChild		(xmlNodePtr parent,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewTextChild		(xmlNodePtr parent,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewDocText		(xmlDocPtr doc,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewText		(const xmlChar *content);
+xmlNodePtr	xmlNewPI		(const xmlChar *name,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewDocTextLen	(xmlDocPtr doc,
+					 const xmlChar *content,
+					 int len);
+xmlNodePtr	xmlNewTextLen		(const xmlChar *content,
+					 int len);
+xmlNodePtr	xmlNewDocComment	(xmlDocPtr doc,
+					 const xmlChar *content);
+xmlNodePtr	xmlNewComment		(const xmlChar *content);
+xmlNodePtr	xmlNewCDataBlock	(xmlDocPtr doc,
+					 const xmlChar *content,
+					 int len);
+xmlNodePtr	xmlNewCharRef		(xmlDocPtr doc,
+					 const xmlChar *name);
+xmlNodePtr	xmlNewReference		(xmlDocPtr doc,
+					 const xmlChar *name);
+xmlNodePtr	xmlCopyNode		(xmlNodePtr node,
+					 int recursive);
+xmlNodePtr	xmlCopyNodeList		(xmlNodePtr node);
+xmlNodePtr	xmlNewDocFragment	(xmlDocPtr doc);
+
+/*
+ * Navigating
+ */
+xmlNodePtr	xmlDocGetRootElement	(xmlDocPtr doc);
+xmlNodePtr	xmlGetLastChild		(xmlNodePtr parent);
+int		xmlNodeIsText		(xmlNodePtr node);
+int		xmlIsBlankNode		(xmlNodePtr node);
+
+/*
+ * Changing the structure
+ */
+xmlNodePtr	xmlDocSetRootElement	(xmlDocPtr doc,
+					 xmlNodePtr root);
+void		xmlNodeSetName		(xmlNodePtr cur,
+					 const xmlChar *name);
+xmlNodePtr	xmlAddChild		(xmlNodePtr parent,
+					 xmlNodePtr cur);
+xmlNodePtr	xmlAddChildList		(xmlNodePtr parent,
+					 xmlNodePtr cur);
+xmlNodePtr	xmlReplaceNode		(xmlNodePtr old,
+					 xmlNodePtr cur);
+xmlNodePtr	xmlAddSibling		(xmlNodePtr cur,
+					 xmlNodePtr elem);
+xmlNodePtr	xmlAddPrevSibling	(xmlNodePtr cur,
+					 xmlNodePtr elem);
+xmlNodePtr	xmlAddNextSibling	(xmlNodePtr cur,
+					 xmlNodePtr elem);
+void		xmlUnlinkNode		(xmlNodePtr cur);
+xmlNodePtr	xmlTextMerge		(xmlNodePtr first,
+					 xmlNodePtr second);
+void		xmlTextConcat		(xmlNodePtr node,
+					 const xmlChar *content,
+					 int len);
+void		xmlFreeNodeList		(xmlNodePtr cur);
+void		xmlFreeNode		(xmlNodePtr cur);
+void		xmlSetTreeDoc		(xmlNodePtr tree,
+					 xmlDocPtr doc);
+void		xmlSetListDoc		(xmlNodePtr list,
+					 xmlDocPtr doc);
+
+/*
+ * Namespaces
+ */
+xmlNsPtr	xmlSearchNs		(xmlDocPtr doc,
+					 xmlNodePtr node,
+					 const xmlChar *nameSpace);
+xmlNsPtr	xmlSearchNsByHref	(xmlDocPtr doc,
+					 xmlNodePtr node,
+					 const xmlChar *href);
+xmlNsPtr *	xmlGetNsList		(xmlDocPtr doc,
+					 xmlNodePtr node);
+void		xmlSetNs		(xmlNodePtr node,
+					 xmlNsPtr ns);
+xmlNsPtr	xmlCopyNamespace	(xmlNsPtr cur);
+xmlNsPtr	xmlCopyNamespaceList	(xmlNsPtr cur);
+
+/*
+ * Changing the content.
+ */
+xmlAttrPtr	xmlSetProp		(xmlNodePtr node,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlChar *	xmlGetProp		(xmlNodePtr node,
+					 const xmlChar *name);
+xmlAttrPtr	xmlHasProp		(xmlNodePtr node,
+					 const xmlChar *name);
+xmlAttrPtr	xmlSetNsProp		(xmlNodePtr node,
+					 xmlNsPtr ns,
+					 const xmlChar *name,
+					 const xmlChar *value);
+xmlChar *	xmlGetNsProp		(xmlNodePtr node,
+					 const xmlChar *name,
+					 const xmlChar *nameSpace);
+xmlNodePtr	xmlStringGetNodeList	(xmlDocPtr doc,
+					 const xmlChar *value);
+xmlNodePtr	xmlStringLenGetNodeList	(xmlDocPtr doc,
+					 const xmlChar *value,
+					 int len);
+xmlChar *	xmlNodeListGetString	(xmlDocPtr doc,
+					 xmlNodePtr list,
+					 int inLine);
+xmlChar *	xmlNodeListGetRawString	(xmlDocPtr doc,
+					 xmlNodePtr list,
+					 int inLine);
+void		xmlNodeSetContent	(xmlNodePtr cur,
+					 const xmlChar *content);
+void		xmlNodeSetContentLen	(xmlNodePtr cur,
+					 const xmlChar *content,
+					 int len);
+void		xmlNodeAddContent	(xmlNodePtr cur,
+					 const xmlChar *content);
+void		xmlNodeAddContentLen	(xmlNodePtr cur,
+					 const xmlChar *content,
+					 int len);
+xmlChar *	xmlNodeGetContent	(xmlNodePtr cur);
+xmlChar *	xmlNodeGetLang		(xmlNodePtr cur);
+void		xmlNodeSetLang		(xmlNodePtr cur,
+					 const xmlChar *lang);
+int		xmlNodeGetSpacePreserve	(xmlNodePtr cur);
+void		xmlNodeSetSpacePreserve (xmlNodePtr cur, int
+					 val);
+xmlChar *	xmlNodeGetBase		(xmlDocPtr doc,
+					 xmlNodePtr cur);
+void		xmlNodeSetBase		(xmlNodePtr cur,
+					 xmlChar *uri);
+
+/*
+ * Removing content.
+ */
+int		xmlRemoveProp		(xmlAttrPtr attr);
+int		xmlRemoveNode		(xmlNodePtr node); /* TODO */
+
+/*
+ * Internal, don't use
+ */
+#ifdef VMS
+void		xmlBufferWriteXmlCHAR	(xmlBufferPtr buf,
+					 const xmlChar *string);
+#define 	xmlBufferWriteCHAR 	xmlBufferWriteXmlCHAR
+#else
+void		xmlBufferWriteCHAR	(xmlBufferPtr buf,
+					 const xmlChar *string);
+#endif
+void		xmlBufferWriteChar	(xmlBufferPtr buf,
+					 const char *string);
+void		xmlBufferWriteQuotedString(xmlBufferPtr buf,
+					 const xmlChar *string);
+
+/*
+ * Namespace handling
+ */
+int		xmlReconciliateNs	(xmlDocPtr doc,
+					 xmlNodePtr tree);
+
+/*
+ * Saving
+ */
+void		xmlDocDumpFormatMemory	(xmlDocPtr cur,
+					 xmlChar**mem,
+					 int *size,
+					 int format);
+void		xmlDocDumpMemory	(xmlDocPtr cur,
+					 xmlChar**mem,
+					 int *size);
+void		xmlDocDumpMemoryEnc	(xmlDocPtr out_doc,
+					 xmlChar **doc_txt_ptr,
+					 int * doc_txt_len,
+					 const char *txt_encoding);
+void		xmlDocDumpFormatMemoryEnc(xmlDocPtr out_doc,
+					 xmlChar **doc_txt_ptr,
+					 int * doc_txt_len,
+					 const char *txt_encoding,
+					 int format);
+int		xmlDocDump		(FILE *f,
+					 xmlDocPtr cur);
+void		xmlElemDump		(FILE *f,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur);
+int		xmlSaveFile		(const char *filename,
+					 xmlDocPtr cur);
+void		xmlNodeDump		(xmlBufferPtr buf,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur,
+					 int level,
+					 int format);
+
+/* This one is exported from xmlIO.h
+ 
+int		xmlSaveFileTo		(xmlOutputBuffer *buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+ */ 					 
+
+int		xmlSaveFileEnc		(const char *filename,
+					 xmlDocPtr cur,
+					 const char *encoding);
+
+/*
+ * Compression
+ */
+int		xmlGetDocCompressMode	(xmlDocPtr doc);
+void		xmlSetDocCompressMode	(xmlDocPtr doc,
+					 int mode);
+int		xmlGetCompressMode	(void);
+void		xmlSetCompressMode	(int mode);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_TREE_H__ */
+
diff --git a/uri.c b/uri.c
new file mode 100644
index 0000000..31875f7
--- /dev/null
+++ b/uri.c
@@ -0,0 +1,1943 @@
+/**
+ * uri.c: set of generic URI related routines 
+ *
+ * Reference: RFC 2396
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#define INCLUDE_WINSOCK
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <libxml/xmlmemory.h>
+#include <libxml/uri.h>
+#include <libxml/xmlerror.h>
+
+/************************************************************************
+ *									*
+ *		Macros to differenciate various character type		*
+ *			directly extracted from RFC 2396		*
+ *									*
+ ************************************************************************/
+
+/*
+ * alpha    = lowalpha | upalpha
+ */
+#define IS_ALPHA(x) (IS_LOWALPHA(x) || IS_UPALPHA(x))
+
+
+/*
+ * lowalpha = "a" | "b" | "c" | "d" | "e" | "f" | "g" | "h" | "i" | "j" |
+ *            "k" | "l" | "m" | "n" | "o" | "p" | "q" | "r" | "s" | "t" |
+ *            "u" | "v" | "w" | "x" | "y" | "z"
+ */
+
+#define IS_LOWALPHA(x) (((x) >= 'a') && ((x) <= 'z'))
+
+/*
+ * upalpha = "A" | "B" | "C" | "D" | "E" | "F" | "G" | "H" | "I" | "J" |
+ *           "K" | "L" | "M" | "N" | "O" | "P" | "Q" | "R" | "S" | "T" |
+ *           "U" | "V" | "W" | "X" | "Y" | "Z"
+ */
+#define IS_UPALPHA(x) (((x) >= 'A') && ((x) <= 'Z'))
+
+/*
+ * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
+ */
+
+#define IS_DIGIT(x) (((x) >= '0') && ((x) <= '9'))
+
+/*
+ * alphanum = alpha | digit
+ */
+
+#define IS_ALPHANUM(x) (IS_ALPHA(x) || IS_DIGIT(x))
+
+/*
+ * hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
+ *               "a" | "b" | "c" | "d" | "e" | "f"
+ */
+
+#define IS_HEX(x) ((IS_DIGIT(x)) || (((x) >= 'a') && ((x) <= 'f')) || \
+	    (((x) >= 'A') && ((x) <= 'F')))
+
+/*
+ * mark = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+ */
+
+#define IS_MARK(x) (((x) == '-') || ((x) == '_') || ((x) == '.') ||	\
+    ((x) == '!') || ((x) == '~') || ((x) == '*') || ((x) == '\'') ||	\
+    ((x) == '(') || ((x) == ')'))
+
+
+/*
+ * reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","
+ */
+
+#define IS_RESERVED(x) (((x) == ';') || ((x) == '/') || ((x) == '?') ||	\
+        ((x) == ':') || ((x) == '@') || ((x) == '&') || ((x) == '=') ||	\
+	((x) == '+') || ((x) == '$') || ((x) == ','))
+
+/*
+ * unreserved = alphanum | mark
+ */
+
+#define IS_UNRESERVED(x) (IS_ALPHANUM(x) || IS_MARK(x))
+
+/*
+ * escaped = "%" hex hex
+ */
+
+#define IS_ESCAPED(p) ((*(p) == '%') && (IS_HEX((p)[1])) &&		\
+	    (IS_HEX((p)[2])))
+
+/*
+ * uric_no_slash = unreserved | escaped | ";" | "?" | ":" | "@" |
+ *                        "&" | "=" | "+" | "$" | ","
+ */
+#define IS_URIC_NO_SLASH(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||\
+	        ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||\
+	        ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||\
+	        ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
+
+/*
+ * pchar = unreserved | escaped | ":" | "@" | "&" | "=" | "+" | "$" | ","
+ */
+#define IS_PCHAR(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||	\
+	        ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||\
+	        ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||\
+	        ((*(p) == ',')))
+
+/*
+ * rel_segment   = 1*( unreserved | escaped |
+ *                 ";" | "@" | "&" | "=" | "+" | "$" | "," )
+ */
+
+#define IS_SEGMENT(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||	\
+          ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||	\
+	  ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||	\
+	  ((*(p) == ',')))
+
+/*
+ * scheme = alpha *( alpha | digit | "+" | "-" | "." )
+ */
+
+#define IS_SCHEME(x) ((IS_ALPHA(x)) || (IS_DIGIT(x)) ||			\
+	              ((x) == '+') || ((x) == '-') || ((x) == '.'))
+
+/*
+ * reg_name = 1*( unreserved | escaped | "$" | "," |
+ *                ";" | ":" | "@" | "&" | "=" | "+" )
+ */
+
+#define IS_REG_NAME(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||	\
+       ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||		\
+       ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||		\
+       ((*(p) == '=')) || ((*(p) == '+')))
+
+/*
+ * userinfo = *( unreserved | escaped | ";" | ":" | "&" | "=" |
+ *                      "+" | "$" | "," )
+ */
+#define IS_USERINFO(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||	\
+       ((*(p) == ';')) || ((*(p) == ':')) || ((*(p) == '&')) ||		\
+       ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||		\
+       ((*(p) == ',')))
+
+/*
+ * uric = reserved | unreserved | escaped
+ */
+
+#define IS_URIC(p) ((IS_UNRESERVED(*(p))) || (IS_ESCAPED(p)) ||		\
+	            (IS_RESERVED(*(p))))
+
+/*
+ * Skip to next pointer char, handle escaped sequences
+ */
+
+#define NEXT(p) ((*p == '%')? p += 3 : p++)
+
+/*
+ * Productions from the spec.
+ *
+ *    authority     = server | reg_name
+ *    reg_name      = 1*( unreserved | escaped | "$" | "," |
+ *                        ";" | ":" | "@" | "&" | "=" | "+" )
+ *
+ * path          = [ abs_path | opaque_part ]
+ */
+
+/************************************************************************
+ *									*
+ *			Generic URI structure functions			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlCreateURI:
+ *
+ * Simply creates an empty xmlURI
+ *
+ * Returns the new structure or NULL in case of error
+ */
+xmlURIPtr
+xmlCreateURI(void) {
+    xmlURIPtr ret;
+
+    ret = (xmlURIPtr) xmlMalloc(sizeof(xmlURI));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlCreateURI: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlURI));
+    return(ret);
+}
+
+/**
+ * xmlSaveUri:
+ * @uri:  pointer to an xmlURI
+ *
+ * Save the URI as an escaped string
+ *
+ * Returns a new string (to be deallocated by caller)
+ */
+xmlChar *
+xmlSaveUri(xmlURIPtr uri) {
+    xmlChar *ret = NULL;
+    const char *p;
+    int len;
+    int max;
+
+    if (uri == NULL) return(NULL);
+
+
+    max = 80;
+    ret = (xmlChar *) xmlMalloc((max + 1) * sizeof(xmlChar));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlSaveUri: out of memory\n");
+	return(NULL);
+    }
+    len = 0;
+
+    if (uri->scheme != NULL) {
+	p = uri->scheme;
+	while (*p != 0) {
+	    if (len >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    ret[len++] = *p++;
+	}
+	if (len >= max) {
+	    max *= 2;
+	    ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
+	    if (ret == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlSaveUri: out of memory\n");
+		return(NULL);
+	    }
+	}
+	ret[len++] = ':';
+    }
+    if (uri->opaque != NULL) {
+	p = uri->opaque;
+	while (*p != 0) {
+	    if (len + 3 >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    if ((IS_UNRESERVED(*(p))) ||
+	        ((*(p) == ';')) || ((*(p) == '?')) || ((*(p) == ':')) ||
+	        ((*(p) == '@')) || ((*(p) == '&')) || ((*(p) == '=')) ||
+	        ((*(p) == '+')) || ((*(p) == '$')) || ((*(p) == ',')))
+		ret[len++] = *p++;
+	    else {
+		int val = *(unsigned char *)p++;
+		int hi = val / 0x10, lo = val % 0x10;
+		ret[len++] = '%';
+		ret[len++] = hi + (hi > 9? 'A'-10 : '0');
+		ret[len++] = lo + (lo > 9? 'A'-10 : '0');
+	    }
+	}
+	if (len >= max) {
+	    max *= 2;
+	    ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
+	    if (ret == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlSaveUri: out of memory\n");
+		return(NULL);
+	    }
+	}
+	ret[len++] = 0;
+    } else {
+	if (uri->server != NULL) {
+	    if (len + 3 >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    ret[len++] = '/';
+	    ret[len++] = '/';
+	    if (uri->user != NULL) {
+		p = uri->user;
+		while (*p != 0) {
+		    if (len + 3 >= max) {
+			max *= 2;
+			ret = (xmlChar *) xmlRealloc(ret,
+				(max + 1) * sizeof(xmlChar));
+			if (ret == NULL) {
+			    xmlGenericError(xmlGenericErrorContext,
+				    "xmlSaveUri: out of memory\n");
+			    return(NULL);
+			}
+		    }
+		    if ((IS_UNRESERVED(*(p))) ||
+			((*(p) == ';')) || ((*(p) == ':')) ||
+			((*(p) == '&')) || ((*(p) == '=')) ||
+			((*(p) == '+')) || ((*(p) == '$')) ||
+			((*(p) == ',')))
+			ret[len++] = *p++;
+		    else {
+			int val = *(unsigned char *)p++;
+			int hi = val / 0x10, lo = val % 0x10;
+			ret[len++] = '%';
+			ret[len++] = hi + (hi > 9? 'A'-10 : '0');
+			ret[len++] = lo + (lo > 9? 'A'-10 : '0');
+		    }
+		}
+		if (len + 3 >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		ret[len++] = '@';
+	    }
+	    p = uri->server;
+	    while (*p != 0) {
+		if (len >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		ret[len++] = *p++;
+	    }
+	    if (uri->port > 0) {
+		if (len + 10 >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		len += sprintf((char *) &ret[len], ":%d", uri->port);
+	    }
+	} else if (uri->authority != NULL) {
+	    if (len + 3 >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret,
+			(max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    ret[len++] = '/';
+	    ret[len++] = '/';
+	    p = uri->authority;
+	    while (*p != 0) {
+		if (len + 3 >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		if ((IS_UNRESERVED(*(p))) ||
+                    ((*(p) == '$')) || ((*(p) == ',')) || ((*(p) == ';')) ||
+                    ((*(p) == ':')) || ((*(p) == '@')) || ((*(p) == '&')) ||
+                    ((*(p) == '=')) || ((*(p) == '+')))
+		    ret[len++] = *p++;
+		else {
+		    int val = *(unsigned char *)p++;
+		    int hi = val / 0x10, lo = val % 0x10;
+		    ret[len++] = '%';
+		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
+		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
+		}
+	    }
+	} else if (uri->scheme != NULL) {
+	    if (len + 3 >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret,
+			(max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    ret[len++] = '/';
+	    ret[len++] = '/';
+	}
+	if (uri->path != NULL) {
+	    p = uri->path;
+	    while (*p != 0) {
+		if (len + 3 >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		if ((IS_UNRESERVED(*(p))) || ((*(p) == '/')) ||
+                    ((*(p) == ';')) || ((*(p) == '@')) || ((*(p) == '&')) ||
+	            ((*(p) == '=')) || ((*(p) == '+')) || ((*(p) == '$')) ||
+	            ((*(p) == ',')))
+		    ret[len++] = *p++;
+		else {
+		    int val = *(unsigned char *)p++;
+		    int hi = val / 0x10, lo = val % 0x10;
+		    ret[len++] = '%';
+		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
+		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
+		}
+	    }
+	}
+	if (uri->query != NULL) {
+	    if (len + 3 >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret,
+			(max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    ret[len++] = '?';
+	    p = uri->query;
+	    while (*p != 0) {
+		if (len + 3 >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
+		    ret[len++] = *p++;
+		else {
+		    int val = *(unsigned char *)p++;
+		    int hi = val / 0x10, lo = val % 0x10;
+		    ret[len++] = '%';
+		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
+		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
+		}
+	    }
+	}
+	if (uri->fragment != NULL) {
+	    if (len + 3 >= max) {
+		max *= 2;
+		ret = (xmlChar *) xmlRealloc(ret,
+			(max + 1) * sizeof(xmlChar));
+		if (ret == NULL) {
+		    xmlGenericError(xmlGenericErrorContext,
+			    "xmlSaveUri: out of memory\n");
+		    return(NULL);
+		}
+	    }
+	    ret[len++] = '#';
+	    p = uri->fragment;
+	    while (*p != 0) {
+		if (len + 3 >= max) {
+		    max *= 2;
+		    ret = (xmlChar *) xmlRealloc(ret,
+			    (max + 1) * sizeof(xmlChar));
+		    if (ret == NULL) {
+			xmlGenericError(xmlGenericErrorContext,
+				"xmlSaveUri: out of memory\n");
+			return(NULL);
+		    }
+		}
+		if ((IS_UNRESERVED(*(p))) || (IS_RESERVED(*(p)))) 
+		    ret[len++] = *p++;
+		else {
+		    int val = *(unsigned char *)p++;
+		    int hi = val / 0x10, lo = val % 0x10;
+		    ret[len++] = '%';
+		    ret[len++] = hi + (hi > 9? 'A'-10 : '0');
+		    ret[len++] = lo + (lo > 9? 'A'-10 : '0');
+		}
+	    }
+	}
+	if (len >= max) {
+	    max *= 2;
+	    ret = (xmlChar *) xmlRealloc(ret, (max + 1) * sizeof(xmlChar));
+	    if (ret == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlSaveUri: out of memory\n");
+		return(NULL);
+	    }
+	}
+	ret[len++] = 0;
+    }
+    return(ret);
+}
+
+/**
+ * xmlPrintURI:
+ * @stream:  a FILE* for the output
+ * @uri:  pointer to an xmlURI
+ *
+ * Prints the URI in the stream @steam.
+ */
+void
+xmlPrintURI(FILE *stream, xmlURIPtr uri) {
+    xmlChar *out;
+
+    out = xmlSaveUri(uri);
+    if (out != NULL) {
+	fprintf(stream, "%s", out);
+	xmlFree(out);
+    }
+}
+
+/**
+ * xmlCleanURI:
+ * @uri:  pointer to an xmlURI
+ *
+ * Make sure the xmlURI struct is free of content
+ */
+void
+xmlCleanURI(xmlURIPtr uri) {
+    if (uri == NULL) return;
+
+    if (uri->scheme != NULL) xmlFree(uri->scheme);
+    uri->scheme = NULL;
+    if (uri->server != NULL) xmlFree(uri->server);
+    uri->server = NULL;
+    if (uri->user != NULL) xmlFree(uri->user);
+    uri->user = NULL;
+    if (uri->path != NULL) xmlFree(uri->path);
+    uri->path = NULL;
+    if (uri->fragment != NULL) xmlFree(uri->fragment);
+    uri->fragment = NULL;
+    if (uri->opaque != NULL) xmlFree(uri->opaque);
+    uri->opaque = NULL;
+    if (uri->authority != NULL) xmlFree(uri->authority);
+    uri->authority = NULL;
+    if (uri->query != NULL) xmlFree(uri->query);
+    uri->query = NULL;
+}
+
+/**
+ * xmlFreeURI:
+ * @uri:  pointer to an xmlURI
+ *
+ * Free up the xmlURI struct
+ */
+void
+xmlFreeURI(xmlURIPtr uri) {
+    if (uri == NULL) return;
+
+    if (uri->scheme != NULL) xmlFree(uri->scheme);
+    if (uri->server != NULL) xmlFree(uri->server);
+    if (uri->user != NULL) xmlFree(uri->user);
+    if (uri->path != NULL) xmlFree(uri->path);
+    if (uri->fragment != NULL) xmlFree(uri->fragment);
+    if (uri->opaque != NULL) xmlFree(uri->opaque);
+    if (uri->authority != NULL) xmlFree(uri->authority);
+    if (uri->query != NULL) xmlFree(uri->query);
+    memset(uri, -1, sizeof(xmlURI));
+    xmlFree(uri);
+}
+
+/************************************************************************
+ *									*
+ *			Helper functions				*
+ *									*
+ ************************************************************************/
+
+#if 0
+/**
+ * xmlNormalizeURIPath:
+ * @path:  pointer to the path string
+ *
+ * applies the 5 normalization steps to a path string
+ * Normalization occurs directly on the string, no new allocation is done
+ *
+ * Returns 0 or an error code
+ */
+int
+xmlNormalizeURIPath(char *path) {
+    int cur, out;
+
+    if (path == NULL)
+	return(-1);
+    cur = 0;
+    out = 0;
+    while ((path[cur] != 0) && (path[cur] != '/')) cur++;
+    if (path[cur] == 0)
+	return(0);
+
+    /* we are positionned at the beginning of the first segment */
+    cur++;
+    out = cur;
+
+    /*
+     * Analyze each segment in sequence.
+     */
+    while (path[cur] != 0) {
+	/*
+	 * c) All occurrences of "./", where "." is a complete path segment,
+	 *    are removed from the buffer string.
+	 */
+	if ((path[cur] == '.') && (path[cur + 1] == '/')) {
+	    cur += 2;
+	    if (path[cur] == 0) {
+		path[out++] = 0;
+	    }
+	    continue;
+	}
+
+	/*
+	 * d) If the buffer string ends with "." as a complete path segment,
+	 *    that "." is removed.
+	 */
+	if ((path[cur] == '.') && (path[cur + 1] == 0)) {
+	    path[out] = 0;
+	    break;
+	}
+
+	/* read the segment */
+	while ((path[cur] != 0) && (path[cur] != '/')) {
+	    path[out++] = path[cur++];
+	}
+	path[out++] = path[cur];
+	if (path[cur] != 0) {
+	    cur++;
+	}
+    }
+
+    cur = 0;
+    out = 0;
+    while ((path[cur] != 0) && (path[cur] != '/')) cur++;
+    if (path[cur] == 0)
+	return(0);
+    /* we are positionned at the beginning of the first segment */
+    cur++;
+    out = cur;
+    /*
+     * Analyze each segment in sequence.
+     */
+    while (path[cur] != 0) {
+	/*
+	 * e) All occurrences of "<segment>/../", where <segment> is a
+	 *    complete path segment not equal to "..", are removed from the
+	 *    buffer string.  Removal of these path segments is performed
+	 *    iteratively, removing the leftmost matching pattern on each
+	 *    iteration, until no matching pattern remains.
+	 */
+	if ((cur > 1) && (out > 1) &&
+	    (path[cur] == '/') && (path[cur + 1] == '.') &&
+	    (path[cur + 2] == '.') && (path[cur + 3] == '/') &&
+	    ((path[out] != '.') || (path[out - 1] != '.') ||
+	     (path[out - 2] != '/'))) {
+	    cur += 3;
+	    out --;
+	    while ((out > 0) && (path[out] != '/')) { out --; }
+	    path[out] = 0;
+            continue;
+	}
+
+	/*
+	 * f) If the buffer string ends with "<segment>/..", where <segment>
+	 *    is a complete path segment not equal to "..", that
+	 *    "<segment>/.." is removed.
+	 */
+	if ((path[cur] == '/') && (path[cur + 1] == '.') &&
+	    (path[cur + 2] == '.') && (path[cur + 3] == 0) &&
+	    ((path[out] != '.') || (path[out - 1] != '.') ||
+	     (path[out - 2] != '/'))) {
+	    cur += 4;
+	    out --;
+	    while ((out > 0) && (path[out - 1] != '/')) { out --; }
+	    path[out] = 0;
+            continue;
+	}
+        
+	path[out++] = path[cur++]; /* / or 0 */
+    }
+    path[out] = 0;
+
+    /*
+     * g) If the resulting buffer string still begins with one or more
+     *    complete path segments of "..", then the reference is 
+     *    considered to be in error. Implementations may handle this
+     *    error by retaining these components in the resolved path (i.e.,
+     *    treating them as part of the final URI), by removing them from
+     *    the resolved path (i.e., discarding relative levels above the
+     *    root), or by avoiding traversal of the reference.
+     *
+     * We discard them from the final path.
+     */
+    cur = 0;
+    while ((path[cur] == '/') && (path[cur + 1] == '.') &&
+	   (path[cur + 2] == '.'))
+	cur += 3;
+    if (cur != 0) {
+	out = 0;
+	while (path[cur] != 0) path[out++] = path[cur++];
+	path[out] = 0;
+    }
+    return(0);
+}
+#else
+/**
+ * xmlNormalizeURIPath:
+ * @path:  pointer to the path string
+ *
+ * Applies the 5 normalization steps to a path string--that is, RFC 2396
+ * Section 5.2, steps 6.c through 6.g.
+ *
+ * Normalization occurs directly on the string, no new allocation is done
+ *
+ * Returns 0 or an error code
+ */
+int
+xmlNormalizeURIPath(char *path) {
+    char *cur, *out;
+
+    if (path == NULL)
+	return(-1);
+
+    /* Skip all initial "/" chars.  We want to get to the beginning of the
+     * first non-empty segment.
+     */
+    cur = path;
+    while (cur[0] == '/')
+      ++cur;
+    if (cur[0] == '\0')
+      return(0);
+
+    /* Keep everything we've seen so far.  */
+    out = cur;
+
+    /*
+     * Analyze each segment in sequence for cases (c) and (d).
+     */
+    while (cur[0] != '\0') {
+	/*
+	 * c) All occurrences of "./", where "." is a complete path segment,
+	 *    are removed from the buffer string.
+	 */
+	if ((cur[0] == '.') && (cur[1] == '/')) {
+	    cur += 2;
+	    continue;
+	}
+
+	/*
+	 * d) If the buffer string ends with "." as a complete path segment,
+	 *    that "." is removed.
+	 */
+	if ((cur[0] == '.') && (cur[1] == '\0'))
+	    break;
+
+	/* Otherwise keep the segment.  */
+	while (cur[0] != '/') {
+            if (cur[0] == '\0')
+              goto done_cd;
+	    (out++)[0] = (cur++)[0];
+	}
+        (out++)[0] = (cur++)[0];
+    }
+ done_cd:
+    out[0] = '\0';
+
+    /* Reset to the beginning of the first segment for the next sequence.  */
+    cur = path;
+    while (cur[0] == '/')
+      ++cur;
+    if (cur[0] == '\0')
+	return(0);
+
+    /*
+     * Analyze each segment in sequence for cases (e) and (f).
+     *
+     * e) All occurrences of "<segment>/../", where <segment> is a
+     *    complete path segment not equal to "..", are removed from the
+     *    buffer string.  Removal of these path segments is performed
+     *    iteratively, removing the leftmost matching pattern on each
+     *    iteration, until no matching pattern remains.
+     *
+     * f) If the buffer string ends with "<segment>/..", where <segment>
+     *    is a complete path segment not equal to "..", that
+     *    "<segment>/.." is removed.
+     *
+     * To satisfy the "iterative" clause in (e), we need to collapse the
+     * string every time we find something that needs to be removed.  Thus,
+     * we don't need to keep two pointers into the string: we only need a
+     * "current position" pointer.
+     */
+    while (1) {
+        char *segp;
+
+        /* At the beginning of each iteration of this loop, "cur" points to
+         * the first character of the segment we want to examine.
+         */
+
+        /* Find the end of the current segment.  */
+        segp = cur;
+        while ((segp[0] != '/') && (segp[0] != '\0'))
+          ++segp;
+
+        /* If this is the last segment, we're done (we need at least two
+         * segments to meet the criteria for the (e) and (f) cases).
+         */
+        if (segp[0] == '\0')
+          break;
+
+        /* If the first segment is "..", or if the next segment _isn't_ "..",
+         * keep this segment and try the next one.
+         */
+        ++segp;
+        if (((cur[0] == '.') && (cur[1] == '.') && (segp == cur+3))
+            || ((segp[0] != '.') || (segp[1] != '.')
+                || ((segp[2] != '/') && (segp[2] != '\0')))) {
+          cur = segp;
+          continue;
+        }
+
+        /* If we get here, remove this segment and the next one and back up
+         * to the previous segment (if there is one), to implement the
+         * "iteratively" clause.  It's pretty much impossible to back up
+         * while maintaining two pointers into the buffer, so just compact
+         * the whole buffer now.
+         */
+
+        /* If this is the end of the buffer, we're done.  */
+        if (segp[2] == '\0') {
+          cur[0] = '\0';
+          break;
+        }
+        strcpy(cur, segp + 3);
+
+        /* If there are no previous segments, then keep going from here.  */
+        segp = cur;
+        while ((segp > path) && ((--segp)[0] == '/'))
+          ;
+        if (segp == path)
+          continue;
+
+        /* "segp" is pointing to the end of a previous segment; find it's
+         * start.  We need to back up to the previous segment and start
+         * over with that to handle things like "foo/bar/../..".  If we
+         * don't do this, then on the first pass we'll remove the "bar/..",
+         * but be pointing at the second ".." so we won't realize we can also
+         * remove the "foo/..".
+         */
+        cur = segp;
+        while ((cur > path) && (cur[-1] != '/'))
+          --cur;
+    }
+    out[0] = '\0';
+
+    /*
+     * g) If the resulting buffer string still begins with one or more
+     *    complete path segments of "..", then the reference is
+     *    considered to be in error. Implementations may handle this
+     *    error by retaining these components in the resolved path (i.e.,
+     *    treating them as part of the final URI), by removing them from
+     *    the resolved path (i.e., discarding relative levels above the
+     *    root), or by avoiding traversal of the reference.
+     *
+     * We discard them from the final path.
+     */
+    if (path[0] == '/') {
+      cur = path;
+      while ((cur[1] == '.') && (cur[2] == '.')
+             && ((cur[3] == '/') || (cur[3] == '\0')))
+	cur += 3;
+
+      if (cur != path) {
+	out = path;
+	while (cur[0] != '\0')
+          (out++)[0] = (cur++)[0];
+	out[0] = 0;
+      }
+    }
+
+    return(0);
+}
+#endif
+
+/**
+ * xmlURIUnescapeString:
+ * @str:  the string to unescape
+ * @len:   the lenght in bytes to unescape (or <= 0 to indicate full string)
+ * @target:  optionnal destination buffer
+ *
+ * Unescaping routine, does not do validity checks !
+ * Output is direct unsigned char translation of %XX values (no encoding)
+ *
+ * Returns an copy of the string, but unescaped
+ */
+char *
+xmlURIUnescapeString(const char *str, int len, char *target) {
+    char *ret, *out;
+    const char *in;
+
+    if (str == NULL)
+	return(NULL);
+    if (len <= 0) len = strlen(str);
+    if (len <= 0) return(NULL);
+
+    if (target == NULL) {
+	ret = (char *) xmlMalloc(len + 1);
+	if (ret == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlURIUnescapeString: out of memory\n");
+	    return(NULL);
+	}
+    } else
+	ret = target;
+    in = str;
+    out = ret;
+    while(len > 0) {
+	if (*in == '%') {
+	    in++;
+	    if ((*in >= '0') && (*in <= '9')) 
+	        *out = (*in - '0');
+	    else if ((*in >= 'a') && (*in <= 'f'))
+	        *out = (*in - 'a') + 10;
+	    else if ((*in >= 'A') && (*in <= 'F'))
+	        *out = (*in - 'A') + 10;
+	    in++;
+	    if ((*in >= '0') && (*in <= '9')) 
+	        *out = *out * 16 + (*in - '0');
+	    else if ((*in >= 'a') && (*in <= 'f'))
+	        *out = *out * 16 + (*in - 'a') + 10;
+	    else if ((*in >= 'A') && (*in <= 'F'))
+	        *out = *out * 16 + (*in - 'A') + 10;
+	    in++;
+	    len -= 3;
+	    out++;
+	} else {
+	    *out++ = *in++;
+	    len--;
+	}
+    }
+    *out = 0;
+    return(ret);
+}
+
+/**
+ * xmlURIEscape:
+ * @str:  the string of the URI to escape
+ *
+ * Escaping routine, does not do validity checks !
+ * It will try to escape the chars needing this, but this is heuristic
+ * based it's impossible to be sure.
+ *
+ * Returns an copy of the string, but escaped
+ */
+xmlChar *
+xmlURIEscape(const xmlChar *str) {
+    xmlChar *ret;
+    const xmlChar *in;
+    unsigned int len, out;
+
+    if (str == NULL)
+	return(NULL);
+    len = xmlStrlen(str);
+    if (len <= 0) return(NULL);
+
+    len += 20;
+    ret = (xmlChar *) xmlMalloc(len);
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlURIEscape: out of memory\n");
+	return(NULL);
+    }
+    in = (const xmlChar *) str;
+    out = 0;
+    while(*in != 0) {
+	if (len - out <= 3) {
+	    len += 20;
+	    ret = (xmlChar *) xmlRealloc(ret, len);
+	    if (ret == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlURIEscape: out of memory\n");
+		return(NULL);
+	    }
+	}
+	if ((!IS_UNRESERVED(*in)) && (*in != ':') && (*in != '/') &&
+	    (*in != '?') && (*in != '#')) {
+	    unsigned char val;
+	    ret[out++] = '%';
+	    val = *in >> 4;
+	    if (val <= 9)
+		ret[out++] = '0' + val;
+	    else
+		ret[out++] = 'A' + val - 0xA;
+	    val = *in & 0xF;
+	    if (val <= 9)
+		ret[out++] = '0' + val;
+	    else
+		ret[out++] = 'A' + val - 0xA;
+	    in++;
+	} else {
+	    ret[out++] = *in++;
+	}
+    }
+    ret[out] = 0;
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *			Escaped URI parsing				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlParseURIFragment:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an URI fragment string and fills in the appropriate fields
+ * of the @uri structure.
+ * 
+ * fragment = *uric
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIFragment(xmlURIPtr uri, const char **str) {
+    const char *cur = *str;
+
+    if (str == NULL) return(-1);
+
+    while (IS_URIC(cur)) NEXT(cur);
+    if (uri != NULL) {
+	if (uri->fragment != NULL) xmlFree(uri->fragment);
+	uri->fragment = xmlURIUnescapeString(*str, cur - *str, NULL);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIQuery:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse the query part of an URI
+ * 
+ * query = *uric
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIQuery(xmlURIPtr uri, const char **str) {
+    const char *cur = *str;
+
+    if (str == NULL) return(-1);
+
+    while (IS_URIC(cur)) NEXT(cur);
+    if (uri != NULL) {
+	if (uri->query != NULL) xmlFree(uri->query);
+	uri->query = xmlURIUnescapeString(*str, cur - *str, NULL);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIScheme:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an URI scheme
+ * 
+ * scheme = alpha *( alpha | digit | "+" | "-" | "." )
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIScheme(xmlURIPtr uri, const char **str) {
+    const char *cur;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+    if (!IS_ALPHA(*cur))
+	return(2);
+    cur++;
+    while (IS_SCHEME(*cur)) cur++;
+    if (uri != NULL) {
+	if (uri->scheme != NULL) xmlFree(uri->scheme);
+	/* !!! strndup */
+	uri->scheme = xmlURIUnescapeString(*str, cur - *str, NULL);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIOpaquePart:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an URI opaque part
+ * 
+ * opaque_part = uric_no_slash *uric
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIOpaquePart(xmlURIPtr uri, const char **str) {
+    const char *cur;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+    if (!IS_URIC_NO_SLASH(cur)) {
+	return(3);
+    }
+    NEXT(cur);
+    while (IS_URIC(cur)) NEXT(cur);
+    if (uri != NULL) {
+	if (uri->opaque != NULL) xmlFree(uri->opaque);
+	uri->opaque = xmlURIUnescapeString(*str, cur - *str, NULL);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIServer:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse a server subpart of an URI, it's a finer grain analysis
+ * of the authority part.
+ * 
+ * server        = [ [ userinfo "@" ] hostport ]
+ * userinfo      = *( unreserved | escaped |
+ *                       ";" | ":" | "&" | "=" | "+" | "$" | "," )
+ * hostport      = host [ ":" port ]
+ * host          = hostname | IPv4address
+ * hostname      = *( domainlabel "." ) toplabel [ "." ]
+ * domainlabel   = alphanum | alphanum *( alphanum | "-" ) alphanum
+ * toplabel      = alpha | alpha *( alphanum | "-" ) alphanum
+ * IPv4address   = 1*digit "." 1*digit "." 1*digit "." 1*digit
+ * port          = *digit
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIServer(xmlURIPtr uri, const char **str) {
+    const char *cur;
+    const char *host, *tmp;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+
+    /*
+     * is there an userinfo ?
+     */
+    while (IS_USERINFO(cur)) NEXT(cur);
+    if (*cur == '@') {
+	if (uri != NULL) {
+	    if (uri->user != NULL) xmlFree(uri->user);
+	    uri->user = xmlURIUnescapeString(*str, cur - *str, NULL);
+	}
+	cur++;
+    } else {
+	if (uri != NULL) {
+	    if (uri->user != NULL) xmlFree(uri->user);
+	    uri->user = NULL;
+	}
+        cur = *str;
+    }
+    /*
+     * This can be empty in the case where there is no server
+     */
+    host = cur;
+    if (*cur == '/') {
+	if (uri != NULL) {
+	    if (uri->authority != NULL) xmlFree(uri->authority);
+	    uri->authority = NULL;
+	    if (uri->server != NULL) xmlFree(uri->server);
+	    uri->server = NULL;
+	    uri->port = 0;
+	}
+	return(0);
+    }
+    /*
+     * host part of hostport can derive either an IPV4 address
+     * or an unresolved name. Check the IP first, it easier to detect
+     * errors if wrong one
+     */
+    if (IS_DIGIT(*cur)) {
+        while(IS_DIGIT(*cur)) cur++;
+	if (*cur != '.')
+	    goto host_name;
+	cur++;
+	if (!IS_DIGIT(*cur))
+	    goto host_name;
+        while(IS_DIGIT(*cur)) cur++;
+	if (*cur != '.')
+	    goto host_name;
+	cur++;
+	if (!IS_DIGIT(*cur))
+	    goto host_name;
+        while(IS_DIGIT(*cur)) cur++;
+	if (*cur != '.')
+	    goto host_name;
+	cur++;
+	if (!IS_DIGIT(*cur))
+	    goto host_name;
+        while(IS_DIGIT(*cur)) cur++;
+	if (uri != NULL) {
+	    if (uri->authority != NULL) xmlFree(uri->authority);
+	    uri->authority = NULL;
+	    if (uri->server != NULL) xmlFree(uri->server);
+	    uri->server = xmlURIUnescapeString(host, cur - host, NULL);
+	}
+	goto host_done;
+    }
+host_name:
+    /*
+     * the hostname production as-is is a parser nightmare.
+     * simplify it to 
+     * hostname = *( domainlabel "." ) domainlabel [ "." ]
+     * and just make sure the last label starts with a non numeric char.
+     */
+    if (!IS_ALPHANUM(*cur))
+        return(6);
+    while (IS_ALPHANUM(*cur)) {
+        while ((IS_ALPHANUM(*cur)) || (*cur == '-')) cur++;
+	if (*cur == '.')
+	    cur++;
+    }
+    tmp = cur;
+    tmp--;
+    while (IS_ALPHANUM(*tmp) && (*tmp != '.') && (tmp >= host)) tmp--;
+    tmp++;
+    if (!IS_ALPHA(*tmp))
+        return(7);
+    if (uri != NULL) {
+	if (uri->authority != NULL) xmlFree(uri->authority);
+	uri->authority = NULL;
+	if (uri->server != NULL) xmlFree(uri->server);
+	uri->server = xmlURIUnescapeString(host, cur - host, NULL);
+    }
+
+host_done:
+
+    /*
+     * finish by checking for a port presence.
+     */
+    if (*cur == ':') {
+        cur++;
+	if (IS_DIGIT(*cur)) {
+	    if (uri != NULL)
+	        uri->port = 0;
+	    while (IS_DIGIT(*cur)) {
+	        if (uri != NULL)
+		    uri->port = uri->port * 10 + (*cur - '0');
+		cur++;
+	    }
+	}
+    }
+    *str = cur;
+    return(0);
+}	
+
+/**
+ * xmlParseURIRelSegment:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an URI relative segment
+ * 
+ * rel_segment = 1*( unreserved | escaped | ";" | "@" | "&" | "=" |
+ *                          "+" | "$" | "," )
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIRelSegment(xmlURIPtr uri, const char **str) {
+    const char *cur;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+    if (!IS_SEGMENT(cur)) {
+	return(3);
+    }
+    NEXT(cur);
+    while (IS_SEGMENT(cur)) NEXT(cur);
+    if (uri != NULL) {
+	if (uri->path != NULL) xmlFree(uri->path);
+	uri->path = xmlURIUnescapeString(*str, cur - *str, NULL);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIPathSegments:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ * @slash:  should we add a leading slash
+ *
+ * Parse an URI set of path segments
+ * 
+ * path_segments = segment *( "/" segment )
+ * segment       = *pchar *( ";" param )
+ * param         = *pchar
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIPathSegments(xmlURIPtr uri, const char **str, int slash) {
+    const char *cur;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+
+    do {
+	while (IS_PCHAR(cur)) NEXT(cur);
+	if (*cur == ';') {
+	    cur++;
+	    while (IS_PCHAR(cur)) NEXT(cur);
+	}
+	if (*cur != '/') break;
+	cur++;
+    } while (1);
+    if (uri != NULL) {
+	int len, len2 = 0;
+	char *path;
+
+	/*
+	 * Concat the set of path segments to the current path
+	 */
+	len = cur - *str;
+	if (slash)
+	    len++;
+
+	if (uri->path != NULL) {
+	    len2 = strlen(uri->path);
+	    len += len2;
+	}
+        path = (char *) xmlMalloc(len + 1);
+	if (path == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlParseURIPathSegments: out of memory\n");
+	    *str = cur;
+	    return(-1);
+	}
+	if (uri->path != NULL)
+	    memcpy(path, uri->path, len2);
+	if (slash) {
+	    path[len2] = '/';
+	    len2++;
+	}
+	path[len2] = 0;
+	if (cur - *str > 0)
+	    xmlURIUnescapeString(*str, cur - *str, &path[len2]);
+	if (uri->path != NULL)
+	    xmlFree(uri->path);
+	uri->path = path;
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIAuthority:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse the authority part of an URI.
+ * 
+ * authority = server | reg_name
+ * server    = [ [ userinfo "@" ] hostport ]
+ * reg_name  = 1*( unreserved | escaped | "$" | "," | ";" | ":" |
+ *                        "@" | "&" | "=" | "+" )
+ *
+ * Note : this is completely ambiguous since reg_name is allowed to
+ *        use the full set of chars in use by server:
+ *
+ *        3.2.1. Registry-based Naming Authority
+ *
+ *        The structure of a registry-based naming authority is specific
+ *        to the URI scheme, but constrained to the allowed characters
+ *        for an authority component.
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIAuthority(xmlURIPtr uri, const char **str) {
+    const char *cur;
+    int ret;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+
+    /*
+     * try first to parse it as a server string.
+     */
+    ret = xmlParseURIServer(uri, str);
+    if (ret == 0)
+        return(0);
+
+    /*
+     * failed, fallback to reg_name
+     */
+    if (!IS_REG_NAME(cur)) {
+	return(5);
+    }
+    NEXT(cur);
+    while (IS_REG_NAME(cur)) NEXT(cur);
+    if (uri != NULL) {
+	if (uri->server != NULL) xmlFree(uri->server);
+	uri->server = NULL;
+	if (uri->user != NULL) xmlFree(uri->user);
+	uri->user = NULL;
+	if (uri->authority != NULL) xmlFree(uri->authority);
+	uri->authority = xmlURIUnescapeString(*str, cur - *str, NULL);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseURIHierPart:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an URI hirarchical part
+ * 
+ * hier_part = ( net_path | abs_path ) [ "?" query ]
+ * abs_path = "/"  path_segments
+ * net_path = "//" authority [ abs_path ]
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIHierPart(xmlURIPtr uri, const char **str) {
+    int ret;
+    const char *cur;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+
+    if ((cur[0] == '/') && (cur[1] == '/')) {
+	cur += 2;
+	ret = xmlParseURIAuthority(uri, &cur);
+	if (ret != 0)
+	    return(ret);
+	if (cur[0] == '/') {
+	    cur++;
+	    ret = xmlParseURIPathSegments(uri, &cur, 1);
+	}
+    } else if (cur[0] == '/') {
+	cur++;
+	ret = xmlParseURIPathSegments(uri, &cur, 1);
+    } else {
+	return(4);
+    }
+    if (ret != 0)
+	return(ret);
+    if (*cur == '?') {
+	cur++;
+	ret = xmlParseURIQuery(uri, &cur);
+	if (ret != 0)
+	    return(ret);
+    }
+    *str = cur;
+    return(0);
+}
+
+/**
+ * xmlParseAbsoluteURI:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an URI reference string and fills in the appropriate fields
+ * of the @uri structure
+ * 
+ * absoluteURI   = scheme ":" ( hier_part | opaque_part )
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseAbsoluteURI(xmlURIPtr uri, const char **str) {
+    int ret;
+
+    if (str == NULL)
+	return(-1);
+    
+    ret = xmlParseURIScheme(uri, str);
+    if (ret != 0) return(ret);
+    if (**str != ':')
+	return(1);
+    (*str)++;
+    if (**str == '/')
+	return(xmlParseURIHierPart(uri, str));
+    return(xmlParseURIOpaquePart(uri, str));
+}
+
+/**
+ * xmlParseRelativeURI:
+ * @uri:  pointer to an URI structure
+ * @str:  pointer to the string to analyze
+ *
+ * Parse an relative URI string and fills in the appropriate fields
+ * of the @uri structure
+ * 
+ * relativeURI = ( net_path | abs_path | rel_path ) [ "?" query ]
+ * abs_path = "/"  path_segments
+ * net_path = "//" authority [ abs_path ]
+ * rel_path = rel_segment [ abs_path ]
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseRelativeURI(xmlURIPtr uri, const char **str) {
+    int ret = 0;
+    const char *cur;
+
+    if (str == NULL)
+	return(-1);
+    
+    cur = *str;
+    if ((cur[0] == '/') && (cur[1] == '/')) {
+	cur += 2;
+	ret = xmlParseURIAuthority(uri, &cur);
+	if (ret != 0)
+	    return(ret);
+	if (cur[0] == '/') {
+	    cur++;
+	    ret = xmlParseURIPathSegments(uri, &cur, 1);
+	}
+    } else if (cur[0] == '/') {
+	cur++;
+	ret = xmlParseURIPathSegments(uri, &cur, 1);
+    } else if (cur[0] != '#' && cur[0] != '?') {
+	ret = xmlParseURIRelSegment(uri, &cur);
+	if (ret != 0)
+	    return(ret);
+	if (cur[0] == '/') {
+	    cur++;
+	    ret = xmlParseURIPathSegments(uri, &cur, 1);
+	}
+    }
+    if (ret != 0)
+	return(ret);
+    if (*cur == '?') {
+	cur++;
+	ret = xmlParseURIQuery(uri, &cur);
+	if (ret != 0)
+	    return(ret);
+    }
+    *str = cur;
+    return(ret);
+}
+
+/**
+ * xmlParseURIReference:
+ * @uri:  pointer to an URI structure
+ * @str:  the string to analyze
+ *
+ * Parse an URI reference string and fills in the appropriate fields
+ * of the @uri structure
+ * 
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ *
+ * Returns 0 or the error code
+ */
+int
+xmlParseURIReference(xmlURIPtr uri, const char *str) {
+    int ret;
+    const char *tmp = str;
+
+    if (str == NULL)
+	return(-1);
+    xmlCleanURI(uri);
+
+    /*
+     * Try first to parse aboslute refs, then fallback to relative if
+     * it fails.
+     */
+    ret = xmlParseAbsoluteURI(uri, &str);
+    if (ret != 0) {
+	xmlCleanURI(uri);
+	str = tmp;
+        ret = xmlParseRelativeURI(uri, &str);
+    }
+    if (ret != 0) {
+	xmlCleanURI(uri);
+	return(ret);
+    }
+
+    if (*str == '#') {
+	str++;
+	ret = xmlParseURIFragment(uri, &str);
+	if (ret != 0) return(ret);
+    }
+    if (*str != 0) {
+	xmlCleanURI(uri);
+	return(1);
+    }
+    return(0);
+}
+
+/**
+ * xmlParseURI:
+ * @str:  the URI string to analyze
+ *
+ * Parse an URI 
+ * 
+ * URI-reference = [ absoluteURI | relativeURI ] [ "#" fragment ]
+ *
+ * Returns a newly build xmlURIPtr or NULL in case of error
+ */
+xmlURIPtr
+xmlParseURI(const char *str) {
+    xmlURIPtr uri;
+    int ret;
+
+    if (str == NULL)
+	return(NULL);
+    uri = xmlCreateURI();
+    if (uri != NULL) {
+	ret = xmlParseURIReference(uri, str);
+        if (ret) {
+	    xmlFreeURI(uri);
+	    return(NULL);
+	}
+    }
+    return(uri);
+}
+
+/************************************************************************
+ *									*
+ *			Public functions				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlBuildURI:
+ * @URI:  the URI instance found in the document
+ * @base:  the base value
+ *
+ * Computes he final URI of the reference done by checking that
+ * the given URI is valid, and building the final URI using the
+ * base URI. This is processed according to section 5.2 of the 
+ * RFC 2396
+ *
+ * 5.2. Resolving Relative References to Absolute Form
+ *
+ * Returns a new URI string (to be freed by the caller) or NULL in case
+ *         of error.
+ */
+xmlChar *
+xmlBuildURI(const xmlChar *URI, const xmlChar *base) {
+    xmlChar *val = NULL;
+    int ret, len, index, cur, out;
+    xmlURIPtr ref = NULL;
+    xmlURIPtr bas = NULL;
+    xmlURIPtr res = NULL;
+
+    /*
+     * 1) The URI reference is parsed into the potential four components and
+     *    fragment identifier, as described in Section 4.3.
+     *
+     *    NOTE that a completely empty URI is treated by modern browsers
+     *    as a reference to "." rather than as a synonym for the current
+     *    URI.  Should we do that here?
+     */
+    if (URI == NULL) 
+	ret = -1;
+    else {
+	if (*URI) {
+	    ref = xmlCreateURI();
+	    if (ref == NULL)
+		goto done;
+	    ret = xmlParseURIReference(ref, (const char *) URI);
+	}
+	else
+	    ret = 0;
+    }
+    if (ret != 0)
+	goto done;
+    if (base == NULL)
+	ret = -1;
+    else {
+	bas = xmlCreateURI();
+	if (bas == NULL)
+	    goto done;
+	ret = xmlParseURIReference(bas, (const char *) base);
+    }
+    if (ret != 0) {
+	if (ref)
+	    val = xmlSaveUri(ref);
+	goto done;
+    }
+    if (ref == NULL) {
+	/*
+	 * the base fragment must be ignored
+	 */
+	if (bas->fragment != NULL) {
+	    xmlFree(bas->fragment);
+	    bas->fragment = NULL;
+	}
+	val = xmlSaveUri(bas);
+	goto done;
+    }
+
+    /*
+     * 2) If the path component is empty and the scheme, authority, and
+     *    query components are undefined, then it is a reference to the
+     *    current document and we are done.  Otherwise, the reference URI's
+     *    query and fragment components are defined as found (or not found)
+     *    within the URI reference and not inherited from the base URI.
+     *
+     *    NOTE that in modern browsers, the parsing differs from the above
+     *    in the following aspect:  the query component is allowed to be
+     *    defined while still treating this as a reference to the current
+     *    document.
+     */
+    res = xmlCreateURI();
+    if (res == NULL)
+	goto done;
+    if ((ref->scheme == NULL) && (ref->path == NULL) &&
+	((ref->authority == NULL) && (ref->server == NULL))) {
+	if (bas->scheme != NULL)
+	    res->scheme = xmlMemStrdup(bas->scheme);
+	if (bas->authority != NULL)
+	    res->authority = xmlMemStrdup(bas->authority);
+	else if (bas->server != NULL) {
+	    res->server = xmlMemStrdup(bas->server);
+	    if (bas->user != NULL)
+		res->user = xmlMemStrdup(bas->user);
+	    res->port = bas->port;		
+	}
+	if (bas->path != NULL)
+	    res->path = xmlMemStrdup(bas->path);
+	if (ref->query != NULL)
+	    res->query = xmlMemStrdup(ref->query);
+	else if (bas->query != NULL)
+	    res->query = xmlMemStrdup(bas->query);
+	if (ref->fragment != NULL)
+	    res->fragment = xmlMemStrdup(ref->fragment);
+	goto step_7;
+    }
+ 
+    if (ref->query != NULL)
+	res->query = xmlMemStrdup(ref->query);
+    if (ref->fragment != NULL)
+	res->fragment = xmlMemStrdup(ref->fragment);
+
+    /*
+     * 3) If the scheme component is defined, indicating that the reference
+     *    starts with a scheme name, then the reference is interpreted as an
+     *    absolute URI and we are done.  Otherwise, the reference URI's
+     *    scheme is inherited from the base URI's scheme component.
+     */
+    if (ref->scheme != NULL) {
+	val = xmlSaveUri(ref);
+	goto done;
+    }
+    if (bas->scheme != NULL)
+	res->scheme = xmlMemStrdup(bas->scheme);
+
+    /*
+     * 4) If the authority component is defined, then the reference is a
+     *    network-path and we skip to step 7.  Otherwise, the reference
+     *    URI's authority is inherited from the base URI's authority
+     *    component, which will also be undefined if the URI scheme does not
+     *    use an authority component.
+     */
+    if ((ref->authority != NULL) || (ref->server != NULL)) {
+	if (ref->authority != NULL)
+	    res->authority = xmlMemStrdup(ref->authority);
+	else {
+	    res->server = xmlMemStrdup(ref->server);
+	    if (ref->user != NULL)
+		res->user = xmlMemStrdup(ref->user);
+            res->port = ref->port;		
+	}
+	if (ref->path != NULL)
+	    res->path = xmlMemStrdup(ref->path);
+	goto step_7;
+    }
+    if (bas->authority != NULL)
+	res->authority = xmlMemStrdup(bas->authority);
+    else if (bas->server != NULL) {
+	res->server = xmlMemStrdup(bas->server);
+	if (bas->user != NULL)
+	    res->user = xmlMemStrdup(bas->user);
+	res->port = bas->port;		
+    }
+
+    /*
+     * 5) If the path component begins with a slash character ("/"), then
+     *    the reference is an absolute-path and we skip to step 7.
+     */
+    if ((ref->path != NULL) && (ref->path[0] == '/')) {
+	res->path = xmlMemStrdup(ref->path);
+	goto step_7;
+    }
+
+
+    /*
+     * 6) If this step is reached, then we are resolving a relative-path
+     *    reference.  The relative path needs to be merged with the base
+     *    URI's path.  Although there are many ways to do this, we will
+     *    describe a simple method using a separate string buffer.
+     *
+     * Allocate a buffer large enough for the result string.
+     */
+    len = 2; /* extra / and 0 */
+    if (ref->path != NULL)
+	len += strlen(ref->path);
+    if (bas->path != NULL)
+	len += strlen(bas->path);
+    res->path = (char *) xmlMalloc(len);
+    if (res->path == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlBuildURI: out of memory\n");
+	goto done;
+    }
+    res->path[0] = 0;
+
+    /*
+     * a) All but the last segment of the base URI's path component is
+     *    copied to the buffer.  In other words, any characters after the
+     *    last (right-most) slash character, if any, are excluded.
+     */
+    cur = 0;
+    out = 0;
+    if (bas->path != NULL) {
+	while (bas->path[cur] != 0) {
+	    while ((bas->path[cur] != 0) && (bas->path[cur] != '/'))
+		cur++;
+	    if (bas->path[cur] == 0)
+		break;
+
+	    cur++;
+	    while (out < cur) {
+		res->path[out] = bas->path[out];
+		out++;
+	    }
+	}
+    }
+    res->path[out] = 0;
+
+    /*
+     * b) The reference's path component is appended to the buffer
+     *    string.
+     */
+    if (ref->path != NULL && ref->path[0] != 0) {
+	index = 0;
+	/*
+	 * Ensure the path includes a '/'
+	 */
+	if ((out == 0) && (bas->server != NULL))
+	    res->path[out++] = '/';
+	while (ref->path[index] != 0) {
+	    res->path[out++] = ref->path[index++];
+	}
+    }
+    res->path[out] = 0;
+
+    /*
+     * Steps c) to h) are really path normalization steps
+     */
+    xmlNormalizeURIPath(res->path);
+
+step_7:
+
+    /*
+     * 7) The resulting URI components, including any inherited from the
+     *    base URI, are recombined to give the absolute form of the URI
+     *    reference.
+     */
+    val = xmlSaveUri(res);
+
+done:
+    if (ref != NULL)
+	xmlFreeURI(ref);
+    if (bas != NULL)
+	xmlFreeURI(bas);
+    if (res != NULL)
+	xmlFreeURI(res);
+    return(val);
+}
+
+
diff --git a/uri.h b/uri.h
new file mode 100644
index 0000000..e7aeda4
--- /dev/null
+++ b/uri.h
@@ -0,0 +1,61 @@
+/**
+ * uri.c: library of generic URI related routines 
+ *
+ * Reference: RFC 2396
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_URI_H__
+#define __XML_URI_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *
+ */
+typedef struct _xmlURI xmlURI;
+typedef xmlURI *xmlURIPtr;
+struct _xmlURI {
+    char *scheme;
+    char *opaque;
+    char *authority;
+    char *server;
+    char *user;
+    int port;
+    char *path;
+    char *query;
+    char *fragment;
+};
+
+/*
+ * This function is in tree.h:
+ * xmlChar *	xmlNodeGetBase	(xmlDocPtr doc,
+ *                               xmlNodePtr cur);
+ */
+xmlURIPtr	xmlCreateURI		(void);
+xmlChar *	xmlBuildURI		(const xmlChar *URI,
+	                        	 const xmlChar *base);
+xmlURIPtr	xmlParseURI		(const char *URI);
+int		xmlParseURIReference	(xmlURIPtr uri,
+					 const char *str);
+xmlChar *	xmlSaveUri		(xmlURIPtr uri);
+void		xmlPrintURI		(FILE *stream,
+					 xmlURIPtr uri);
+char *		xmlURIUnescapeString	(const char *str,
+					 int len,
+					 char *target);
+int		xmlNormalizeURIPath	(char *path);
+xmlChar *	xmlURIEscape		(const xmlChar *str);
+void		xmlFreeURI		(xmlURIPtr uri);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_URI_H__ */
diff --git a/valid.c b/valid.c
new file mode 100644
index 0000000..1b7e6f6
--- /dev/null
+++ b/valid.c
@@ -0,0 +1,4098 @@
+/*
+ * valid.c : part of the code use to do the DTD handling and the validity
+ *           checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/hash.h>
+#include <libxml/valid.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xmlerror.h>
+#include <libxml/list.h>
+
+/*
+ * Generic function for accessing stacks in the Validity Context
+ */
+
+#define PUSH_AND_POP(scope, type, name)					\
+scope int name##VPush(xmlValidCtxtPtr ctxt, type value) {		\
+    if (ctxt->name##Nr >= ctxt->name##Max) {				\
+	ctxt->name##Max *= 2;						\
+        ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,		\
+	             ctxt->name##Max * sizeof(ctxt->name##Tab[0]));	\
+        if (ctxt->name##Tab == NULL) {					\
+	    xmlGenericError(xmlGenericErrorContext,			\
+		    "realloc failed !\n");				\
+	    return(0);							\
+	}								\
+    }									\
+    ctxt->name##Tab[ctxt->name##Nr] = value;				\
+    ctxt->name = value;							\
+    return(ctxt->name##Nr++);						\
+}									\
+scope type name##VPop(xmlValidCtxtPtr ctxt) {				\
+    type ret;								\
+    if (ctxt->name##Nr <= 0) return(0);					\
+    ctxt->name##Nr--;							\
+    if (ctxt->name##Nr > 0)						\
+	ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];		\
+    else								\
+        ctxt->name = NULL;						\
+    ret = ctxt->name##Tab[ctxt->name##Nr];				\
+    ctxt->name##Tab[ctxt->name##Nr] = 0;				\
+    return(ret);							\
+}									\
+
+PUSH_AND_POP(static, xmlNodePtr, node)
+
+/* #define DEBUG_VALID_ALGO */
+
+#ifdef DEBUG_VALID_ALGO
+void xmlValidPrintNodeList(xmlNodePtr cur) {
+    if (cur == NULL)
+	xmlGenericError(xmlGenericErrorContext, "null ");
+    while (cur != NULL) {
+	switch (cur->type) {
+	    case XML_ELEMENT_NODE:
+		xmlGenericError(xmlGenericErrorContext, "%s ", cur->name);
+		break;
+	    case XML_TEXT_NODE:
+		xmlGenericError(xmlGenericErrorContext, "text ");
+		break;
+	    case XML_CDATA_SECTION_NODE:
+		xmlGenericError(xmlGenericErrorContext, "cdata ");
+		break;
+	    case XML_ENTITY_REF_NODE:
+		xmlGenericError(xmlGenericErrorContext, "&%s; ", cur->name);
+		break;
+	    case XML_PI_NODE:
+		xmlGenericError(xmlGenericErrorContext, "pi(%s) ", cur->name);
+		break;
+	    case XML_COMMENT_NODE:
+		xmlGenericError(xmlGenericErrorContext, "comment ");
+		break;
+	    case XML_ATTRIBUTE_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?attr? ");
+		break;
+	    case XML_ENTITY_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?ent? ");
+		break;
+	    case XML_DOCUMENT_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?doc? ");
+		break;
+	    case XML_DOCUMENT_TYPE_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?doctype? ");
+		break;
+	    case XML_DOCUMENT_FRAG_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?frag? ");
+		break;
+	    case XML_NOTATION_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?nota? ");
+		break;
+	    case XML_HTML_DOCUMENT_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?html? ");
+		break;
+	    case XML_DTD_NODE:
+		xmlGenericError(xmlGenericErrorContext, "?dtd? ");
+		break;
+	    case XML_ELEMENT_DECL:
+		xmlGenericError(xmlGenericErrorContext, "?edecl? ");
+		break;
+	    case XML_ATTRIBUTE_DECL:
+		xmlGenericError(xmlGenericErrorContext, "?adecl? ");
+		break;
+	    case XML_ENTITY_DECL:
+		xmlGenericError(xmlGenericErrorContext, "?entdecl? ");
+		break;
+	}
+	cur = cur->next;
+    }
+}
+
+void xmlValidDebug(xmlNodePtr cur, xmlElementContentPtr cont) {
+    char expr[1000];
+
+    expr[0] = 0;
+    xmlGenericError(xmlGenericErrorContext, "valid: ");
+    xmlValidPrintNodeList(cur);
+    xmlGenericError(xmlGenericErrorContext, "against ");
+    xmlSprintfElementContent(expr, cont, 0);
+    xmlGenericError(xmlGenericErrorContext, "%s\n", expr);
+}
+
+#define DEBUG_VALID_STATE(n,c) xmlValidDebug(n,c);
+#else
+#define DEBUG_VALID_STATE(n,c)
+#endif
+
+/* TODO: use hash table for accesses to elem and attribute dedinitions */
+
+#define VERROR							\
+   if ((ctxt != NULL) && (ctxt->error != NULL)) ctxt->error
+
+#define VWARNING						\
+   if ((ctxt != NULL) && (ctxt->warning != NULL)) ctxt->warning
+
+#define CHECK_DTD						\
+   if (doc == NULL) return(0);					\
+   else if ((doc->intSubset == NULL) &&				\
+	    (doc->extSubset == NULL)) return(0)
+
+xmlElementPtr xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name);
+xmlAttributePtr xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem);
+
+/************************************************************************
+ *									*
+ *			QName handling helper				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlSplitQName2:
+ * @name:  an XML parser context
+ * @prefix:  a xmlChar ** 
+ *
+ * parse an XML qualified name string
+ *
+ * [NS 5] QName ::= (Prefix ':')? LocalPart
+ *
+ * [NS 6] Prefix ::= NCName
+ *
+ * [NS 7] LocalPart ::= NCName
+ *
+ * Returns NULL if not a QName, otherwise the local part, and prefix
+ *   is updated to get the Prefix if any.
+ */
+
+xmlChar *
+xmlSplitQName2(const xmlChar *name, xmlChar **prefix) {
+    int len = 0;
+    xmlChar *ret = NULL;
+
+    *prefix = NULL;
+
+    /* xml: prefix is not really a namespace */
+    if ((name[0] == 'x') && (name[1] == 'm') &&
+        (name[2] == 'l') && (name[3] == ':'))
+	return(NULL);
+
+    /* nasty but valid */
+    if (name[0] == ':')
+	return(NULL);
+
+    /*
+     * we are not trying to validate but just to cut, and yes it will
+     * work even if this is as set of UTF-8 encoded chars
+     */
+    while ((name[len] != 0) && (name[len] != ':')) 
+	len++;
+    
+    if (name[len] == 0)
+	return(NULL);
+
+    *prefix = xmlStrndup(name, len);
+    ret = xmlStrdup(&name[len + 1]);
+
+    return(ret);
+}
+
+/****************************************************************
+ *								*
+ *	Util functions for data allocation/deallocation		*
+ *								*
+ ****************************************************************/
+
+/**
+ * xmlNewElementContent:
+ * @name:  the subelement name or NULL
+ * @type:  the type of element content decl
+ *
+ * Allocate an element content structure.
+ *
+ * Returns NULL if not, othervise the new element content structure
+ */
+xmlElementContentPtr
+xmlNewElementContent(xmlChar *name, xmlElementContentType type) {
+    xmlElementContentPtr ret;
+
+    switch(type) {
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    if (name == NULL) {
+	        xmlGenericError(xmlGenericErrorContext,
+			"xmlNewElementContent : name == NULL !\n");
+	    }
+	    break;
+        case XML_ELEMENT_CONTENT_PCDATA:
+	case XML_ELEMENT_CONTENT_SEQ:
+	case XML_ELEMENT_CONTENT_OR:
+	    if (name != NULL) {
+	        xmlGenericError(xmlGenericErrorContext,
+			"xmlNewElementContent : name != NULL !\n");
+	    }
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlNewElementContent: unknown type %d\n", type);
+	    return(NULL);
+    }
+    ret = (xmlElementContentPtr) xmlMalloc(sizeof(xmlElementContent));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlNewElementContent : out of memory!\n");
+	return(NULL);
+    }
+    ret->type = type;
+    ret->ocur = XML_ELEMENT_CONTENT_ONCE;
+    if (name != NULL)
+        ret->name = xmlStrdup(name);
+    else
+        ret->name = NULL;
+    ret->c1 = ret->c2 = NULL;
+    return(ret);
+}
+
+/**
+ * xmlCopyElementContent:
+ * @content:  An element content pointer.
+ *
+ * Build a copy of an element content description.
+ * 
+ * Returns the new xmlElementContentPtr or NULL in case of error.
+ */
+xmlElementContentPtr
+xmlCopyElementContent(xmlElementContentPtr cur) {
+    xmlElementContentPtr ret;
+
+    if (cur == NULL) return(NULL);
+    ret = xmlNewElementContent((xmlChar *) cur->name, cur->type);
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlCopyElementContent : out of memory\n");
+	return(NULL);
+    }
+    ret->ocur = cur->ocur;
+    if (cur->c1 != NULL) ret->c1 = xmlCopyElementContent(cur->c1);
+    if (cur->c2 != NULL) ret->c2 = xmlCopyElementContent(cur->c2);
+    return(ret);
+}
+
+/**
+ * xmlFreeElementContent:
+ * @cur:  the element content tree to free
+ *
+ * Free an element content structure. This is a recursive call !
+ */
+void
+xmlFreeElementContent(xmlElementContentPtr cur) {
+    if (cur == NULL) return;
+    switch (cur->type) {
+	case XML_ELEMENT_CONTENT_PCDATA:
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	case XML_ELEMENT_CONTENT_SEQ:
+	case XML_ELEMENT_CONTENT_OR:
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlFreeElementContent : type %d\n", cur->type);
+	    return;
+    }
+    if (cur->c1 != NULL) xmlFreeElementContent(cur->c1);
+    if (cur->c2 != NULL) xmlFreeElementContent(cur->c2);
+    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
+    memset(cur, -1, sizeof(xmlElementContent));
+    xmlFree(cur);
+}
+
+/**
+ * xmlDumpElementContent:
+ * @buf:  An XML buffer
+ * @content:  An element table
+ * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
+ *
+ * This will dump the content of the element table as an XML DTD definition
+ */
+void
+xmlDumpElementContent(xmlBufferPtr buf, xmlElementContentPtr content, int glob) {
+    if (content == NULL) return;
+
+    if (glob) xmlBufferWriteChar(buf, "(");
+    switch (content->type) {
+        case XML_ELEMENT_CONTENT_PCDATA:
+            xmlBufferWriteChar(buf, "#PCDATA");
+	    break;
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    xmlBufferWriteCHAR(buf, content->name);
+	    break;
+	case XML_ELEMENT_CONTENT_SEQ:
+	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
+	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
+		xmlDumpElementContent(buf, content->c1, 1);
+	    else
+		xmlDumpElementContent(buf, content->c1, 0);
+            xmlBufferWriteChar(buf, " , ");
+	    if (content->c2->type == XML_ELEMENT_CONTENT_OR)
+		xmlDumpElementContent(buf, content->c2, 1);
+	    else
+		xmlDumpElementContent(buf, content->c2, 0);
+	    break;
+	case XML_ELEMENT_CONTENT_OR:
+	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
+	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
+		xmlDumpElementContent(buf, content->c1, 1);
+	    else
+		xmlDumpElementContent(buf, content->c1, 0);
+            xmlBufferWriteChar(buf, " | ");
+	    if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
+		xmlDumpElementContent(buf, content->c2, 1);
+	    else
+		xmlDumpElementContent(buf, content->c2, 0);
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlDumpElementContent: unknown type %d\n",
+	            content->type);
+    }
+    if (glob)
+        xmlBufferWriteChar(buf, ")");
+    switch (content->ocur) {
+        case XML_ELEMENT_CONTENT_ONCE:
+	    break;
+        case XML_ELEMENT_CONTENT_OPT:
+	    xmlBufferWriteChar(buf, "?");
+	    break;
+        case XML_ELEMENT_CONTENT_MULT:
+	    xmlBufferWriteChar(buf, "*");
+	    break;
+        case XML_ELEMENT_CONTENT_PLUS:
+	    xmlBufferWriteChar(buf, "+");
+	    break;
+    }
+}
+
+/**
+ * xmlSprintfElementContent:
+ * @buf:  an output buffer
+ * @content:  An element table
+ * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
+ *
+ * This will dump the content of the element content definition
+ * Intended just for the debug routine
+ */
+void
+xmlSprintfElementContent(char *buf, xmlElementContentPtr content, int glob) {
+    if (content == NULL) return;
+    if (glob) strcat(buf, "(");
+    switch (content->type) {
+        case XML_ELEMENT_CONTENT_PCDATA:
+            strcat(buf, "#PCDATA");
+	    break;
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    strcat(buf, (char *) content->name);
+	    break;
+	case XML_ELEMENT_CONTENT_SEQ:
+	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
+	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
+		xmlSprintfElementContent(buf, content->c1, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c1, 0);
+            strcat(buf, " , ");
+	    if (content->c2->type == XML_ELEMENT_CONTENT_OR)
+		xmlSprintfElementContent(buf, content->c2, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c2, 0);
+	    break;
+	case XML_ELEMENT_CONTENT_OR:
+	    if ((content->c1->type == XML_ELEMENT_CONTENT_OR) ||
+	        (content->c1->type == XML_ELEMENT_CONTENT_SEQ))
+		xmlSprintfElementContent(buf, content->c1, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c1, 0);
+            strcat(buf, " | ");
+	    if (content->c2->type == XML_ELEMENT_CONTENT_SEQ)
+		xmlSprintfElementContent(buf, content->c2, 1);
+	    else
+		xmlSprintfElementContent(buf, content->c2, 0);
+	    break;
+    }
+    if (glob)
+        strcat(buf, ")");
+    switch (content->ocur) {
+        case XML_ELEMENT_CONTENT_ONCE:
+	    break;
+        case XML_ELEMENT_CONTENT_OPT:
+	    strcat(buf, "?");
+	    break;
+        case XML_ELEMENT_CONTENT_MULT:
+	    strcat(buf, "*");
+	    break;
+        case XML_ELEMENT_CONTENT_PLUS:
+	    strcat(buf, "+");
+	    break;
+    }
+}
+
+/****************************************************************
+ *								*
+ *	Registration of DTD declarations			*
+ *								*
+ ****************************************************************/
+
+/**
+ * xmlCreateElementTable:
+ *
+ * create and initialize an empty element hash table.
+ *
+ * Returns the xmlElementTablePtr just created or NULL in case of error.
+ */
+xmlElementTablePtr
+xmlCreateElementTable(void) {
+    return(xmlHashCreate(0));
+}
+
+/**
+ * xmlFreeElement:
+ * @elem:  An element
+ *
+ * Deallocate the memory used by an element definition
+ */
+void
+xmlFreeElement(xmlElementPtr elem) {
+    if (elem == NULL) return;
+    xmlUnlinkNode((xmlNodePtr) elem);
+    xmlFreeElementContent(elem->content);
+    if (elem->name != NULL)
+	xmlFree((xmlChar *) elem->name);
+    if (elem->prefix != NULL)
+	xmlFree((xmlChar *) elem->prefix);
+    memset(elem, -1, sizeof(xmlElement));
+    xmlFree(elem);
+}
+
+
+/**
+ * xmlAddElementDecl:
+ * @ctxt:  the validation context
+ * @dtd:  pointer to the DTD
+ * @name:  the entity name
+ * @type:  the element type
+ * @content:  the element content tree or NULL
+ *
+ * Register a new element declaration
+ *
+ * Returns NULL if not, othervise the entity
+ */
+xmlElementPtr
+xmlAddElementDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
+                  xmlElementTypeVal type,
+		  xmlElementContentPtr content) {
+    xmlElementPtr ret;
+    xmlElementTablePtr table;
+    xmlChar *ns, *uqname;
+
+    if (dtd == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddElementDecl: dtd == NULL\n");
+	return(NULL);
+    }
+    if (name == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddElementDecl: name == NULL\n");
+	return(NULL);
+    }
+    switch (type) {
+        case XML_ELEMENT_TYPE_EMPTY:
+	    if (content != NULL) {
+	        xmlGenericError(xmlGenericErrorContext,
+		        "xmlAddElementDecl: content != NULL for EMPTY\n");
+		return(NULL);
+	    }
+	    break;
+	case XML_ELEMENT_TYPE_ANY:
+	    if (content != NULL) {
+	        xmlGenericError(xmlGenericErrorContext,
+		        "xmlAddElementDecl: content != NULL for ANY\n");
+		return(NULL);
+	    }
+	    break;
+	case XML_ELEMENT_TYPE_MIXED:
+	    if (content == NULL) {
+	        xmlGenericError(xmlGenericErrorContext,
+		        "xmlAddElementDecl: content == NULL for MIXED\n");
+		return(NULL);
+	    }
+	    break;
+	case XML_ELEMENT_TYPE_ELEMENT:
+	    if (content == NULL) {
+	        xmlGenericError(xmlGenericErrorContext,
+		        "xmlAddElementDecl: content == NULL for ELEMENT\n");
+		return(NULL);
+	    }
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddElementDecl: unknown type %d\n", type);
+	    return(NULL);
+    }
+
+    /*
+     * check if name is a QName
+     */
+    uqname = xmlSplitQName2(name, &ns);
+    if (uqname != NULL)
+	name = uqname;
+
+    /*
+     * Create the Element table if needed.
+     */
+    table = (xmlElementTablePtr) dtd->elements;
+    if (table == NULL) {
+        table = xmlCreateElementTable();
+	dtd->elements = (void *) table;
+    }
+    if (table == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddElementDecl: Table creation failed!\n");
+        return(NULL);
+    }
+
+    ret = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddElementDecl: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlElement));
+    ret->type = XML_ELEMENT_DECL;
+
+    /*
+     * fill the structure.
+     */
+    ret->etype = type;
+    ret->name = xmlStrdup(name);
+    ret->prefix = ns;
+    ret->content = xmlCopyElementContent(content);
+    ret->attributes = xmlScanAttributeDecl(dtd, name);
+
+    /*
+     * Validity Check:
+     * Insertion must not fail
+     */
+    if (xmlHashAddEntry2(table, name, ns, ret)) {
+	/*
+	 * The element is already defined in this Dtd.
+	 */
+	VERROR(ctxt->userData, "Redefinition of element %s\n", name);
+	xmlFreeElement(ret);
+	if (uqname != NULL)
+	    xmlFree(uqname);
+	return(NULL);
+    }
+
+    /*
+     * Link it to the Dtd
+     */
+    ret->parent = dtd;
+    ret->doc = dtd->doc;
+    if (dtd->last == NULL) {
+	dtd->children = dtd->last = (xmlNodePtr) ret;
+    } else {
+        dtd->last->next = (xmlNodePtr) ret;
+	ret->prev = dtd->last;
+	dtd->last = (xmlNodePtr) ret;
+    }
+    if (uqname != NULL)
+	xmlFree(uqname);
+    return(ret);
+}
+
+/**
+ * xmlFreeElementTable:
+ * @table:  An element table
+ *
+ * Deallocate the memory used by an element hash table.
+ */
+void
+xmlFreeElementTable(xmlElementTablePtr table) {
+    xmlHashFree(table, (xmlHashDeallocator) xmlFreeElement);
+}
+
+/**
+ * xmlCopyElement:
+ * @elem:  An element
+ *
+ * Build a copy of an element.
+ * 
+ * Returns the new xmlElementPtr or NULL in case of error.
+ */
+xmlElementPtr
+xmlCopyElement(xmlElementPtr elem) {
+    xmlElementPtr cur;
+
+    cur = (xmlElementPtr) xmlMalloc(sizeof(xmlElement));
+    if (cur == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlCopyElement: out of memory !\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlElement));
+    cur->type = XML_ELEMENT_DECL;
+    cur->etype = elem->etype;
+    if (elem->name != NULL)
+	cur->name = xmlStrdup(elem->name);
+    else
+	cur->name = NULL;
+    if (elem->prefix != NULL)
+	cur->prefix = xmlStrdup(elem->prefix);
+    else
+	cur->prefix = NULL;
+    cur->content = xmlCopyElementContent(elem->content);
+    /* TODO : rebuild the attribute list on the copy */
+    cur->attributes = NULL;
+    return(cur);
+}
+
+/**
+ * xmlCopyElementTable:
+ * @table:  An element table
+ *
+ * Build a copy of an element table.
+ * 
+ * Returns the new xmlElementTablePtr or NULL in case of error.
+ */
+xmlElementTablePtr
+xmlCopyElementTable(xmlElementTablePtr table) {
+    return((xmlElementTablePtr) xmlHashCopy(table,
+		                            (xmlHashCopier) xmlCopyElement));
+}
+
+/**
+ * xmlDumpElementDecl:
+ * @buf:  the XML buffer output
+ * @elem:  An element table
+ *
+ * This will dump the content of the element declaration as an XML
+ * DTD definition
+ */
+void
+xmlDumpElementDecl(xmlBufferPtr buf, xmlElementPtr elem) {
+    switch (elem->etype) {
+	case XML_ELEMENT_TYPE_EMPTY:
+	    xmlBufferWriteChar(buf, "<!ELEMENT ");
+	    xmlBufferWriteCHAR(buf, elem->name);
+	    xmlBufferWriteChar(buf, " EMPTY>\n");
+	    break;
+	case XML_ELEMENT_TYPE_ANY:
+	    xmlBufferWriteChar(buf, "<!ELEMENT ");
+	    xmlBufferWriteCHAR(buf, elem->name);
+	    xmlBufferWriteChar(buf, " ANY>\n");
+	    break;
+	case XML_ELEMENT_TYPE_MIXED:
+	    xmlBufferWriteChar(buf, "<!ELEMENT ");
+	    xmlBufferWriteCHAR(buf, elem->name);
+	    xmlBufferWriteChar(buf, " ");
+	    xmlDumpElementContent(buf, elem->content, 1);
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	case XML_ELEMENT_TYPE_ELEMENT:
+	    xmlBufferWriteChar(buf, "<!ELEMENT ");
+	    xmlBufferWriteCHAR(buf, elem->name);
+	    xmlBufferWriteChar(buf, " ");
+	    xmlDumpElementContent(buf, elem->content, 1);
+	    xmlBufferWriteChar(buf, ">\n");
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		"xmlDumpElementDecl: internal: unknown type %d\n",
+		    elem->etype);
+    }
+}
+
+/**
+ * xmlDumpElementTable:
+ * @buf:  the XML buffer output
+ * @table:  An element table
+ *
+ * This will dump the content of the element table as an XML DTD definition
+ */
+void
+xmlDumpElementTable(xmlBufferPtr buf, xmlElementTablePtr table) {
+    xmlHashScan(table, (xmlHashScanner) xmlDumpElementDecl, buf);
+}
+
+/**
+ * xmlCreateEnumeration:
+ * @name:  the enumeration name or NULL
+ *
+ * create and initialize an enumeration attribute node.
+ *
+ * Returns the xmlEnumerationPtr just created or NULL in case
+ *                of error.
+ */
+xmlEnumerationPtr
+xmlCreateEnumeration(xmlChar *name) {
+    xmlEnumerationPtr ret;
+
+    ret = (xmlEnumerationPtr) xmlMalloc(sizeof(xmlEnumeration));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlCreateEnumeration : xmlMalloc(%ld) failed\n",
+	        (long)sizeof(xmlEnumeration));
+        return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlEnumeration));
+
+    if (name != NULL)
+        ret->name = xmlStrdup(name);
+    return(ret);
+}
+
+/**
+ * xmlFreeEnumeration:
+ * @cur:  the tree to free.
+ *
+ * free an enumeration attribute node (recursive).
+ */
+void
+xmlFreeEnumeration(xmlEnumerationPtr cur) {
+    if (cur == NULL) return;
+
+    if (cur->next != NULL) xmlFreeEnumeration(cur->next);
+
+    if (cur->name != NULL) xmlFree((xmlChar *) cur->name);
+    memset(cur, -1, sizeof(xmlEnumeration));
+    xmlFree(cur);
+}
+
+/**
+ * xmlCopyEnumeration:
+ * @cur:  the tree to copy.
+ *
+ * Copy an enumeration attribute node (recursive).
+ *
+ * Returns the xmlEnumerationPtr just created or NULL in case
+ *                of error.
+ */
+xmlEnumerationPtr
+xmlCopyEnumeration(xmlEnumerationPtr cur) {
+    xmlEnumerationPtr ret;
+
+    if (cur == NULL) return(NULL);
+    ret = xmlCreateEnumeration((xmlChar *) cur->name);
+
+    if (cur->next != NULL) ret->next = xmlCopyEnumeration(cur->next);
+    else ret->next = NULL;
+
+    return(ret);
+}
+
+/**
+ * xmlDumpEnumeration:
+ * @buf:  the XML buffer output
+ * @enum:  An enumeration
+ *
+ * This will dump the content of the enumeration
+ */
+void
+xmlDumpEnumeration(xmlBufferPtr buf, xmlEnumerationPtr cur) {
+    if (cur == NULL)  return;
+    
+    xmlBufferWriteCHAR(buf, cur->name);
+    if (cur->next == NULL)
+	xmlBufferWriteChar(buf, ")");
+    else {
+	xmlBufferWriteChar(buf, " | ");
+	xmlDumpEnumeration(buf, cur->next);
+    }
+}
+
+/**
+ * xmlCreateAttributeTable:
+ *
+ * create and initialize an empty attribute hash table.
+ *
+ * Returns the xmlAttributeTablePtr just created or NULL in case
+ *                of error.
+ */
+xmlAttributeTablePtr
+xmlCreateAttributeTable(void) {
+    return(xmlHashCreate(0));
+}
+
+/**
+ * xmlScanAttributeDeclCallback:
+ * @attr:  the attribute decl
+ * @list:  the list to update
+ *
+ * Callback called by xmlScanAttributeDecl when a new attribute
+ * has to be entered in the list.
+ */
+void
+xmlScanAttributeDeclCallback(xmlAttributePtr attr, xmlAttributePtr *list,
+	                     const xmlChar* name) {
+    attr->nexth = *list;
+    *list = attr;
+}
+
+/**
+ * xmlScanAttributeDecl:
+ * @dtd:  pointer to the DTD
+ * @elem:  the element name
+ *
+ * When inserting a new element scan the DtD for existing attributes
+ * for taht element and initialize the Attribute chain
+ *
+ * Returns the pointer to the first attribute decl in the chain,
+ *         possibly NULL.
+ */
+xmlAttributePtr
+xmlScanAttributeDecl(xmlDtdPtr dtd, const xmlChar *elem) {
+    xmlAttributePtr ret = NULL;
+    xmlAttributeTablePtr table;
+
+    if (dtd == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlScanAttributeDecl: dtd == NULL\n");
+	return(NULL);
+    }
+    if (elem == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlScanAttributeDecl: elem == NULL\n");
+	return(NULL);
+    }
+    table = (xmlAttributeTablePtr) dtd->attributes;
+    if (table == NULL) 
+        return(NULL);
+
+    /* WRONG !!! */
+    xmlHashScan3(table, NULL, NULL, elem,
+	        (xmlHashScanner) xmlScanAttributeDeclCallback, &ret);
+    return(ret);
+}
+
+/**
+ * xmlScanIDAttributeDecl:
+ * @ctxt:  the validation context
+ * @elem:  the element name
+ *
+ * Verify that the element don't have too many ID attributes
+ * declared.
+ *
+ * Returns the number of ID attributes found.
+ */
+int
+xmlScanIDAttributeDecl(xmlValidCtxtPtr ctxt, xmlElementPtr elem) {
+    xmlAttributePtr cur;
+    int ret = 0;
+
+    if (elem == NULL) return(0);
+    cur = elem->attributes;
+    while (cur != NULL) {
+        if (cur->atype == XML_ATTRIBUTE_ID) {
+	    ret ++;
+	    if (ret > 1)
+		VERROR(ctxt->userData, 
+	       "Element %s has too may ID attributes defined : %s\n",
+		       elem->name, cur->name);
+	}
+	cur = cur->nexth;
+    }
+    return(ret);
+}
+
+/**
+ * xmlFreeAttribute:
+ * @elem:  An attribute
+ *
+ * Deallocate the memory used by an attribute definition
+ */
+void
+xmlFreeAttribute(xmlAttributePtr attr) {
+    if (attr == NULL) return;
+    xmlUnlinkNode((xmlNodePtr) attr);
+    if (attr->tree != NULL)
+        xmlFreeEnumeration(attr->tree);
+    if (attr->elem != NULL)
+	xmlFree((xmlChar *) attr->elem);
+    if (attr->name != NULL)
+	xmlFree((xmlChar *) attr->name);
+    if (attr->defaultValue != NULL)
+	xmlFree((xmlChar *) attr->defaultValue);
+    if (attr->prefix != NULL)
+	xmlFree((xmlChar *) attr->prefix);
+    memset(attr, -1, sizeof(xmlAttribute));
+    xmlFree(attr);
+}
+
+
+/**
+ * xmlAddAttributeDecl:
+ * @ctxt:  the validation context
+ * @dtd:  pointer to the DTD
+ * @elem:  the element name
+ * @name:  the attribute name
+ * @ns:  the attribute namespace prefix
+ * @type:  the attribute type
+ * @def:  the attribute default type
+ * @defaultValue:  the attribute default value
+ * @tree:  if it's an enumeration, the associated list
+ *
+ * Register a new attribute declaration
+ * Note that @tree becomes the ownership of the DTD
+ *
+ * Returns NULL if not new, othervise the attribute decl
+ */
+xmlAttributePtr
+xmlAddAttributeDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *elem,
+                    const xmlChar *name, const xmlChar *ns,
+		    xmlAttributeType type, xmlAttributeDefault def,
+		    const xmlChar *defaultValue, xmlEnumerationPtr tree) {
+    xmlAttributePtr ret;
+    xmlAttributeTablePtr table;
+    xmlElementPtr elemDef;
+
+    if (dtd == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddAttributeDecl: dtd == NULL\n");
+	xmlFreeEnumeration(tree);
+	return(NULL);
+    }
+    if (name == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddAttributeDecl: name == NULL\n");
+	xmlFreeEnumeration(tree);
+	return(NULL);
+    }
+    if (elem == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddAttributeDecl: elem == NULL\n");
+	xmlFreeEnumeration(tree);
+	return(NULL);
+    }
+    /*
+     * Check the type and possibly the default value.
+     */
+    switch (type) {
+        case XML_ATTRIBUTE_CDATA:
+	    break;
+        case XML_ATTRIBUTE_ID:
+	    break;
+        case XML_ATTRIBUTE_IDREF:
+	    break;
+        case XML_ATTRIBUTE_IDREFS:
+	    break;
+        case XML_ATTRIBUTE_ENTITY:
+	    break;
+        case XML_ATTRIBUTE_ENTITIES:
+	    break;
+        case XML_ATTRIBUTE_NMTOKEN:
+	    break;
+        case XML_ATTRIBUTE_NMTOKENS:
+	    break;
+        case XML_ATTRIBUTE_ENUMERATION:
+	    break;
+        case XML_ATTRIBUTE_NOTATION:
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddAttributeDecl: unknown type %d\n", type);
+	    xmlFreeEnumeration(tree);
+	    return(NULL);
+    }
+    if ((defaultValue != NULL) && 
+        (!xmlValidateAttributeValue(type, defaultValue))) {
+	VERROR(ctxt->userData, "Attribute %s on %s: invalid default value\n",
+	       elem, name, defaultValue);
+	defaultValue = NULL;
+    }
+
+    /*
+     * Create the Attribute table if needed.
+     */
+    table = (xmlAttributeTablePtr) dtd->attributes;
+    if (table == NULL) {
+        table = xmlCreateAttributeTable();
+	dtd->attributes = (void *) table;
+    }
+    if (table == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddAttributeDecl: Table creation failed!\n");
+        return(NULL);
+    }
+
+
+    ret = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddAttributeDecl: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlAttribute));
+    ret->type = XML_ATTRIBUTE_DECL;
+
+    /*
+     * fill the structure.
+     */
+    ret->atype = type;
+    ret->name = xmlStrdup(name);
+    ret->prefix = xmlStrdup(ns);
+    ret->elem = xmlStrdup(elem);
+    ret->def = def;
+    ret->tree = tree;
+    if (defaultValue != NULL)
+	ret->defaultValue = xmlStrdup(defaultValue);
+
+    /*
+     * Validity Check:
+     * Search the DTD for previous declarations of the ATTLIST
+     */
+    if (xmlHashAddEntry3(table, name, ns, elem, ret) < 0) {
+	/*
+	 * The attribute is already defined in this Dtd.
+	 */
+	VWARNING(ctxt->userData,
+		 "Attribute %s on %s: already defined\n",
+		 name, elem);
+	xmlFreeAttribute(ret);
+	return(NULL);
+    }
+
+    /*
+     * Validity Check:
+     * Multiple ID per element
+     */
+    elemDef = xmlGetDtdElementDesc(dtd, elem);
+    if (elemDef != NULL) {
+        if ((type == XML_ATTRIBUTE_ID) &&
+	    (xmlScanIDAttributeDecl(NULL, elemDef) != 0))
+	    VERROR(ctxt->userData, 
+	   "Element %s has too may ID attributes defined : %s\n",
+		   elem, name);
+        ret->nexth = elemDef->attributes;
+        elemDef->attributes = ret;
+    }
+
+    /*
+     * Link it to the Dtd
+     */
+    ret->parent = dtd;
+    ret->doc = dtd->doc;
+    if (dtd->last == NULL) {
+	dtd->children = dtd->last = (xmlNodePtr) ret;
+    } else {
+        dtd->last->next = (xmlNodePtr) ret;
+	ret->prev = dtd->last;
+	dtd->last = (xmlNodePtr) ret;
+    }
+    return(ret);
+}
+
+/**
+ * xmlFreeAttributeTable:
+ * @table:  An attribute table
+ *
+ * Deallocate the memory used by an entities hash table.
+ */
+void
+xmlFreeAttributeTable(xmlAttributeTablePtr table) {
+    xmlHashFree(table, (xmlHashDeallocator) xmlFreeAttribute);
+}
+
+/**
+ * xmlCopyAttribute:
+ * @attr:  An attribute
+ *
+ * Build a copy of an attribute.
+ * 
+ * Returns the new xmlAttributePtr or NULL in case of error.
+ */
+xmlAttributePtr
+xmlCopyAttribute(xmlAttributePtr attr) {
+    xmlAttributePtr cur;
+
+    cur = (xmlAttributePtr) xmlMalloc(sizeof(xmlAttribute));
+    if (cur == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlCopyAttribute: out of memory !\n");
+	return(NULL);
+    }
+    memset(cur, 0, sizeof(xmlAttribute));
+    cur->atype = attr->atype;
+    cur->def = attr->def;
+    cur->tree = xmlCopyEnumeration(attr->tree);
+    if (attr->elem != NULL)
+	cur->elem = xmlStrdup(attr->elem);
+    if (attr->name != NULL)
+	cur->name = xmlStrdup(attr->name);
+    if (attr->defaultValue != NULL)
+	cur->defaultValue = xmlStrdup(attr->defaultValue);
+    return(cur);
+}
+
+/**
+ * xmlCopyAttributeTable:
+ * @table:  An attribute table
+ *
+ * Build a copy of an attribute table.
+ * 
+ * Returns the new xmlAttributeTablePtr or NULL in case of error.
+ */
+xmlAttributeTablePtr
+xmlCopyAttributeTable(xmlAttributeTablePtr table) {
+    return((xmlAttributeTablePtr) xmlHashCopy(table,
+				    (xmlHashCopier) xmlCopyAttribute));
+}
+
+/**
+ * xmlDumpAttributeDecl:
+ * @buf:  the XML buffer output
+ * @attr:  An attribute declaration
+ *
+ * This will dump the content of the attribute declaration as an XML
+ * DTD definition
+ */
+void
+xmlDumpAttributeDecl(xmlBufferPtr buf, xmlAttributePtr attr) {
+    xmlBufferWriteChar(buf, "<!ATTLIST ");
+    xmlBufferWriteCHAR(buf, attr->elem);
+    xmlBufferWriteChar(buf, " ");
+    if (attr->prefix != NULL) {
+	xmlBufferWriteCHAR(buf, attr->prefix);
+	xmlBufferWriteChar(buf, ":");
+    }
+    xmlBufferWriteCHAR(buf, attr->name);
+    switch (attr->atype) {
+	case XML_ATTRIBUTE_CDATA:
+	    xmlBufferWriteChar(buf, " CDATA");
+	    break;
+	case XML_ATTRIBUTE_ID:
+	    xmlBufferWriteChar(buf, " ID");
+	    break;
+	case XML_ATTRIBUTE_IDREF:
+	    xmlBufferWriteChar(buf, " IDREF");
+	    break;
+	case XML_ATTRIBUTE_IDREFS:
+	    xmlBufferWriteChar(buf, " IDREFS");
+	    break;
+	case XML_ATTRIBUTE_ENTITY:
+	    xmlBufferWriteChar(buf, " ENTITY");
+	    break;
+	case XML_ATTRIBUTE_ENTITIES:
+	    xmlBufferWriteChar(buf, " ENTITIES");
+	    break;
+	case XML_ATTRIBUTE_NMTOKEN:
+	    xmlBufferWriteChar(buf, " NMTOKEN");
+	    break;
+	case XML_ATTRIBUTE_NMTOKENS:
+	    xmlBufferWriteChar(buf, " NMTOKENS");
+	    break;
+	case XML_ATTRIBUTE_ENUMERATION:
+	    xmlBufferWriteChar(buf, " (");
+	    xmlDumpEnumeration(buf, attr->tree);
+	    break;
+	case XML_ATTRIBUTE_NOTATION:
+	    xmlBufferWriteChar(buf, " NOTATION (");
+	    xmlDumpEnumeration(buf, attr->tree);
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		"xmlDumpAttributeTable: internal: unknown type %d\n",
+		    attr->atype);
+    }
+    switch (attr->def) {
+	case XML_ATTRIBUTE_NONE:
+	    break;
+	case XML_ATTRIBUTE_REQUIRED:
+	    xmlBufferWriteChar(buf, " #REQUIRED");
+	    break;
+	case XML_ATTRIBUTE_IMPLIED:
+	    xmlBufferWriteChar(buf, " #IMPLIED");
+	    break;
+	case XML_ATTRIBUTE_FIXED:
+	    xmlBufferWriteChar(buf, " #FIXED");
+	    break;
+	default:
+	    xmlGenericError(xmlGenericErrorContext,
+		"xmlDumpAttributeTable: internal: unknown default %d\n",
+		    attr->def);
+    }
+    if (attr->defaultValue != NULL) {
+	xmlBufferWriteChar(buf, " ");
+	xmlBufferWriteQuotedString(buf, attr->defaultValue);
+    }
+    xmlBufferWriteChar(buf, ">\n");
+}
+
+/**
+ * xmlDumpAttributeTable:
+ * @buf:  the XML buffer output
+ * @table:  An attribute table
+ *
+ * This will dump the content of the attribute table as an XML DTD definition
+ */
+void
+xmlDumpAttributeTable(xmlBufferPtr buf, xmlAttributeTablePtr table) {
+    xmlHashScan(table, (xmlHashScanner) xmlDumpAttributeDecl, buf);
+}
+
+/************************************************************************
+ *									*
+ *				NOTATIONs				*
+ *									*
+ ************************************************************************/
+/**
+ * xmlCreateNotationTable:
+ *
+ * create and initialize an empty notation hash table.
+ *
+ * Returns the xmlNotationTablePtr just created or NULL in case
+ *                of error.
+ */
+xmlNotationTablePtr
+xmlCreateNotationTable(void) {
+    return(xmlHashCreate(0));
+}
+
+/**
+ * xmlFreeNotation:
+ * @not:  A notation
+ *
+ * Deallocate the memory used by an notation definition
+ */
+void
+xmlFreeNotation(xmlNotationPtr nota) {
+    if (nota == NULL) return;
+    if (nota->name != NULL)
+	xmlFree((xmlChar *) nota->name);
+    if (nota->PublicID != NULL)
+	xmlFree((xmlChar *) nota->PublicID);
+    if (nota->SystemID != NULL)
+	xmlFree((xmlChar *) nota->SystemID);
+    memset(nota, -1, sizeof(xmlNotation));
+    xmlFree(nota);
+}
+
+
+/**
+ * xmlAddNotationDecl:
+ * @dtd:  pointer to the DTD
+ * @ctxt:  the validation context
+ * @name:  the entity name
+ * @PublicID:  the public identifier or NULL
+ * @SystemID:  the system identifier or NULL
+ *
+ * Register a new notation declaration
+ *
+ * Returns NULL if not, othervise the entity
+ */
+xmlNotationPtr
+xmlAddNotationDecl(xmlValidCtxtPtr ctxt, xmlDtdPtr dtd, const xmlChar *name,
+                   const xmlChar *PublicID, const xmlChar *SystemID) {
+    xmlNotationPtr ret;
+    xmlNotationTablePtr table;
+
+    if (dtd == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNotationDecl: dtd == NULL\n");
+	return(NULL);
+    }
+    if (name == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNotationDecl: name == NULL\n");
+	return(NULL);
+    }
+    if ((PublicID == NULL) && (SystemID == NULL)) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNotationDecl: no PUBLIC ID nor SYSTEM ID\n");
+    }
+
+    /*
+     * Create the Notation table if needed.
+     */
+    table = (xmlNotationTablePtr) dtd->notations;
+    if (table == NULL) 
+        dtd->notations = table = xmlCreateNotationTable();
+    if (table == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNotationDecl: Table creation failed!\n");
+        return(NULL);
+    }
+
+    ret = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNotationDecl: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0, sizeof(xmlNotation));
+
+    /*
+     * fill the structure.
+     */
+    ret->name = xmlStrdup(name);
+    if (SystemID != NULL)
+        ret->SystemID = xmlStrdup(SystemID);
+    if (PublicID != NULL)
+        ret->PublicID = xmlStrdup(PublicID);
+
+    /*
+     * Validity Check:
+     * Check the DTD for previous declarations of the ATTLIST
+     */
+    if (xmlHashAddEntry(table, name, ret)) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddNotationDecl: %s already defined\n", name);
+	xmlFreeNotation(ret);
+	return(NULL);
+    }
+    return(ret);
+}
+
+/**
+ * xmlFreeNotationTable:
+ * @table:  An notation table
+ *
+ * Deallocate the memory used by an entities hash table.
+ */
+void
+xmlFreeNotationTable(xmlNotationTablePtr table) {
+    xmlHashFree(table, (xmlHashDeallocator) xmlFreeNotation);
+}
+
+/**
+ * xmlCopyNotation:
+ * @nota:  A notation
+ *
+ * Build a copy of a notation.
+ * 
+ * Returns the new xmlNotationPtr or NULL in case of error.
+ */
+xmlNotationPtr
+xmlCopyNotation(xmlNotationPtr nota) {
+    xmlNotationPtr cur;
+
+    cur = (xmlNotationPtr) xmlMalloc(sizeof(xmlNotation));
+    if (cur == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlCopyNotation: out of memory !\n");
+	return(NULL);
+    }
+    if (nota->name != NULL)
+	cur->name = xmlStrdup(nota->name);
+    else
+	cur->name = NULL;
+    if (nota->PublicID != NULL)
+	cur->PublicID = xmlStrdup(nota->PublicID);
+    else
+	cur->PublicID = NULL;
+    if (nota->SystemID != NULL)
+	cur->SystemID = xmlStrdup(nota->SystemID);
+    else
+	cur->SystemID = NULL;
+    return(cur);
+}
+
+/**
+ * xmlCopyNotationTable:
+ * @table:  A notation table
+ *
+ * Build a copy of a notation table.
+ * 
+ * Returns the new xmlNotationTablePtr or NULL in case of error.
+ */
+xmlNotationTablePtr
+xmlCopyNotationTable(xmlNotationTablePtr table) {
+    return((xmlNotationTablePtr) xmlHashCopy(table,
+				    (xmlHashCopier) xmlCopyNotation));
+}
+
+/**
+ * xmlDumpNotationDecl:
+ * @buf:  the XML buffer output
+ * @nota:  A notation declaration
+ *
+ * This will dump the content the notation declaration as an XML DTD definition
+ */
+void
+xmlDumpNotationDecl(xmlBufferPtr buf, xmlNotationPtr nota) {
+    xmlBufferWriteChar(buf, "<!NOTATION ");
+    xmlBufferWriteCHAR(buf, nota->name);
+    if (nota->PublicID != NULL) {
+	xmlBufferWriteChar(buf, " PUBLIC ");
+	xmlBufferWriteQuotedString(buf, nota->PublicID);
+	if (nota->SystemID != NULL) {
+	    xmlBufferWriteChar(buf, " ");
+	    xmlBufferWriteCHAR(buf, nota->SystemID);
+	}
+    } else {
+	xmlBufferWriteChar(buf, " SYSTEM ");
+	xmlBufferWriteCHAR(buf, nota->SystemID);
+    }
+    xmlBufferWriteChar(buf, " >\n");
+}
+
+/**
+ * xmlDumpNotationTable:
+ * @buf:  the XML buffer output
+ * @table:  A notation table
+ *
+ * This will dump the content of the notation table as an XML DTD definition
+ */
+void
+xmlDumpNotationTable(xmlBufferPtr buf, xmlNotationTablePtr table) {
+    xmlHashScan(table, (xmlHashScanner) xmlDumpNotationDecl, buf);
+}
+
+/************************************************************************
+ *									*
+ *				IDs					*
+ *									*
+ ************************************************************************/
+/**
+ * xmlCreateIDTable:
+ *
+ * create and initialize an empty id hash table.
+ *
+ * Returns the xmlIDTablePtr just created or NULL in case
+ *                of error.
+ */
+xmlIDTablePtr
+xmlCreateIDTable(void) {
+    return(xmlHashCreate(0));
+}
+
+/**
+ * xmlFreeID:
+ * @not:  A id
+ *
+ * Deallocate the memory used by an id definition
+ */
+void
+xmlFreeID(xmlIDPtr id) {
+    if (id == NULL) return;
+    if (id->value != NULL)
+	xmlFree((xmlChar *) id->value);
+    memset(id, -1, sizeof(xmlID));
+    xmlFree(id);
+}
+
+/**
+ * xmlAddID:
+ * @ctxt:  the validation context
+ * @doc:  pointer to the document
+ * @value:  the value name
+ * @attr:  the attribute holding the ID
+ *
+ * Register a new id declaration
+ *
+ * Returns NULL if not, othervise the new xmlIDPtr
+ */
+xmlIDPtr 
+xmlAddID(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
+         xmlAttrPtr attr) {
+    xmlIDPtr ret;
+    xmlIDTablePtr table;
+
+    if (doc == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddIDDecl: doc == NULL\n");
+	return(NULL);
+    }
+    if (value == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddIDDecl: value == NULL\n");
+	return(NULL);
+    }
+    if (attr == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAddIDDecl: attr == NULL\n");
+	return(NULL);
+    }
+
+    /*
+     * Create the ID table if needed.
+     */
+    table = (xmlIDTablePtr) doc->ids;
+    if (table == NULL) 
+        doc->ids = table = xmlCreateIDTable();
+    if (table == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddID: Table creation failed!\n");
+        return(NULL);
+    }
+
+    ret = (xmlIDPtr) xmlMalloc(sizeof(xmlID));
+    if (ret == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlAddID: out of memory\n");
+	return(NULL);
+    }
+
+    /*
+     * fill the structure.
+     */
+    ret->value = xmlStrdup(value);
+    ret->attr = attr;
+
+    if (xmlHashAddEntry(table, value, ret) < 0) {
+	/*
+	 * The id is already defined in this Dtd.
+	 */
+	VERROR(ctxt->userData, "ID %s already defined\n", value);
+	xmlFreeID(ret);
+	return(NULL);
+    }
+    return(ret);
+}
+
+/**
+ * xmlFreeIDTable:
+ * @table:  An id table
+ *
+ * Deallocate the memory used by an ID hash table.
+ */
+void
+xmlFreeIDTable(xmlIDTablePtr table) {
+    xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
+}
+
+/**
+ * xmlIsID:
+ * @doc:  the document
+ * @elem:  the element carrying the attribute
+ * @attr:  the attribute
+ *
+ * Determine whether an attribute is of type ID. In case we have Dtd(s)
+ * then this is simple, otherwise we use an heuristic: name ID (upper
+ * or lowercase).
+ *
+ * Returns 0 or 1 depending on the lookup result
+ */
+int
+xmlIsID(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
+    if (doc == NULL) return(0);
+    if (attr == NULL) return(0);
+    if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
+	return(0);
+    } else if (doc->type == XML_HTML_DOCUMENT_NODE) {
+        if ((xmlStrEqual(BAD_CAST "id", attr->name)) ||
+	    (xmlStrEqual(BAD_CAST "name", attr->name)))
+	    return(1);
+	return(0);    
+    } else {
+	xmlAttributePtr attrDecl;
+
+	if (elem == NULL) return(0);
+	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
+	if ((attrDecl == NULL) && (doc->extSubset != NULL))
+	    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
+	                                 attr->name);
+
+        if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_ID))
+	    return(1);
+    }
+    return(0);
+}
+
+/**
+ * xmlRemoveID
+ * @doc:  the document
+ * @attr:  the attribute
+ *
+ * Remove the given attribute from the ID table maintained internally.
+ *
+ * Returns -1 if the lookup failed and 0 otherwise
+ */
+int
+xmlRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
+    xmlAttrPtr cur;
+    xmlIDTablePtr table;
+    xmlChar *ID;
+
+    if (doc == NULL) return(-1);
+    if (attr == NULL) return(-1);
+    table = (xmlIDTablePtr) doc->ids;
+    if (table == NULL) 
+        return(-1);
+
+    if (attr == NULL)
+	return(-1);
+    ID = xmlNodeListGetString(doc, attr->children, 1);
+    if (ID == NULL)
+	return(-1);
+    cur = xmlHashLookup(table, ID);
+    if (cur != attr) {
+	xmlFree(ID);
+	return(-1);
+    }
+    xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator) xmlFreeID);
+    xmlFree(ID);
+    return(0);
+}
+
+/**
+ * xmlGetID:
+ * @doc:  pointer to the document
+ * @ID:  the ID value
+ *
+ * Search the attribute declaring the given ID
+ *
+ * Returns NULL if not found, otherwise the xmlAttrPtr defining the ID
+ */
+xmlAttrPtr 
+xmlGetID(xmlDocPtr doc, const xmlChar *ID) {
+    xmlIDTablePtr table;
+    xmlIDPtr id;
+
+    if (doc == NULL) {
+        xmlGenericError(xmlGenericErrorContext, "xmlGetID: doc == NULL\n");
+	return(NULL);
+    }
+
+    if (ID == NULL) {
+        xmlGenericError(xmlGenericErrorContext, "xmlGetID: ID == NULL\n");
+	return(NULL);
+    }
+
+    table = (xmlIDTablePtr) doc->ids;
+    if (table == NULL) 
+        return(NULL);
+
+    id = xmlHashLookup(table, ID);
+    if (id == NULL)
+	return(NULL);
+    return(id->attr);
+}
+
+/************************************************************************
+ *									*
+ *				Refs					*
+ *									*
+ ************************************************************************/
+typedef struct xmlRemove_t 
+{
+	xmlListPtr l;
+	xmlAttrPtr ap;
+} xmlRemove;
+
+/**
+ * xmlCreateRefTable:
+ *
+ * create and initialize an empty ref hash table.
+ *
+ * Returns the xmlRefTablePtr just created or NULL in case
+ *                of error.
+ */
+xmlRefTablePtr
+xmlCreateRefTable(void) {
+    return(xmlHashCreate(0));
+}
+
+/**
+ * xmlFreeRef:
+ * @lk:  A list link
+ *
+ * Deallocate the memory used by a ref definition
+ */
+static void
+xmlFreeRef(xmlLinkPtr lk) {
+	xmlRefPtr ref = (xmlRefPtr)xmlLinkGetData(lk);
+	if (ref == NULL) return;
+	if (ref->value != NULL)
+		xmlFree((xmlChar *)ref->value);
+	memset(ref, -1, sizeof(xmlRef));
+	xmlFree(ref);
+}
+
+/**
+ * xmlFreeRefList:
+ * @list_ref:  A list of references.
+ *
+ * Deallocate the memory used by a list of references
+ */
+static void
+xmlFreeRefList(xmlListPtr list_ref) {
+	if (list_ref == NULL) return;
+	xmlListDelete(list_ref);
+}
+
+/**
+ * xmlWalkRemoveRef:
+ * @data:  Contents of current link
+ * @user:  Value supplied by the user
+ *
+ * Return 0 to abort the walk or 1 to continue
+ */
+static int
+xmlWalkRemoveRef(const void *data, const void *user)
+{
+	xmlAttrPtr attr0 = ((xmlRefPtr)data)->attr;
+	xmlAttrPtr attr1 = ((xmlRemove *)user)->ap;
+	xmlListPtr ref_list = ((xmlRemove *)user)->l;
+
+	if (attr0 == attr1) { /* Matched: remove and terminate walk */
+		xmlListRemoveFirst(ref_list, (void *)data);
+		return 0;
+	}
+	return 1;
+}
+
+/**
+ * xmlAddRef:
+ * @ctxt:  the validation context
+ * @doc:  pointer to the document
+ * @value:  the value name
+ * @attr:  the attribute holding the Ref
+ *
+ * Register a new ref declaration
+ *
+ * Returns NULL if not, othervise the new xmlRefPtr
+ */
+xmlRefPtr 
+xmlAddRef(xmlValidCtxtPtr ctxt, xmlDocPtr doc, const xmlChar *value,
+    xmlAttrPtr attr) {
+	xmlRefPtr ret;
+	xmlRefTablePtr table;
+	xmlListPtr ref_list;
+
+	if (doc == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddRefDecl: doc == NULL\n");
+		return(NULL);
+	}
+	if (value == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddRefDecl: value == NULL\n");
+		return(NULL);
+	}
+	if (attr == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddRefDecl: attr == NULL\n");
+		return(NULL);
+	}
+
+	/*
+     * Create the Ref table if needed.
+     */
+	table = (xmlRefTablePtr) doc->refs;
+	if (table == NULL) 
+		doc->refs = table = xmlCreateRefTable();
+	if (table == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddRef: Table creation failed!\n");
+		return(NULL);
+	}
+
+	ret = (xmlRefPtr) xmlMalloc(sizeof(xmlRef));
+	if (ret == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "xmlAddRef: out of memory\n");
+		return(NULL);
+	}
+
+	/*
+     * fill the structure.
+     */
+ 	ret->value = xmlStrdup(value);
+	ret->attr = attr;
+
+	/* To add a reference :-
+	 * References are maintained as a list of references,
+	 * Lookup the entry, if no entry create new nodelist
+	 * Add the owning node to the NodeList
+	 * Return the ref
+	 */
+
+	if(NULL == (ref_list = xmlHashLookup(table, value))) {
+		if(NULL == (ref_list = xmlListCreate(xmlFreeRef, NULL))) {
+			xmlGenericError(xmlGenericErrorContext,
+			    "xmlAddRef: Reference list creation failed!\n");
+			return(NULL);
+		}
+		if (xmlHashAddEntry(table, value, ref_list) < 0) {
+			xmlListDelete(ref_list);
+			xmlGenericError(xmlGenericErrorContext,
+			    "xmlAddRef: Reference list insertion failed!\n");
+			return(NULL);
+		}
+	}
+	xmlListInsert(ref_list, ret);
+	return(ret);
+}
+
+/**
+ * xmlFreeRefTable:
+ * @table:  An ref table
+ *
+ * Deallocate the memory used by an Ref hash table.
+ */
+void
+xmlFreeRefTable(xmlRefTablePtr table) {
+	xmlHashFree(table, (xmlHashDeallocator) xmlFreeRefList);
+}
+
+/**
+ * xmlIsRef:
+ * @doc:  the document
+ * @elem:  the element carrying the attribute
+ * @attr:  the attribute
+ *
+ * Determine whether an attribute is of type Ref. In case we have Dtd(s)
+ * then this is simple, otherwise we use an heuristic: name Ref (upper
+ * or lowercase).
+ *
+ * Returns 0 or 1 depending on the lookup result
+ */
+int
+xmlIsRef(xmlDocPtr doc, xmlNodePtr elem, xmlAttrPtr attr) {
+	if ((doc->intSubset == NULL) && (doc->extSubset == NULL)) {
+		return(0);
+	} else if (doc->type == XML_HTML_DOCUMENT_NODE) {
+		/* TODO @@@ */
+		return(0);    
+	} else {
+		xmlAttributePtr attrDecl;
+
+		attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, attr->name);
+		if ((attrDecl == NULL) && (doc->extSubset != NULL))
+			attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name,
+			    attr->name);
+
+		if ((attrDecl != NULL) && (attrDecl->atype == XML_ATTRIBUTE_IDREF))
+			return(1);
+	}
+	return(0);
+}
+
+/**
+ * xmlRemoveRef
+ * @doc:  the document
+ * @attr:  the attribute
+ *
+ * Remove the given attribute from the Ref table maintained internally.
+ *
+ * Returns -1 if the lookup failed and 0 otherwise
+ */
+int
+xmlRemoveRef(xmlDocPtr doc, xmlAttrPtr attr) {
+	xmlListPtr ref_list;
+	xmlRefTablePtr table;
+	xmlChar *ID;
+	xmlRemove target;
+
+	if (doc == NULL) return(-1);
+	if (attr == NULL) return(-1);
+	table = (xmlRefTablePtr) doc->refs;
+	if (table == NULL) 
+		return(-1);
+
+	if (attr == NULL)
+		return(-1);
+	ID = xmlNodeListGetString(doc, attr->children, 1);
+	if (ID == NULL)
+		return(-1);
+	ref_list = xmlHashLookup(table, ID);
+
+	if(ref_list == NULL) {
+		xmlFree(ID);
+		return (-1);
+	}
+	/* At this point, ref_list refers to a list of references which
+	 * have the same key as the supplied attr. Our list of references
+	 * is ordered by reference address and we don't have that information
+	 * here to use when removing. We'll have to walk the list and
+	 * check for a matching attribute, when we find one stop the walk
+	 * and remove the entry.
+	 * The list is ordered by reference, so that means we don't have the
+	 * key. Passing the list and the reference to the walker means we
+	 * will have enough data to be able to remove the entry.
+	 */
+	target.l = ref_list;
+	target.ap = attr;
+	
+	/* Remove the supplied attr from our list */
+	xmlListWalk(ref_list, xmlWalkRemoveRef, &target);
+
+	/*If the list is empty then remove the list entry in the hash */
+	if (xmlListEmpty(ref_list))
+	    xmlHashUpdateEntry(table, ID, NULL, (xmlHashDeallocator)
+	    xmlFreeRefList);
+	xmlFree(ID);
+	return(0);
+}
+
+/**
+ * xmlGetRefs:
+ * @doc:  pointer to the document
+ * @ID:  the ID value
+ *
+ * Find the set of references for the supplied ID. 
+ *
+ * Returns NULL if not found, otherwise node set for the ID.
+ */
+xmlListPtr 
+xmlGetRefs(xmlDocPtr doc, const xmlChar *ID) {
+	xmlRefTablePtr table;
+
+	if (doc == NULL) {
+		xmlGenericError(xmlGenericErrorContext, "xmlGetRef: doc == NULL\n");
+		return(NULL);
+	}
+
+	if (ID == NULL) {
+		xmlGenericError(xmlGenericErrorContext, "xmlGetRef: ID == NULL\n");
+		return(NULL);
+	}
+
+	table = (xmlRefTablePtr) doc->refs;
+	if (table == NULL) 
+		return(NULL);
+
+	return (xmlHashLookup(table, ID));
+}
+
+/************************************************************************
+ *									*
+ *		Routines for validity checking				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlGetDtdElementDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the element name
+ *
+ * Search the Dtd for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+xmlElementPtr
+xmlGetDtdElementDesc(xmlDtdPtr dtd, const xmlChar *name) {
+    xmlElementTablePtr table;
+    xmlElementPtr cur;
+    xmlChar *uqname = NULL, *prefix = NULL;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->elements == NULL) return(NULL);
+    table = (xmlElementTablePtr) dtd->elements;
+
+    uqname = xmlSplitQName2(name, &prefix);
+    if (uqname != NULL) {
+	cur = xmlHashLookup2(table, uqname, prefix);
+	if (prefix != NULL) xmlFree(prefix);
+	if (uqname != NULL) xmlFree(uqname);
+    } else
+	cur = xmlHashLookup2(table, name, NULL);
+    return(cur);
+}
+
+/**
+ * xmlGetDtdQElementDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the element name
+ * @prefix:  the element namespace prefix
+ *
+ * Search the Dtd for the description of this element
+ *
+ * returns the xmlElementPtr if found or NULL
+ */
+
+xmlElementPtr
+xmlGetDtdQElementDesc(xmlDtdPtr dtd, const xmlChar *name,
+	              const xmlChar *prefix) {
+    xmlElementTablePtr table;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->elements == NULL) return(NULL);
+    table = (xmlElementTablePtr) dtd->elements;
+
+    return(xmlHashLookup2(table, name, prefix));
+}
+
+/**
+ * xmlGetDtdAttrDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @elem:  the element name
+ * @name:  the attribute name
+ *
+ * Search the Dtd for the description of this attribute on
+ * this element.
+ *
+ * returns the xmlAttributePtr if found or NULL
+ */
+
+xmlAttributePtr
+xmlGetDtdAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name) {
+    xmlAttributeTablePtr table;
+    xmlAttributePtr cur;
+    xmlChar *uqname = NULL, *prefix = NULL;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->attributes == NULL) return(NULL);
+
+    table = (xmlAttributeTablePtr) dtd->attributes;
+    if (table == NULL)
+	return(NULL);
+
+    uqname = xmlSplitQName2(name, &prefix);
+
+    if (uqname != NULL) {
+	cur = xmlHashLookup3(table, uqname, prefix, elem);
+	if (prefix != NULL) xmlFree(prefix);
+	if (uqname != NULL) xmlFree(uqname);
+    } else
+	cur = xmlHashLookup3(table, name, NULL, elem);
+    return(cur);
+}
+
+/**
+ * xmlGetDtdQAttrDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @elem:  the element name
+ * @name:  the attribute name
+ * @prefix:  the attribute namespace prefix
+ *
+ * Search the Dtd for the description of this qualified attribute on
+ * this element.
+ *
+ * returns the xmlAttributePtr if found or NULL
+ */
+
+xmlAttributePtr
+xmlGetDtdQAttrDesc(xmlDtdPtr dtd, const xmlChar *elem, const xmlChar *name,
+	          const xmlChar *prefix) {
+    xmlAttributeTablePtr table;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->attributes == NULL) return(NULL);
+    table = (xmlAttributeTablePtr) dtd->attributes;
+
+    return(xmlHashLookup3(table, name, prefix, elem));
+}
+
+/**
+ * xmlGetDtdNotationDesc:
+ * @dtd:  a pointer to the DtD to search
+ * @name:  the notation name
+ *
+ * Search the Dtd for the description of this notation
+ *
+ * returns the xmlNotationPtr if found or NULL
+ */
+
+xmlNotationPtr
+xmlGetDtdNotationDesc(xmlDtdPtr dtd, const xmlChar *name) {
+    xmlNotationTablePtr table;
+
+    if (dtd == NULL) return(NULL);
+    if (dtd->notations == NULL) return(NULL);
+    table = (xmlNotationTablePtr) dtd->notations;
+
+    return(xmlHashLookup(table, name));
+}
+
+/**
+ * xmlValidateNotationUse:
+ * @ctxt:  the validation context
+ * @doc:  the document
+ * @notationName:  the notation name to check
+ *
+ * Validate that the given mame match a notation declaration.
+ * - [ VC: Notation Declared ]
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNotationUse(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                       const xmlChar *notationName) {
+    xmlNotationPtr notaDecl;
+    if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
+
+    notaDecl = xmlGetDtdNotationDesc(doc->intSubset, notationName);
+    if ((notaDecl == NULL) && (doc->extSubset != NULL))
+	notaDecl = xmlGetDtdNotationDesc(doc->extSubset, notationName);
+
+    if (notaDecl == NULL) {
+	VERROR(ctxt->userData, "NOTATION %s is not declared\n",
+	       notationName);
+	return(0);
+    }
+    return(1);
+}
+
+/**
+ * xmlIsMixedElement
+ * @doc:  the document
+ * @name:  the element name
+ *
+ * Search in the DtDs whether an element accept Mixed content (or ANY)
+ * basically if it is supposed to accept text childs
+ *
+ * returns 0 if no, 1 if yes, and -1 if no element description is available
+ */
+
+int
+xmlIsMixedElement(xmlDocPtr doc, const xmlChar *name) {
+    xmlElementPtr elemDecl;
+
+    if ((doc == NULL) || (doc->intSubset == NULL)) return(-1);
+
+    elemDecl = xmlGetDtdElementDesc(doc->intSubset, name);
+    if ((elemDecl == NULL) && (doc->extSubset != NULL))
+	elemDecl = xmlGetDtdElementDesc(doc->extSubset, name);
+    if (elemDecl == NULL) return(-1);
+    switch (elemDecl->etype) {
+	case XML_ELEMENT_TYPE_ELEMENT:
+	    return(0);
+        case XML_ELEMENT_TYPE_EMPTY:
+	    /*
+	     * return 1 for EMPTY since we want VC error to pop up
+	     * on <empty>     </empty> for example
+	     */
+	case XML_ELEMENT_TYPE_ANY:
+	case XML_ELEMENT_TYPE_MIXED:
+	    return(1);
+    }
+    return(1);
+}
+
+/**
+ * xmlValidateNameValue:
+ * @value:  an Name value
+ *
+ * Validate that the given value match Name production
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNameValue(const xmlChar *value) {
+    const xmlChar *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && (*cur != '_') &&
+        (*cur != ':')) {
+	return(0);
+    }
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNamesValue:
+ * @value:  an Names value
+ *
+ * Validate that the given value match Names production
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNamesValue(const xmlChar *value) {
+    const xmlChar *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && (*cur != '_') &&
+        (*cur != ':')) {
+	return(0);
+    }
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    while (IS_BLANK(*cur)) {
+	while (IS_BLANK(*cur)) cur++;
+
+	if (!IS_LETTER(*cur) && (*cur != '_') &&
+	    (*cur != ':')) {
+	    return(0);
+	}
+
+	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+	       (*cur == '.') || (*cur == '-') ||
+	       (*cur == '_') || (*cur == ':') || 
+	       (IS_COMBINING(*cur)) ||
+	       (IS_EXTENDER(*cur)))
+	       cur++;
+    }
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNmtokenValue:
+ * @value:  an Mntoken value
+ *
+ * Validate that the given value match Nmtoken production
+ *
+ * [ VC: Name Token ]
+ * 
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNmtokenValue(const xmlChar *value) {
+    const xmlChar *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
+        (*cur != '.') && (*cur != '-') &&
+        (*cur != '_') && (*cur != ':') && 
+        (!IS_COMBINING(*cur)) &&
+        (!IS_EXTENDER(*cur)))
+	return(0);
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNmtokensValue:
+ * @value:  an Mntokens value
+ *
+ * Validate that the given value match Nmtokens production
+ *
+ * [ VC: Name Token ]
+ * 
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNmtokensValue(const xmlChar *value) {
+    const xmlChar *cur;
+
+    if (value == NULL) return(0);
+    cur = value;
+    
+    while (IS_BLANK(*cur)) cur++;
+    if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
+        (*cur != '.') && (*cur != '-') &&
+        (*cur != '_') && (*cur != ':') && 
+        (!IS_COMBINING(*cur)) &&
+        (!IS_EXTENDER(*cur)))
+	return(0);
+
+    while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+           (*cur == '.') || (*cur == '-') ||
+	   (*cur == '_') || (*cur == ':') || 
+	   (IS_COMBINING(*cur)) ||
+	   (IS_EXTENDER(*cur)))
+	   cur++;
+
+    while (IS_BLANK(*cur)) {
+	while (IS_BLANK(*cur)) cur++;
+	if (*cur == 0) return(1);
+
+	if (!IS_LETTER(*cur) && !IS_DIGIT(*cur) &&
+	    (*cur != '.') && (*cur != '-') &&
+	    (*cur != '_') && (*cur != ':') && 
+	    (!IS_COMBINING(*cur)) &&
+	    (!IS_EXTENDER(*cur)))
+	    return(0);
+
+	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+	       (*cur == '.') || (*cur == '-') ||
+	       (*cur == '_') || (*cur == ':') || 
+	       (IS_COMBINING(*cur)) ||
+	       (IS_EXTENDER(*cur)))
+	       cur++;
+    }
+
+    if (*cur != 0) return(0);
+
+    return(1);
+}
+
+/**
+ * xmlValidateNotationDecl:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @nota:  a notation definition
+ *
+ * Try to validate a single notation definition
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - it seems that no validity constraing exist on notation declarations
+ * But this function get called anyway ...
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateNotationDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                         xmlNotationPtr nota) {
+    int ret = 1;
+
+    return(ret);
+}
+
+/**
+ * xmlValidateAttributeValue:
+ * @type:  an attribute type
+ * @value:  an attribute value
+ *
+ * Validate that the given attribute value match  the proper production
+ *
+ * [ VC: ID ]
+ * Values of type ID must match the Name production....
+ *
+ * [ VC: IDREF ]
+ * Values of type IDREF must match the Name production, and values
+ * of type IDREFS must match Names ...
+ *
+ * [ VC: Entity Name ]
+ * Values of type ENTITY must match the Name production, values
+ * of type ENTITIES must match Names ...
+ *
+ * [ VC: Name Token ]
+ * Values of type NMTOKEN must match the Nmtoken production; values
+ * of type NMTOKENS must match Nmtokens. 
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateAttributeValue(xmlAttributeType type, const xmlChar *value) {
+    switch (type) {
+	case XML_ATTRIBUTE_ENTITIES:
+	case XML_ATTRIBUTE_IDREFS:
+	    return(xmlValidateNamesValue(value));
+	case XML_ATTRIBUTE_ENTITY:
+	case XML_ATTRIBUTE_IDREF:
+	case XML_ATTRIBUTE_ID:
+	case XML_ATTRIBUTE_NOTATION:
+	    return(xmlValidateNameValue(value));
+	case XML_ATTRIBUTE_NMTOKENS:
+	case XML_ATTRIBUTE_ENUMERATION:
+	    return(xmlValidateNmtokensValue(value));
+	case XML_ATTRIBUTE_NMTOKEN:
+	    return(xmlValidateNmtokenValue(value));
+        case XML_ATTRIBUTE_CDATA:
+	    break;
+    }
+    return(1);
+}
+
+/**
+ * xmlValidateAttributeValue2:
+ * @ctxt:  the validation context
+ * @doc:  the document
+ * @name:  the attribute name (used for error reporting only)
+ * @type:  the attribute type
+ * @value:  the attribute value
+ *
+ * Validate that the given attribute value match a given type.
+ * This typically cannot be done before having finished parsing
+ * the subsets.
+ *
+ * [ VC: IDREF ]
+ * Values of type IDREF must match one of the declared IDs
+ * Values of type IDREFS must match a sequence of the declared IDs
+ * each Name must match the value of an ID attribute on some element
+ * in the XML document; i.e. IDREF values must match the value of
+ * some ID attribute
+ *
+ * [ VC: Entity Name ]
+ * Values of type ENTITY must match one declared entity
+ * Values of type ENTITIES must match a sequence of declared entities
+ *
+ * [ VC: Notation Attributes ]
+ * all notation names in the declaration must be declared.
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateAttributeValue2(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+      const xmlChar *name, xmlAttributeType type, const xmlChar *value) {
+    int ret = 1;
+    switch (type) {
+	case XML_ATTRIBUTE_IDREFS:
+	case XML_ATTRIBUTE_IDREF:
+	case XML_ATTRIBUTE_ID:
+	case XML_ATTRIBUTE_NMTOKENS:
+	case XML_ATTRIBUTE_ENUMERATION:
+	case XML_ATTRIBUTE_NMTOKEN:
+        case XML_ATTRIBUTE_CDATA:
+	    break;
+	case XML_ATTRIBUTE_ENTITY: {
+	    xmlEntityPtr ent;
+
+	    ent = xmlGetDocEntity(doc, value);
+	    if (ent == NULL) {
+		VERROR(ctxt->userData, 
+   "ENTITY attribute %s reference an unknown entity \"%s\"\n",
+		       name, value);
+		ret = 0;
+	    } else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
+		VERROR(ctxt->userData, 
+   "ENTITY attribute %s reference an entity \"%s\" of wrong type\n",
+		       name, value);
+		ret = 0;
+	    }
+	    break;
+        }
+	case XML_ATTRIBUTE_ENTITIES: {
+	    xmlChar *dup, *nam = NULL, *cur, save;
+	    xmlEntityPtr ent;
+
+	    dup = xmlStrdup(value);
+	    if (dup == NULL)
+		return(0);
+	    cur = dup;
+	    while (*cur != 0) {
+		nam = cur;
+		while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
+		save = *cur;
+		*cur = 0;
+		ent = xmlGetDocEntity(doc, nam);
+		if (ent == NULL) {
+		    VERROR(ctxt->userData, 
+       "ENTITIES attribute %s reference an unknown entity \"%s\"\n",
+			   name, nam);
+		    ret = 0;
+		} else if (ent->etype != XML_EXTERNAL_GENERAL_UNPARSED_ENTITY) {
+		    VERROR(ctxt->userData, 
+       "ENTITIES attribute %s reference an entity \"%s\" of wrong type\n",
+			   name, nam);
+		    ret = 0;
+		}
+		if (save == 0)
+		    break;
+		*cur = save;
+		while (IS_BLANK(*cur)) cur++;
+	    }
+	    xmlFree(dup);
+	    break;
+	}
+	case XML_ATTRIBUTE_NOTATION: {
+	    xmlNotationPtr nota;
+
+	    nota = xmlGetDtdNotationDesc(doc->intSubset, value);
+	    if ((nota == NULL) && (doc->extSubset != NULL))
+		nota = xmlGetDtdNotationDesc(doc->extSubset, value);
+
+	    if (nota == NULL) {
+		VERROR(ctxt->userData, 
+       "NOTATION attribute %s reference an unknown notation \"%s\"\n",
+		       name, value);
+		ret = 0;
+	    }
+	    break;
+        }
+    }
+    return(ret);
+}
+
+/**
+ * xmlValidNormalizeAttributeValue:
+ * @doc:  the document
+ * @elem:  the parent
+ * @name:  the attribute name
+ * @value:  the attribute value
+ *
+ * Does the validation related extra step of the normalization of attribute
+ * values:
+ *
+ * If the declared value is not CDATA, then the XML processor must further
+ * process the normalized attribute value by discarding any leading and
+ * trailing space (#x20) characters, and by replacing sequences of space
+ * (#x20) characters by single space (#x20) character.
+ *
+ * returns a new normalized string if normalization is needed, NULL otherwise
+ *      the caller must free the returned value.
+ */
+
+xmlChar *
+xmlValidNormalizeAttributeValue(xmlDocPtr doc, xmlNodePtr elem,
+			        const xmlChar *name, const xmlChar *value) {
+    xmlChar *ret, *dst;
+    const xmlChar *src;
+    xmlAttributePtr attrDecl = NULL;
+
+    if (doc == NULL) return(NULL);
+    if (elem == NULL) return(NULL);
+    if (name == NULL) return(NULL);
+    if (value == NULL) return(NULL);
+
+    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+	xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+	snprintf((char *) qname, sizeof(qname), "%s:%s",
+		 elem->ns->prefix, elem->name);
+#else
+	sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
+#endif
+        qname[sizeof(qname) - 1] = 0;
+	attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, name);
+	if ((attrDecl == NULL) && (doc->extSubset != NULL))
+	    attrDecl = xmlGetDtdAttrDesc(doc->extSubset, qname, name);
+    }
+    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, elem->name, name);
+    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+	attrDecl = xmlGetDtdAttrDesc(doc->extSubset, elem->name, name);
+
+    if (attrDecl == NULL)
+	return(NULL);
+    if (attrDecl->atype == XML_ATTRIBUTE_CDATA)
+	return(NULL);
+
+    ret = xmlStrdup(value);
+    if (ret == NULL)
+	return(NULL);
+    src = value;
+    dst = ret;
+    while (*src == 0x20) src++;
+    while (*src != 0) {
+	if (*src == 0x20) {
+	    while (*src == 0x20) src++;
+	    if (*src != 0)
+		*dst++ = 0x20;
+	} else {
+	    *dst++ = *src++;
+	}
+    }
+    *dst = 0;
+    return(ret);
+}
+
+void
+xmlValidateAttributeIdCallback(xmlAttributePtr attr, int *count,
+	                       const xmlChar* name) {
+    if (attr->atype == XML_ATTRIBUTE_ID) (*count)++;
+}
+
+/**
+ * xmlValidateAttributeDecl:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @attr:  an attribute definition
+ *
+ * Try to validate a single attribute definition
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Attribute Default Legal ]
+ *  - [ VC: Enumeration ]
+ *  - [ VC: ID Attribute Default ]
+ *
+ * The ID/IDREF uniqueness and matching are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                         xmlAttributePtr attr) {
+    int ret = 1;
+    int val;
+    CHECK_DTD;
+    if(attr == NULL) return(1);
+    
+    /* Attribute Default Legal */
+    /* Enumeration */
+    if (attr->defaultValue != NULL) {
+	val = xmlValidateAttributeValue(attr->atype, attr->defaultValue);
+	if (val == 0) {
+	    VERROR(ctxt->userData, 
+	       "Syntax of default value for attribute %s on %s is not valid\n",
+	           attr->name, attr->elem);
+	}
+        ret &= val;
+    }
+
+    /* ID Attribute Default */
+    if ((attr->atype == XML_ATTRIBUTE_ID)&&
+        (attr->def != XML_ATTRIBUTE_IMPLIED) &&
+	(attr->def != XML_ATTRIBUTE_REQUIRED)) {
+	VERROR(ctxt->userData, 
+          "ID attribute %s on %s is not valid must be #IMPLIED or #REQUIRED\n",
+	       attr->name, attr->elem);
+	ret = 0;
+    }
+
+    /* One ID per Element Type */
+    if (attr->atype == XML_ATTRIBUTE_ID) {
+        int nbId;
+
+	/* the trick is taht we parse DtD as their own internal subset */
+        xmlElementPtr elem = xmlGetDtdElementDesc(doc->intSubset,
+	                                          attr->elem);
+	if (elem != NULL) {
+	    nbId = xmlScanIDAttributeDecl(NULL, elem);
+	} else {
+	    xmlAttributeTablePtr table;
+
+	    /*
+	     * The attribute may be declared in the internal subset and the
+	     * element in the external subset.
+	     */
+	    nbId = 0;
+	    table = (xmlAttributeTablePtr) doc->intSubset->attributes;
+	    xmlHashScan3(table, NULL, NULL, attr->elem, (xmlHashScanner)
+		         xmlValidateAttributeIdCallback, &nbId);
+	}
+	if (nbId > 1) {
+	    VERROR(ctxt->userData, 
+       "Element %s has %d ID attribute defined in the internal subset : %s\n",
+		   attr->elem, nbId, attr->name);
+	} else if (doc->extSubset != NULL) {
+	    int extId = 0;
+	    elem = xmlGetDtdElementDesc(doc->extSubset, attr->elem);
+	    if (elem != NULL) {
+		extId = xmlScanIDAttributeDecl(NULL, elem);
+	    }
+	    if (extId > 1) {
+		VERROR(ctxt->userData, 
+       "Element %s has %d ID attribute defined in the external subset : %s\n",
+		       attr->elem, extId, attr->name);
+	    } else if (extId + nbId > 1) {
+		VERROR(ctxt->userData, 
+"Element %s has ID attributes defined in the internal and external subset : %s\n",
+		       attr->elem, attr->name);
+	    }
+	}
+    }
+
+    /* Validity Constraint: Enumeration */
+    if ((attr->defaultValue != NULL) && (attr->tree != NULL)) {
+        xmlEnumerationPtr tree = attr->tree;
+	while (tree != NULL) {
+	    if (xmlStrEqual(tree->name, attr->defaultValue)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VERROR(ctxt->userData, 
+"Default value \"%s\" for attribute %s on %s is not among the enumerated set\n",
+		   attr->defaultValue, attr->name, attr->elem);
+	    ret = 0;
+	}
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlValidateElementDecl:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element definition
+ *
+ * Try to validate a single element definition
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: One ID per Element Type ]
+ *  - [ VC: No Duplicate Types ]
+ *  - [ VC: Unique Element Type Declaration ]
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateElementDecl(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                       xmlElementPtr elem) {
+    int ret = 1;
+    xmlElementPtr tst;
+
+    CHECK_DTD;
+    
+    if (elem == NULL) return(1);
+
+    /* No Duplicate Types */
+    if (elem->etype == XML_ELEMENT_TYPE_MIXED) {
+	xmlElementContentPtr cur, next;
+        const xmlChar *name;
+
+	cur = elem->content;
+	while (cur != NULL) {
+	    if (cur->type != XML_ELEMENT_CONTENT_OR) break;
+	    if (cur->c1 == NULL) break;
+	    if (cur->c1->type == XML_ELEMENT_CONTENT_ELEMENT) {
+		name = cur->c1->name;
+		next = cur->c2;
+		while (next != NULL) {
+		    if (next->type == XML_ELEMENT_CONTENT_ELEMENT) {
+		        if (xmlStrEqual(next->name, name)) {
+			    VERROR(ctxt->userData, 
+		   "Definition of %s has duplicate references of %s\n",
+				   elem->name, name);
+			    ret = 0;
+			}
+			break;
+		    }
+		    if (next->c1 == NULL) break;
+		    if (next->c1->type != XML_ELEMENT_CONTENT_ELEMENT) break;
+		    if (xmlStrEqual(next->c1->name, name)) {
+			VERROR(ctxt->userData, 
+	       "Definition of %s has duplicate references of %s\n",
+			       elem->name, name);
+			ret = 0;
+		    }
+		    next = next->c2;
+		}
+	    }
+	    cur = cur->c2;
+	}
+    }
+
+    /* VC: Unique Element Type Declaration */
+    tst = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+    if ((tst != NULL ) && (tst != elem)) {
+	VERROR(ctxt->userData, "Redefinition of element %s\n",
+	       elem->name);
+	ret = 0;
+    }
+    tst = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+    if ((tst != NULL ) && (tst != elem)) {
+	VERROR(ctxt->userData, "Redefinition of element %s\n",
+	       elem->name);
+	ret = 0;
+    }
+
+    /* One ID per Element Type */
+    if (xmlScanIDAttributeDecl(ctxt, elem) > 1) {
+	ret = 0;
+    }
+    return(ret);
+}
+
+/**
+ * xmlValidateOneAttribute:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ * @attr:  an attribute instance
+ * @value:  the attribute value (without entities processing)
+ *
+ * Try to validate a single attribute for an element
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Attribute Value Type ]
+ *  - [ VC: Fixed Attribute Default ]
+ *  - [ VC: Entity Name ]
+ *  - [ VC: Name Token ]
+ *  - [ VC: ID ]
+ *  - [ VC: IDREF ]
+ *  - [ VC: Entity Name ]
+ *  - [ VC: Notation Attributes ]
+ *
+ * The ID/IDREF uniqueness and matching are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateOneAttribute(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                        xmlNodePtr elem, xmlAttrPtr attr, const xmlChar *value) {
+    /* xmlElementPtr elemDecl; */
+    xmlAttributePtr attrDecl =  NULL;
+    int val;
+    int ret = 1;
+
+    CHECK_DTD;
+    if ((elem == NULL) || (elem->name == NULL)) return(0);
+    if ((attr == NULL) || (attr->name == NULL)) return(0);
+
+    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+	xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+	snprintf((char *) qname, sizeof(qname), "%s:%s",
+		 elem->ns->prefix, elem->name);
+#else
+	sprintf((char *) qname, "%s:%s", elem->ns->prefix, elem->name);
+#endif
+        qname[sizeof(qname) - 1] = 0;
+	if (attr->ns != NULL) {
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, qname,
+		                          attr->name, attr->ns->prefix);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, qname,
+					      attr->name, attr->ns->prefix);
+	} else {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset, qname, attr->name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
+					     qname, attr->name);
+	}
+    }
+    if (attrDecl == NULL) {
+	if (attr->ns != NULL) {
+	    attrDecl = xmlGetDtdQAttrDesc(doc->intSubset, elem->name,
+		                          attr->name, attr->ns->prefix);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdQAttrDesc(doc->extSubset, elem->name,
+					      attr->name, attr->ns->prefix);
+	} else {
+	    attrDecl = xmlGetDtdAttrDesc(doc->intSubset,
+		                         elem->name, attr->name);
+	    if ((attrDecl == NULL) && (doc->extSubset != NULL))
+		attrDecl = xmlGetDtdAttrDesc(doc->extSubset,
+					     elem->name, attr->name);
+	}
+    }
+
+
+    /* Validity Constraint: Attribute Value Type */
+    if (attrDecl == NULL) {
+	VERROR(ctxt->userData,
+	       "No declaration for attribute %s on element %s\n",
+	       attr->name, elem->name);
+	return(0);
+    }
+    attr->atype = attrDecl->atype;
+
+    val = xmlValidateAttributeValue(attrDecl->atype, value);
+    if (val == 0) {
+	VERROR(ctxt->userData, 
+	   "Syntax of value for attribute %s on %s is not valid\n",
+	       attr->name, elem->name);
+        ret = 0;
+    }
+
+    /* Validity constraint: Fixed Attribute Default */
+    if (attrDecl->def == XML_ATTRIBUTE_FIXED) {
+	if (!xmlStrEqual(value, attrDecl->defaultValue)) {
+	    VERROR(ctxt->userData, 
+	   "Value for attribute %s on %s is differnt from default \"%s\"\n",
+		   attr->name, elem->name, attrDecl->defaultValue);
+	    ret = 0;
+	}
+    }
+
+    /* Validity Constraint: ID uniqueness */
+    if (attrDecl->atype == XML_ATTRIBUTE_ID) {
+        if (xmlAddID(ctxt, doc, value, attr) == NULL)
+	    ret = 0;
+    }
+
+    if ((attrDecl->atype == XML_ATTRIBUTE_IDREF) ||
+	(attrDecl->atype == XML_ATTRIBUTE_IDREFS)) {
+        if (xmlAddRef(ctxt, doc, value, attr) == NULL)
+	    ret = 0;
+    }
+
+    /* Validity Constraint: Notation Attributes */
+    if (attrDecl->atype == XML_ATTRIBUTE_NOTATION) {
+        xmlEnumerationPtr tree = attrDecl->tree;
+        xmlNotationPtr nota;
+
+        /* First check that the given NOTATION was declared */
+	nota = xmlGetDtdNotationDesc(doc->intSubset, value);
+	if (nota == NULL)
+	    nota = xmlGetDtdNotationDesc(doc->extSubset, value);
+	
+	if (nota == NULL) {
+	    VERROR(ctxt->userData, 
+       "Value \"%s\" for attribute %s on %s is not a declared Notation\n",
+		   value, attr->name, elem->name);
+	    ret = 0;
+        }
+
+	/* Second, verify that it's among the list */
+	while (tree != NULL) {
+	    if (xmlStrEqual(tree->name, value)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VERROR(ctxt->userData, 
+"Value \"%s\" for attribute %s on %s is not among the enumerated notations\n",
+		   value, attr->name, elem->name);
+	    ret = 0;
+	}
+    }
+
+    /* Validity Constraint: Enumeration */
+    if (attrDecl->atype == XML_ATTRIBUTE_ENUMERATION) {
+        xmlEnumerationPtr tree = attrDecl->tree;
+	while (tree != NULL) {
+	    if (xmlStrEqual(tree->name, value)) break;
+	    tree = tree->next;
+	}
+	if (tree == NULL) {
+	    VERROR(ctxt->userData, 
+       "Value \"%s\" for attribute %s on %s is not among the enumerated set\n",
+		   value, attr->name, elem->name);
+	    ret = 0;
+	}
+    }
+
+    /* Fixed Attribute Default */
+    if ((attrDecl->def == XML_ATTRIBUTE_FIXED) &&
+        (!xmlStrEqual(attrDecl->defaultValue, value))) {
+	VERROR(ctxt->userData, 
+	   "Value for attribute %s on %s must be \"%s\"\n",
+	       attr->name, elem->name, attrDecl->defaultValue);
+        ret = 0;
+    }
+
+    /* Extra check for the attribute value */
+    ret &= xmlValidateAttributeValue2(ctxt, doc, attr->name,
+				      attrDecl->atype, value);
+
+    return(ret);
+}
+
+/* Find the next XML_ELEMENT_NODE, subject to the content constraints.
+ * Return -1 if we found something unexpected, or 1 otherwise.
+ */
+
+static int
+xmlValidateFindNextElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+                           xmlElementContentPtr cont)
+{
+  while (*child && (*child)->type != XML_ELEMENT_NODE) {
+    switch ((*child)->type) {
+      /*
+       * If there is an entity declared and it's not empty
+       * Push the current node on the stack and process with the
+       * entity content.
+       */
+      case XML_ENTITY_REF_NODE:
+        if (((*child)->children != NULL) &&
+            ((*child)->children->children != NULL)) {
+          nodeVPush(ctxt, *child);
+          *child = (*child)->children->children;
+          continue;
+        }
+        break;
+
+      /* These things are ignored (skipped) during validation.  */
+      case XML_PI_NODE:
+      case XML_COMMENT_NODE:
+      case XML_XINCLUDE_START:
+      case XML_XINCLUDE_END:
+        break;
+
+      case XML_TEXT_NODE:
+        if (xmlIsBlankNode(*child)
+            && (cont->type == XML_ELEMENT_CONTENT_ELEMENT
+                || cont->type == XML_ELEMENT_CONTENT_SEQ
+                || cont->type == XML_ELEMENT_CONTENT_OR))
+          break;
+        return -1;
+
+      default:
+        return -1;
+    }
+    *child = (*child)->next;
+  }
+
+  return 1;
+}
+
+int xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+				  xmlElementContentPtr cont);
+
+/**
+ * xmlValidateElementTypeExpr:
+ * @ctxt:  the validation context
+ * @child:  pointer to the child list
+ * @cont:  pointer to the content declaration
+ *
+ * Try to validate the content of an element of type element
+ * but don't handle the occurence factor
+ *
+ * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
+ *         also update child value in-situ.
+ */
+
+int
+xmlValidateElementTypeExpr(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+			   xmlElementContentPtr cont) {
+    xmlNodePtr cur;
+    int ret = 1;
+
+    if (cont == NULL) return(-1);
+    DEBUG_VALID_STATE(*child, cont)
+    ret = xmlValidateFindNextElement(ctxt, child, cont);
+    if (ret < 0)
+	    return(-1);
+    DEBUG_VALID_STATE(*child, cont)
+    switch (cont->type) {
+	case XML_ELEMENT_CONTENT_PCDATA:
+	    if (*child == NULL) return(0);
+	    if ((*child)->type == XML_TEXT_NODE) return(1);
+	    return(0);
+	case XML_ELEMENT_CONTENT_ELEMENT:
+	    if (*child == NULL) return(0);
+	    ret = (xmlStrEqual((*child)->name, cont->name));
+	    if (ret == 1) {
+		while ((*child)->next == NULL) {
+                    if (((*child)->parent != NULL) &&
+			((*child)->parent->type == XML_ENTITY_DECL)) {
+			*child = nodeVPop(ctxt);
+		    } else
+			break;
+		}
+	        *child = (*child)->next;
+	    }
+	    return(ret);
+	case XML_ELEMENT_CONTENT_OR:
+	    cur = *child;
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
+	    if (ret == -1) return(-1);
+	    if (ret == 1) {
+		 return(1);
+	    }
+	    /* rollback and retry the other path */
+	    *child = cur;
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
+	    if (ret == -1) return(-1);
+	    if (ret == 0) {
+		*child = cur;
+		return(0);
+	    }
+	    return(1);
+	case XML_ELEMENT_CONTENT_SEQ:
+	    cur = *child;
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c1);
+	    if (ret == -1) return(-1);
+	    if (ret == 0) {
+		*child = cur;
+		return(0);
+	    }
+	    ret = xmlValidateElementTypeElement(ctxt, child, cont->c2);
+	    if (ret == -1) return(-1);
+	    if (ret == 0) {
+		*child = cur;
+		return(0);
+	    }
+	    return(1);
+    }
+    return(ret);
+}
+
+/**
+ * xmlValidateElementTypeElement:
+ * @ctxt:  the validation context
+ * @child:  pointer to the child list
+ * @cont:  pointer to the content declaration
+ *
+ * Try to validate the content of an element of type element
+ * yeah, Yet Another Regexp Implementation, and recursive
+ *
+ * returns 1 if valid or 0 and -1 if PCDATA stuff is found,
+ *         also update child and content values in-situ.
+ */
+
+int
+xmlValidateElementTypeElement(xmlValidCtxtPtr ctxt, xmlNodePtr *child,
+			      xmlElementContentPtr cont) {
+    xmlNodePtr cur;
+    int ret;
+
+    if (cont == NULL) return(-1);
+
+    DEBUG_VALID_STATE(*child, cont)
+    ret = xmlValidateFindNextElement(ctxt, child, cont);
+    if (ret < 0)
+	    return(-1);
+    DEBUG_VALID_STATE(*child, cont)
+    cur = *child;
+    ret = xmlValidateElementTypeExpr(ctxt, child, cont);
+    if (ret == -1) return(-1);
+    switch (cont->ocur) {
+	case XML_ELEMENT_CONTENT_ONCE:
+	    if (ret == 1) {
+		/* skip ignorable elems */
+		while ((*child != NULL) &&
+		       ((*child)->type == XML_PI_NODE
+                        || (*child)->type == XML_COMMENT_NODE
+                        || (*child)->type == XML_XINCLUDE_START
+                        || (*child)->type == XML_XINCLUDE_END)) {
+		    while ((*child)->next == NULL) {
+			if (((*child)->parent != NULL) &&
+			    ((*child)->parent->type == XML_ENTITY_REF_NODE)) {
+			    *child = (*child)->parent;
+			} else
+			    break;
+		    }
+		    *child = (*child)->next;
+		}
+		return(1);
+	    }
+	    *child = cur;
+	    return(0);
+	case XML_ELEMENT_CONTENT_OPT:
+	    if (ret == 0) {
+		*child = cur;
+	        return(1);
+	    }
+	    break;
+	case XML_ELEMENT_CONTENT_MULT:
+	    if (ret == 0) {
+		*child = cur;
+	        break;
+	    }
+	    /* no break on purpose */
+	case XML_ELEMENT_CONTENT_PLUS:
+	    if (ret == 0) {
+		*child = cur;
+	        return(0);
+	    }
+	    if (ret == -1) return(-1);
+	    cur = *child;
+	    do {
+		if (*child == NULL)
+		    break; /* while */
+		if ((*child)->type == XML_TEXT_NODE
+                    && xmlIsBlankNode(*child)) {
+		    *child = (*child)->next;
+		    continue;
+		}
+		ret = xmlValidateElementTypeExpr(ctxt, child, cont);
+		if (ret == 1)
+		    cur = *child;
+	    } while (ret == 1);
+	    if (ret == -1) return(-1);
+	    *child = cur;
+	    break;
+    }
+
+    return xmlValidateFindNextElement(ctxt, child, cont);
+}
+
+/**
+ * xmlSprintfElementChilds:
+ * @buf:  an output buffer
+ * @content:  An element
+ * @glob: 1 if one must print the englobing parenthesis, 0 otherwise
+ *
+ * This will dump the list of childs to the buffer
+ * Intended just for the debug routine
+ */
+void
+xmlSprintfElementChilds(char *buf, xmlNodePtr node, int glob) {
+    xmlNodePtr cur;
+
+    if (node == NULL) return;
+    if (glob) strcat(buf, "(");
+    cur = node->children;
+    while (cur != NULL) {
+        switch (cur->type) {
+            case XML_ELEMENT_NODE:
+	         strcat(buf, (char *) cur->name);
+		 if (cur->next != NULL)
+		     strcat(buf, " ");
+		 break;
+            case XML_TEXT_NODE:
+		 if (xmlIsBlankNode(cur))
+		     break;
+            case XML_CDATA_SECTION_NODE:
+            case XML_ENTITY_REF_NODE:
+	         strcat(buf, "CDATA");
+		 if (cur->next != NULL)
+		     strcat(buf, " ");
+		 break;
+            case XML_ATTRIBUTE_NODE:
+            case XML_DOCUMENT_NODE:
+#ifdef LIBXML_SGML_ENABLED
+	    case XML_SGML_DOCUMENT_NODE:
+#endif
+	    case XML_HTML_DOCUMENT_NODE:
+            case XML_DOCUMENT_TYPE_NODE:
+            case XML_DOCUMENT_FRAG_NODE:
+            case XML_NOTATION_NODE:
+	    case XML_NAMESPACE_DECL:
+	         strcat(buf, "???");
+		 if (cur->next != NULL)
+		     strcat(buf, " ");
+		 break;
+            case XML_ENTITY_NODE:
+            case XML_PI_NODE:
+            case XML_DTD_NODE:
+            case XML_COMMENT_NODE:
+	    case XML_ELEMENT_DECL:
+	    case XML_ATTRIBUTE_DECL:
+	    case XML_ENTITY_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
+		 break;
+	}
+	cur = cur->next;
+    }
+    if (glob) strcat(buf, ")");
+}
+
+
+/**
+ * xmlValidateOneElement:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ *
+ * Try to validate a single element and it's attributes,
+ * basically it does the following checks as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Element Valid ]
+ *  - [ VC: Required Attribute ]
+ * Then call xmlValidateOneAttribute() for each attribute present.
+ *
+ * The ID/IDREF checkings are done separately
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateOneElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc,
+                      xmlNodePtr elem) {
+    xmlElementPtr elemDecl = NULL;
+    xmlElementContentPtr cont;
+    xmlAttributePtr attr;
+    xmlNodePtr child;
+    int ret = 1;
+    const xmlChar *name;
+
+    CHECK_DTD;
+
+    if (elem == NULL) return(0);
+    if (elem->type == XML_TEXT_NODE) {
+    }
+    switch (elem->type) {
+        case XML_ATTRIBUTE_NODE:
+	    VERROR(ctxt->userData, 
+		   "Attribute element not expected here\n");
+	    return(0);
+        case XML_TEXT_NODE:
+	    if (elem->children != NULL) {
+		VERROR(ctxt->userData, "Text element has childs !\n");
+		return(0);
+	    }
+	    if (elem->properties != NULL) {
+		VERROR(ctxt->userData, "Text element has attributes !\n");
+		return(0);
+	    }
+	    if (elem->ns != NULL) {
+		VERROR(ctxt->userData, "Text element has namespace !\n");
+		return(0);
+	    }
+	    if (elem->nsDef != NULL) {
+		VERROR(ctxt->userData, 
+		       "Text element carries namespace definitions !\n");
+		return(0);
+	    }
+	    if (elem->content == NULL) {
+		VERROR(ctxt->userData, 
+		       "Text element has no content !\n");
+		return(0);
+	    }
+	    return(1);
+        case XML_XINCLUDE_START:
+        case XML_XINCLUDE_END:
+            return(1);
+        case XML_CDATA_SECTION_NODE:
+        case XML_ENTITY_REF_NODE:
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+	    return(1);
+        case XML_ENTITY_NODE:
+	    VERROR(ctxt->userData, 
+		   "Entity element not expected here\n");
+	    return(0);
+        case XML_NOTATION_NODE:
+	    VERROR(ctxt->userData, 
+		   "Notation element not expected here\n");
+	    return(0);
+        case XML_DOCUMENT_NODE:
+        case XML_DOCUMENT_TYPE_NODE:
+        case XML_DOCUMENT_FRAG_NODE:
+	    VERROR(ctxt->userData, 
+		   "Document element not expected here\n");
+	    return(0);
+        case XML_HTML_DOCUMENT_NODE:
+	    VERROR(ctxt->userData, 
+		   "\n");
+	    return(0);
+        case XML_ELEMENT_NODE:
+	    break;
+	default:
+	    VERROR(ctxt->userData, 
+		   "unknown element type %d\n", elem->type);
+	    return(0);
+    }
+    if (elem->name == NULL) return(0);
+
+    /*
+     * Fetch the declaration for the qualified name
+     */
+    if ((elem->ns != NULL) && (elem->ns->prefix != NULL)) {
+	elemDecl = xmlGetDtdQElementDesc(doc->intSubset,
+		                         elem->name, elem->ns->prefix);
+	if ((elemDecl == NULL) && (doc->extSubset != NULL))
+	    elemDecl = xmlGetDtdQElementDesc(doc->extSubset,
+		                             elem->name, elem->ns->prefix);
+    }
+
+    /*
+     * Fetch the declaration for the non qualified name
+     */
+    if (elemDecl == NULL) {
+	elemDecl = xmlGetDtdElementDesc(doc->intSubset, elem->name);
+	if ((elemDecl == NULL) && (doc->extSubset != NULL))
+	    elemDecl = xmlGetDtdElementDesc(doc->extSubset, elem->name);
+    }
+    if (elemDecl == NULL) {
+	VERROR(ctxt->userData, "No declaration for element %s\n",
+	       elem->name);
+	return(0);
+    }
+
+    /* Check taht the element content matches the definition */
+    switch (elemDecl->etype) {
+        case XML_ELEMENT_TYPE_EMPTY:
+	    if (elem->children != NULL) {
+		VERROR(ctxt->userData,
+	       "Element %s was declared EMPTY this one has content\n",
+	               elem->name);
+		ret = 0;
+	    }
+	    break;
+        case XML_ELEMENT_TYPE_ANY:
+	    /* I don't think anything is required then */
+	    break;
+        case XML_ELEMENT_TYPE_MIXED:
+	    /* Hum, this start to get messy */
+	    child = elem->children;
+	    while (child != NULL) {
+	        if (child->type == XML_ELEMENT_NODE) {
+		    name = child->name;
+		    if ((child->ns != NULL) && (child->ns->prefix != NULL)) {
+			xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+			snprintf((char *) qname, sizeof(qname), "%s:%s",
+				 child->ns->prefix, child->name);
+#else
+			sprintf((char *) qname, "%s:%s",
+                                 child->ns->prefix, child->name);
+#endif
+                        qname[sizeof(qname) - 1] = 0;
+			cont = elemDecl->content;
+			while (cont != NULL) {
+			    if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
+				if (xmlStrEqual(cont->name, qname)) break;
+			    } else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
+			       (cont->c1 != NULL) &&
+			       (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)){
+				if (xmlStrEqual(cont->c1->name, qname)) break;
+			    } else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
+				(cont->c1 == NULL) ||
+				(cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)){
+				/* Internal error !!! */
+				xmlGenericError(xmlGenericErrorContext,
+					"Internal: MIXED struct bad\n");
+				break;
+			    }
+			    cont = cont->c2;
+			}
+			if (cont != NULL)
+			    goto child_ok;
+		    }
+		    cont = elemDecl->content;
+		    while (cont != NULL) {
+		        if (cont->type == XML_ELEMENT_CONTENT_ELEMENT) {
+			    if (xmlStrEqual(cont->name, name)) break;
+			} else if ((cont->type == XML_ELEMENT_CONTENT_OR) &&
+			   (cont->c1 != NULL) &&
+			   (cont->c1->type == XML_ELEMENT_CONTENT_ELEMENT)) {
+			    if (xmlStrEqual(cont->c1->name, name)) break;
+			} else if ((cont->type != XML_ELEMENT_CONTENT_OR) ||
+			    (cont->c1 == NULL) ||
+			    (cont->c1->type != XML_ELEMENT_CONTENT_PCDATA)) {
+			    /* Internal error !!! */
+			    xmlGenericError(xmlGenericErrorContext,
+				    "Internal: MIXED struct bad\n");
+			    break;
+			}
+			cont = cont->c2;
+		    }
+		    if (cont == NULL) {
+			VERROR(ctxt->userData,
+	       "Element %s is not declared in %s list of possible childs\n",
+			       name, elem->name);
+			ret = 0;
+		    }
+		}
+child_ok:
+	        child = child->next;
+	    }
+	    break;
+        case XML_ELEMENT_TYPE_ELEMENT:
+	    child = elem->children;
+	    cont = elemDecl->content;
+	    ret = xmlValidateElementTypeElement(ctxt, &child, cont);
+	    while ((child != NULL) && (child->type == XML_TEXT_NODE) &&
+		(xmlIsBlankNode(child))) {
+		child = child->next;
+		continue;
+	    }
+	    if ((ret == 0) || (child != NULL)) {
+	        char expr[1000];
+	        char list[2000];
+
+		expr[0] = 0;
+		xmlSprintfElementContent(expr, cont, 1);
+		list[0] = 0;
+		xmlSprintfElementChilds(list, elem, 1);
+
+		VERROR(ctxt->userData,
+	   "Element %s content doesn't follow the Dtd\nExpecting %s, got %s\n",
+	               elem->name, expr, list);
+		ret = 0;
+	    }
+	    break;
+    }
+
+    /* [ VC: Required Attribute ] */
+    attr = elemDecl->attributes;
+    while (attr != NULL) {
+	if (attr->def == XML_ATTRIBUTE_REQUIRED) {
+	    xmlAttrPtr attrib;
+	    int qualified = -1;
+	    
+	    attrib = elem->properties;
+	    while (attrib != NULL) {
+		if (xmlStrEqual(attrib->name, attr->name)) {
+		    if (attr->prefix != NULL) {
+		        xmlNsPtr nameSpace = attrib->ns;
+
+			if (nameSpace == NULL)
+			    nameSpace = elem->ns;
+			/*
+			 * qualified names handling is problematic, having a
+			 * different prefix should be possible but DTDs don't
+			 * allow to define the URI instead of the prefix :-(
+			 */
+			if (nameSpace == NULL) {
+			    if (qualified < 0) 
+				qualified = 0;
+	    		} else if (!xmlStrEqual(nameSpace->prefix, attr->prefix)) {
+			    if (qualified < 1) 
+				qualified = 1;
+			} else
+			    goto found;
+		    } else {
+		        /*
+			 * We should allow applications to define namespaces
+			 * for their application even if the DTD doesn't 
+			 * carry one, otherwise, basically we would always
+			 * break.
+			 */
+			goto found;
+		    }
+		}
+		attrib = attrib->next;
+	    }
+	    if (qualified == -1) {
+		if (attr->prefix == NULL) {
+		    VERROR(ctxt->userData,
+		       "Element %s doesn't carry attribute %s\n",
+			   elem->name, attr->name);
+		    ret = 0;
+	        } else {
+		    VERROR(ctxt->userData,
+		       "Element %s doesn't carry attribute %s:%s\n",
+			   elem->name, attr->prefix,attr->name);
+		    ret = 0;
+		}
+	    } else if (qualified == 0) {
+		VWARNING(ctxt->userData,
+		   "Element %s required attribute %s:%s has no prefix\n",
+		       elem->name, attr->prefix,attr->name);
+	    } else if (qualified == 1) {
+		VWARNING(ctxt->userData,
+		   "Element %s required attribute %s:%s has different prefix\n",
+		       elem->name, attr->prefix,attr->name);
+	    }
+	}
+found:	    
+        attr = attr->nexth;
+    }
+    return(ret);
+}
+
+/**
+ * xmlValidateRoot:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Try to validate a the root element
+ * basically it does the following check as described by the
+ * XML-1.0 recommendation:
+ *  - [ VC: Root Element Type ]
+ * it doesn't try to recurse or apply other check to the element
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateRoot(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    xmlNodePtr root;
+    if (doc == NULL) return(0);
+
+    root = xmlDocGetRootElement(doc);
+    if ((root == NULL) || (root->name == NULL)) {
+	VERROR(ctxt->userData, "Not valid: no root element\n");
+        return(0);
+    }
+
+    /*
+     * When doing post validation against a separate DTD, those may
+     * no internal subset has been generated
+     */
+    if ((doc->intSubset != NULL) &&
+	(doc->intSubset->name != NULL)) {
+	/*
+	 * Check first the document root against the NQName
+	 */
+	if (!xmlStrEqual(doc->intSubset->name, root->name)) {
+	    if ((root->ns != NULL) && (root->ns->prefix != NULL)) {
+		xmlChar qname[500];
+#ifdef HAVE_SNPRINTF
+		snprintf((char *) qname, sizeof(qname), "%s:%s",
+			 root->ns->prefix, root->name);
+#else
+		sprintf((char *) qname, "%s:%s", root->ns->prefix, root->name);
+#endif
+		qname[sizeof(qname) - 1] = 0;
+		if (xmlStrEqual(doc->intSubset->name, qname))
+		    goto name_ok;
+	    } 
+	    if ((xmlStrEqual(doc->intSubset->name, BAD_CAST "HTML")) &&
+		(xmlStrEqual(root->name, BAD_CAST "html")))
+		goto name_ok;
+	    VERROR(ctxt->userData,
+		   "Not valid: root and DtD name do not match '%s' and '%s'\n",
+		   root->name, doc->intSubset->name);
+	    return(0);
+	    
+	}
+    }
+name_ok:
+    return(1);
+}
+
+
+/**
+ * xmlValidateElement:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @elem:  an element instance
+ *
+ * Try to validate the subtree under an element 
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateElement(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr elem) {
+    xmlNodePtr child;
+    xmlAttrPtr attr;
+    xmlChar *value;
+    int ret = 1;
+
+    if (elem == NULL) return(0);
+
+    /*
+     * XInclude elements were added after parsing in the infoset,
+     * they don't really mean anything validation wise.
+     */
+    if ((elem->type == XML_XINCLUDE_START) ||
+	(elem->type == XML_XINCLUDE_END))
+	return(1);
+
+    CHECK_DTD;
+
+    ret &= xmlValidateOneElement(ctxt, doc, elem);
+    attr = elem->properties;
+    while(attr != NULL) {
+        value = xmlNodeListGetString(doc, attr->children, 0);
+	ret &= xmlValidateOneAttribute(ctxt, doc, elem, attr, value);
+	if (value != NULL)
+	    xmlFree(value);
+	attr= attr->next;
+    }
+    child = elem->children;
+    while (child != NULL) {
+        ret &= xmlValidateElement(ctxt, doc, child);
+        child = child->next;
+    }
+
+    return(ret);
+}
+
+
+void
+xmlValidateCheckRefCallback(xmlRefPtr ref, xmlValidCtxtPtr ctxt,
+	                   const xmlChar *name) {
+    xmlAttrPtr id;
+    xmlAttrPtr attr;
+
+    if (ref == NULL)
+	return;
+    attr = ref->attr;
+    if (attr == NULL)
+	return;
+    if (attr->atype == XML_ATTRIBUTE_IDREF) {
+	id = xmlGetID(ctxt->doc, name);
+	if (id == NULL) {
+	    VERROR(ctxt->userData, 
+	       "IDREF attribute %s reference an unknown ID \"%s\"\n",
+		   attr->name, name);
+	    ctxt->valid = 0;
+	}
+    } else if (attr->atype == XML_ATTRIBUTE_IDREFS) {
+	xmlChar *dup, *str = NULL, *cur, save;
+
+	dup = xmlStrdup(name);
+	if (dup == NULL) {
+	    ctxt->valid = 0;
+	    return;
+	}
+	cur = dup;
+	while (*cur != 0) {
+	    str = cur;
+	    while ((*cur != 0) && (!IS_BLANK(*cur))) cur++;
+	    save = *cur;
+	    *cur = 0;
+	    id = xmlGetID(ctxt->doc, str);
+	    if (id == NULL) {
+		VERROR(ctxt->userData, 
+	       "IDREFS attribute %s reference an unknown ID \"%s\"\n",
+		       attr->name, str);
+		ctxt->valid = 0;
+	    }
+	    if (save == 0)
+		break;
+	    *cur = save;
+	    while (IS_BLANK(*cur)) cur++;
+	}
+	xmlFree(dup);
+    }
+}
+
+/**
+ * xmlValidateDocumentFinal:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Does the final step for the document validation once all the
+ * incremental validation steps have been completed
+ *
+ * basically it does the following checks described by the XML Rec
+ * 
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    xmlRefTablePtr table;
+
+    if (doc == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlValidateDocumentFinal: doc == NULL\n");
+	return(0);
+    }
+
+    /*
+     * Check all the NOTATION/NOTATIONS attributes
+     */
+    /*
+     * Check all the ENTITY/ENTITIES attributes definition for validity
+     */
+    /*
+     * Check all the IDREF/IDREFS attributes definition for validity
+     */
+    table = (xmlRefTablePtr) doc->refs;
+    ctxt->doc = doc;
+    ctxt->valid = 1;
+    xmlHashScan(table, (xmlHashScanner) xmlValidateCheckRefCallback, ctxt);
+    return(ctxt->valid);
+}
+
+/**
+ * xmlValidateDtd:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ * @dtd:  a dtd instance
+ *
+ * Try to validate the document against the dtd instance
+ *
+ * basically it does check all the definitions in the DtD.
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDtd(xmlValidCtxtPtr ctxt, xmlDocPtr doc, xmlDtdPtr dtd) {
+    int ret;
+    xmlDtdPtr oldExt;
+    xmlNodePtr root;
+
+    if (dtd == NULL) return(0);
+    if (doc == NULL) return(0);
+    oldExt = doc->extSubset;
+    doc->extSubset = dtd;
+    ret = xmlValidateRoot(ctxt, doc);
+    if (ret == 0) {
+	doc->extSubset = oldExt;
+	return(ret);
+    }
+    if (doc->ids != NULL) {
+          xmlFreeIDTable(doc->ids);
+          doc->ids = NULL;
+    }
+    if (doc->refs != NULL) {
+          xmlFreeRefTable(doc->refs);
+          doc->refs = NULL;
+    }
+    root = xmlDocGetRootElement(doc);
+    ret = xmlValidateElement(ctxt, doc, root);
+    ret &= xmlValidateDocumentFinal(ctxt, doc);
+    doc->extSubset = oldExt;
+    return(ret);
+}
+
+void
+xmlValidateAttributeCallback(xmlAttributePtr cur, xmlValidCtxtPtr ctxt,
+	                    const xmlChar *name) {
+    if (cur == NULL)
+	return;
+    switch (cur->atype) {
+	case XML_ATTRIBUTE_CDATA:
+	case XML_ATTRIBUTE_ID:
+	case XML_ATTRIBUTE_IDREF	:
+	case XML_ATTRIBUTE_IDREFS:
+	case XML_ATTRIBUTE_NMTOKEN:
+	case XML_ATTRIBUTE_NMTOKENS:
+	case XML_ATTRIBUTE_ENUMERATION:
+	    break;
+	case XML_ATTRIBUTE_ENTITY:
+	case XML_ATTRIBUTE_ENTITIES:
+	case XML_ATTRIBUTE_NOTATION:
+	    if (cur->defaultValue != NULL) {
+		ctxt->valid &= xmlValidateAttributeValue2(ctxt, ctxt->doc,
+			    cur->name, cur->atype, cur->defaultValue);
+	    }
+	    if (cur->tree != NULL) {
+		xmlEnumerationPtr tree = cur->tree;
+		while (tree != NULL) {
+		    ctxt->valid &= xmlValidateAttributeValue2(ctxt, ctxt->doc,
+				    cur->name, cur->atype, tree->name);
+		    tree = tree->next;
+		}
+	    }
+    }
+}
+
+/**
+ * xmlValidateDtdFinal:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Does the final step for the dtds validation once all the
+ * subsets have been parsed
+ *
+ * basically it does the following checks described by the XML Rec
+ * - check that ENTITY and ENTITIES type attributes default or 
+ *   possible values matches one of the defined entities.
+ * - check that NOTATION type attributes default or 
+ *   possible values matches one of the defined notations.
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDtdFinal(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    int ret = 1;
+    xmlDtdPtr dtd;
+    xmlAttributeTablePtr table;
+
+    if (doc == NULL) return(0);
+    if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
+	return(0);
+    ctxt->doc = doc;
+    ctxt->valid = ret;
+    dtd = doc->intSubset;
+    if ((dtd != NULL) && (dtd->attributes != NULL)) {
+	table = (xmlAttributeTablePtr) dtd->attributes;
+	xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
+    }
+    dtd = doc->extSubset;
+    if ((dtd != NULL) && (dtd->attributes != NULL)) {
+	table = (xmlAttributeTablePtr) dtd->attributes;
+	xmlHashScan(table, (xmlHashScanner) xmlValidateAttributeCallback, ctxt);
+    }
+    return(ctxt->valid);
+}
+
+/**
+ * xmlValidateDocument:
+ * @ctxt:  the validation context
+ * @doc:  a document instance
+ *
+ * Try to validate the document instance
+ *
+ * basically it does the all the checks described by the XML Rec
+ * i.e. validates the internal and external subset (if present)
+ * and validate the document tree.
+ *
+ * returns 1 if valid or 0 otherwise
+ */
+
+int
+xmlValidateDocument(xmlValidCtxtPtr ctxt, xmlDocPtr doc) {
+    int ret;
+    xmlNodePtr root;
+
+    if ((doc->intSubset == NULL) && (doc->extSubset == NULL))
+	return(0);
+    if ((doc->intSubset != NULL) && ((doc->intSubset->SystemID != NULL) ||
+	(doc->intSubset->ExternalID != NULL)) && (doc->extSubset == NULL)) {
+        doc->extSubset = xmlParseDTD(doc->intSubset->ExternalID,
+		                     doc->intSubset->SystemID);
+        if (doc->extSubset == NULL) {
+	    if (doc->intSubset->SystemID != NULL) {
+		VERROR(ctxt->userData, 
+		       "Could not load the external subset \"%s\"\n",
+		       doc->intSubset->SystemID);
+	    } else {
+		VERROR(ctxt->userData, 
+		       "Could not load the external subset \"%s\"\n",
+		       doc->intSubset->ExternalID);
+	    }
+	    return(0);
+	}
+    }
+
+    if (doc->ids != NULL) {
+          xmlFreeIDTable(doc->ids);
+          doc->ids = NULL;
+    }
+    if (doc->refs != NULL) {
+          xmlFreeRefTable(doc->refs);
+          doc->refs = NULL;
+    }
+    ret = xmlValidateDtdFinal(ctxt, doc);
+    if (!xmlValidateRoot(ctxt, doc)) return(0);
+
+    root = xmlDocGetRootElement(doc);
+    ret &= xmlValidateElement(ctxt, doc, root);
+    ret &= xmlValidateDocumentFinal(ctxt, doc);
+    return(ret);
+}
+
+
+/************************************************************************
+ *									*
+ *		Routines for dynamic validation editing			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlValidGetPotentialChildren:
+ * @ctree:  an element content tree
+ * @list:  an array to store the list of child names
+ * @len:  a pointer to the number of element in the list
+ * @max:  the size of the array
+ *
+ * Build/extend a list of  potential children allowed by the content tree
+ *
+ * returns the number of element in the list, or -1 in case of error.
+ */
+
+int
+xmlValidGetPotentialChildren(xmlElementContent *ctree, const xmlChar **list,
+                             int *len, int max) {
+    int i;
+
+    if ((ctree == NULL) || (list == NULL) || (len == NULL))
+        return(-1);
+    if (*len >= max) return(*len);
+
+    switch (ctree->type) {
+	case XML_ELEMENT_CONTENT_PCDATA: 
+	    for (i = 0; i < *len;i++)
+		if (xmlStrEqual(BAD_CAST "#PCDATA", list[i])) return(*len);
+	    list[(*len)++] = BAD_CAST "#PCDATA";
+	    break;
+	case XML_ELEMENT_CONTENT_ELEMENT: 
+	    for (i = 0; i < *len;i++)
+		if (xmlStrEqual(ctree->name, list[i])) return(*len);
+	    list[(*len)++] = ctree->name;
+	    break;
+	case XML_ELEMENT_CONTENT_SEQ: 
+	    xmlValidGetPotentialChildren(ctree->c1, list, len, max);
+	    xmlValidGetPotentialChildren(ctree->c2, list, len, max);
+	    break;
+	case XML_ELEMENT_CONTENT_OR:
+	    xmlValidGetPotentialChildren(ctree->c1, list, len, max);
+	    xmlValidGetPotentialChildren(ctree->c2, list, len, max);
+	    break;
+   }
+   
+   return(*len);
+}
+
+/**
+ * xmlValidGetValidElements:
+ * @prev:  an element to insert after
+ * @next:  an element to insert next
+ * @list:  an array to store the list of child names
+ * @max:  the size of the array
+ *
+ * This function returns the list of authorized children to insert
+ * within an existing tree while respecting the validity constraints
+ * forced by the Dtd. The insertion point is defined using @prev and
+ * @next in the following ways:
+ *  to insert before 'node': xmlValidGetValidElements(node->prev, node, ...
+ *  to insert next 'node': xmlValidGetValidElements(node, node->next, ...
+ *  to replace 'node': xmlValidGetValidElements(node->prev, node->next, ...
+ *  to prepend a child to 'node': xmlValidGetValidElements(NULL, node->childs,
+ *  to append a child to 'node': xmlValidGetValidElements(node->last, NULL, ...
+ *
+ * pointers to the element names are inserted at the beginning of the array
+ * and do not need to be freed.
+ *
+ * returns the number of element in the list, or -1 in case of error. If
+ *    the function returns the value @max the caller is invited to grow the
+ *    receiving array and retry.
+ */
+
+int
+xmlValidGetValidElements(xmlNode *prev, xmlNode *next, const xmlChar **list,
+                         int max) {
+    int nb_valid_elements = 0;
+    const xmlChar *elements[256];
+    int nb_elements = 0, i;
+    
+    xmlNode *ref_node;
+    xmlNode *parent;
+    xmlNode *test_node;
+    
+    xmlNode *prev_next;
+    xmlNode *next_prev;
+    xmlNode *parent_childs;
+    xmlNode *parent_last;
+    
+    xmlElement *element_desc;
+
+    if (prev == NULL && next == NULL)
+        return(-1);
+
+    if (list == NULL) return(-1);
+    if (max <= 0) return(-1);
+
+    nb_valid_elements = 0;
+    ref_node = prev ? prev : next;
+    parent = ref_node->parent;
+
+    /*
+     * Retrieves the parent element declaration
+     */
+    element_desc = xmlGetDtdElementDesc(parent->doc->intSubset,
+                                         parent->name);
+    if ((element_desc == NULL) && (parent->doc->extSubset != NULL))
+        element_desc = xmlGetDtdElementDesc(parent->doc->extSubset,
+                                             parent->name);
+    if (element_desc == NULL) return(-1);
+	
+    /*
+     * Do a backup of the current tree structure
+     */
+    prev_next = prev ? prev->next : NULL;
+    next_prev = next ? next->prev : NULL;
+    parent_childs = parent->children;
+    parent_last = parent->last;
+
+    /*
+     * Creates a dummy node and insert it into the tree
+     */    
+    test_node = xmlNewNode (NULL, BAD_CAST "<!dummy?>");
+    test_node->doc = ref_node->doc;
+    test_node->parent = parent;
+    test_node->prev = prev;
+    test_node->next = next;
+    
+    if (prev) prev->next = test_node;
+    else parent->children = test_node;
+		
+    if (next) next->prev = test_node;
+    else parent->last = test_node;
+
+    /*
+     * Insert each potential child node and check if the parent is
+     * still valid
+     */
+    nb_elements = xmlValidGetPotentialChildren(element_desc->content,
+		       elements, &nb_elements, 256);
+    
+    for (i = 0;i < nb_elements;i++) {
+	test_node->name = elements[i];
+	if (xmlValidateOneElement(NULL, parent->doc, parent)) {
+	    int j;
+
+	    for (j = 0; j < nb_valid_elements;j++)
+		if (xmlStrEqual(elements[i], list[j])) break;
+	    list[nb_valid_elements++] = elements[i];
+	    if (nb_valid_elements >= max) break;
+	}
+    }
+
+    /*
+     * Restore the tree structure
+     */
+    if (prev) prev->next = prev_next;
+    if (next) next->prev = next_prev;
+    parent->children = parent_childs;
+    parent->last = parent_last;
+    
+    return(nb_valid_elements);
+}
diff --git a/valid.h b/valid.h
new file mode 100644
index 0000000..a7eb675
--- /dev/null
+++ b/valid.h
@@ -0,0 +1,236 @@
+/*
+ * valid.h : interface to the DTD handling and the validity checking
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifndef __XML_VALID_H__
+#define __XML_VALID_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * an xmlValidCtxt is used for error reporting when validating
+ */
+
+typedef void (*xmlValidityErrorFunc) (void *ctx, const char *msg, ...);
+typedef void (*xmlValidityWarningFunc) (void *ctx, const char *msg, ...);
+
+typedef struct _xmlValidCtxt xmlValidCtxt;
+typedef xmlValidCtxt *xmlValidCtxtPtr;
+struct _xmlValidCtxt {
+    void *userData;			/* user specific data block */
+    xmlValidityErrorFunc error;		/* the callback in case of errors */
+    xmlValidityWarningFunc warning;	/* the callback in case of warning */
+
+    /* Node analysis stack used when validating within entities */
+    xmlNodePtr         node;          /* Current parsed Node */
+    int                nodeNr;        /* Depth of the parsing stack */
+    int                nodeMax;       /* Max depth of the parsing stack */
+    xmlNodePtr        *nodeTab;       /* array of nodes */
+
+    int              finishDtd;       /* finished validating the Dtd ? */
+    xmlDocPtr              doc;       /* the document */
+    int                  valid;       /* temporary validity check result */
+};
+
+/*
+ * ALl notation declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlNotationTable;
+typedef xmlNotationTable *xmlNotationTablePtr;
+
+/*
+ * ALl element declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlElementTable;
+typedef xmlElementTable *xmlElementTablePtr;
+
+/*
+ * ALl attribute declarations are stored in a table
+ * there is one table per DTD
+ */
+
+typedef struct _xmlHashTable xmlAttributeTable;
+typedef xmlAttributeTable *xmlAttributeTablePtr;
+
+/*
+ * ALl IDs attributes are stored in a table
+ * there is one table per document
+ */
+
+typedef struct _xmlHashTable xmlIDTable;
+typedef xmlIDTable *xmlIDTablePtr;
+
+/*
+ * ALl Refs attributes are stored in a table
+ * there is one table per document
+ */
+
+typedef struct _xmlHashTable xmlRefTable;
+typedef xmlRefTable *xmlRefTablePtr;
+
+/* helper */
+xmlChar *           xmlSplitQName2	(const xmlChar *name,
+					 xmlChar **prefix);
+
+/* Notation */
+xmlNotationPtr	    xmlAddNotationDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDtdPtr dtd,
+					 const xmlChar *name,
+					 const xmlChar *PublicID,
+					 const xmlChar *SystemID);
+xmlNotationTablePtr xmlCopyNotationTable(xmlNotationTablePtr table);
+void		    xmlFreeNotationTable(xmlNotationTablePtr table);
+void		    xmlDumpNotationDecl	(xmlBufferPtr buf,
+					 xmlNotationPtr nota);
+void		    xmlDumpNotationTable(xmlBufferPtr buf,
+					 xmlNotationTablePtr table);
+
+/* Element Content */
+xmlElementContentPtr xmlNewElementContent (xmlChar *name,
+					   xmlElementContentType type);
+xmlElementContentPtr xmlCopyElementContent(xmlElementContentPtr content);
+void		     xmlFreeElementContent(xmlElementContentPtr cur);
+void		     xmlSprintfElementContent(char *buf,
+	                                   xmlElementContentPtr content,
+					   int glob);
+
+/* Element */
+xmlElementPtr	   xmlAddElementDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDtdPtr dtd,
+					 const xmlChar *name,
+					 xmlElementTypeVal type,
+					 xmlElementContentPtr content);
+xmlElementTablePtr xmlCopyElementTable	(xmlElementTablePtr table);
+void		   xmlFreeElementTable	(xmlElementTablePtr table);
+void		   xmlDumpElementTable	(xmlBufferPtr buf,
+					 xmlElementTablePtr table);
+void		   xmlDumpElementDecl	(xmlBufferPtr buf,
+					 xmlElementPtr elem);
+
+/* Enumeration */
+xmlEnumerationPtr  xmlCreateEnumeration	(xmlChar *name);
+void		   xmlFreeEnumeration	(xmlEnumerationPtr cur);
+xmlEnumerationPtr  xmlCopyEnumeration	(xmlEnumerationPtr cur);
+
+/* Attribute */
+xmlAttributePtr	    xmlAddAttributeDecl	    (xmlValidCtxtPtr ctxt,
+					     xmlDtdPtr dtd,
+					     const xmlChar *elem,
+					     const xmlChar *name,
+					     const xmlChar *ns,
+					     xmlAttributeType type,
+					     xmlAttributeDefault def,
+					     const xmlChar *defaultValue,
+					     xmlEnumerationPtr tree);
+xmlAttributeTablePtr xmlCopyAttributeTable  (xmlAttributeTablePtr table);
+void		     xmlFreeAttributeTable  (xmlAttributeTablePtr table);
+void		     xmlDumpAttributeTable  (xmlBufferPtr buf,
+					     xmlAttributeTablePtr table);
+void		     xmlDumpAttributeDecl   (xmlBufferPtr buf,
+					     xmlAttributePtr attr);
+
+/* IDs */
+xmlIDPtr	xmlAddID	(xmlValidCtxtPtr ctxt,
+				 xmlDocPtr doc,
+				 const xmlChar *value,
+				 xmlAttrPtr attr);
+xmlIDTablePtr	xmlCopyIDTable	(xmlIDTablePtr table);
+void		xmlFreeIDTable	(xmlIDTablePtr table);
+xmlAttrPtr	xmlGetID	(xmlDocPtr doc,
+				 const xmlChar *ID);
+int		xmlIsID		(xmlDocPtr doc,
+				 xmlNodePtr elem,
+				 xmlAttrPtr attr);
+int		xmlRemoveID	(xmlDocPtr doc, xmlAttrPtr attr);
+
+/* IDREFs */
+xmlRefPtr	xmlAddRef	(xmlValidCtxtPtr ctxt,
+				 xmlDocPtr doc,
+				 const xmlChar *value,
+				 xmlAttrPtr attr);
+xmlRefTablePtr	xmlCopyRefTable	(xmlRefTablePtr table);
+void		xmlFreeRefTable	(xmlRefTablePtr table);
+int		xmlIsRef	(xmlDocPtr doc,
+				 xmlNodePtr elem,
+				 xmlAttrPtr attr);
+int		xmlRemoveRef	(xmlDocPtr doc, xmlAttrPtr attr);
+
+/**
+ * The public function calls related to validity checking
+ */
+
+int		xmlValidateRoot		(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateElementDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlElementPtr elem);
+xmlChar *	xmlValidNormalizeAttributeValue(xmlDocPtr doc,
+					 xmlNodePtr elem,
+					 const xmlChar *name,
+					 const xmlChar *value);
+int		xmlValidateAttributeDecl(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlAttributePtr attr);
+int		xmlValidateAttributeValue(xmlAttributeType type,
+					 const xmlChar *value);
+int		xmlValidateNotationDecl	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlNotationPtr nota);
+int		xmlValidateDtd		(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlDtdPtr dtd);
+int		xmlValidateDtdFinal	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateDocument	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateElement	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlNodePtr elem);
+int		xmlValidateOneElement	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+		                         xmlNodePtr elem);
+int		xmlValidateOneAttribute	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 xmlNodePtr	elem,
+					 xmlAttrPtr attr,
+					 const xmlChar *value);
+int		xmlValidateDocumentFinal(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc);
+int		xmlValidateNotationUse	(xmlValidCtxtPtr ctxt,
+					 xmlDocPtr doc,
+					 const xmlChar *notationName);
+int		xmlIsMixedElement	(xmlDocPtr doc,
+					 const xmlChar *name);
+xmlAttributePtr	xmlGetDtdAttrDesc	(xmlDtdPtr dtd,
+					 const xmlChar *elem,
+					 const xmlChar *name);
+xmlNotationPtr	xmlGetDtdNotationDesc	(xmlDtdPtr dtd,
+					 const xmlChar *name);
+xmlElementPtr	xmlGetDtdElementDesc	(xmlDtdPtr dtd,
+					 const xmlChar *name);
+
+int		xmlValidGetValidElements(xmlNode *prev,
+					 xmlNode *next,
+					 const xmlChar **list,
+					 int max);
+int		xmlValidGetPotentialChildren(xmlElementContent *ctree,
+					 const xmlChar **list,
+					 int *len,
+					 int max);
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_VALID_H__ */
diff --git a/xinclude.c b/xinclude.c
new file mode 100644
index 0000000..c377f64
--- /dev/null
+++ b/xinclude.c
@@ -0,0 +1,806 @@
+/*
+ * xinclude.c : Code to implement XInclude processing
+ *
+ * World Wide Web Consortium Working Draft 26 October 2000
+ * http://www.w3.org/TR/2000/WD-xinclude-20001026
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+/*
+ * TODO: compute XPointers nodesets
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/uri.h>
+#include <libxml/xpointer.h>
+#include <libxml/parserInternals.h>
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
+#include <libxml/xmlerror.h>
+
+#ifdef LIBXML_XINCLUDE_ENABLED
+#include <libxml/xinclude.h>
+
+#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/1999/XML/xinclude"
+#define XINCLUDE_NODE (const xmlChar *) "include"
+#define XINCLUDE_HREF (const xmlChar *) "href"
+#define XINCLUDE_PARSE (const xmlChar *) "parse"
+#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
+#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
+
+/* #define DEBUG_XINCLUDE  */
+
+/************************************************************************
+ *									*
+ *			XInclude contexts handling			*
+ *									*
+ ************************************************************************/
+
+/*
+ * An XInclude context
+ */
+typedef xmlChar *URL;
+typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
+typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
+struct _xmlXIncludeCtxt {
+    xmlDocPtr             doc; /* the source document */
+    int                 incNr; /* number of includes */
+    int                incMax; /* size of includes tab */
+    xmlNodePtr        *incTab; /* array of include nodes */
+    xmlNodePtr        *repTab; /* array of replacement node lists */
+    int                 docNr; /* number of parsed documents */
+    int                docMax; /* size of parsed documents tab */
+    xmlDocPtr         *docTab; /* array of parsed documents */
+    URL               *urlTab; /* array of parsed documents URLs */
+    int                 txtNr; /* number of unparsed documents */
+    int                txtMax; /* size of unparsed documents tab */
+    xmlNodePtr        *txtTab; /* array of unparsed text nodes */
+    URL            *txturlTab; /* array of unparsed txtuments URLs */
+};
+
+/**
+ * xmlXIncludeAddNode:
+ * @ctxt:  the XInclude context
+ * @node:  the new node
+ * 
+ * Add a new node to process to an XInclude context
+ */
+void
+xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    if (ctxt->incMax == 0) {
+	ctxt->incMax = 4;
+        ctxt->incTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
+		                          sizeof(ctxt->incTab[0]));
+        if (ctxt->incTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->repTab = (xmlNodePtr *) xmlMalloc(ctxt->incMax *
+		                          sizeof(ctxt->repTab[0]));
+        if (ctxt->repTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->incNr >= ctxt->incMax) {
+	ctxt->incMax *= 2;
+        ctxt->incTab = (xmlNodePtr *) xmlRealloc(ctxt->incTab,
+	             ctxt->incMax * sizeof(ctxt->incTab[0]));
+        if (ctxt->incTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->repTab = (xmlNodePtr *) xmlRealloc(ctxt->repTab,
+	             ctxt->incMax * sizeof(ctxt->repTab[0]));
+        if (ctxt->repTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->incTab[ctxt->incNr] = node;
+    ctxt->repTab[ctxt->incNr] = NULL;
+    ctxt->incNr++;
+}
+
+/**
+ * xmlXIncludeAddDoc:
+ * @ctxt:  the XInclude context
+ * @doc:  the new document
+ * @url:  the associated URL
+ * 
+ * Add a new document to the list
+ */
+void
+xmlXIncludeAddDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, const URL url) {
+    if (ctxt->docMax == 0) {
+	ctxt->docMax = 4;
+        ctxt->docTab = (xmlDocPtr *) xmlMalloc(ctxt->docMax *
+		                          sizeof(ctxt->docTab[0]));
+        if (ctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->urlTab = (URL *) xmlMalloc(ctxt->docMax *
+		                          sizeof(ctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->docNr >= ctxt->docMax) {
+	ctxt->docMax *= 2;
+        ctxt->docTab = (xmlDocPtr *) xmlRealloc(ctxt->docTab,
+	             ctxt->docMax * sizeof(ctxt->docTab[0]));
+        if (ctxt->docTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->urlTab = (URL *) xmlRealloc(ctxt->urlTab,
+	             ctxt->docMax * sizeof(ctxt->urlTab[0]));
+        if (ctxt->urlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->docTab[ctxt->docNr] = doc;
+    ctxt->urlTab[ctxt->docNr] = xmlStrdup(url);
+    ctxt->docNr++;
+}
+
+/**
+ * xmlXIncludeAddTxt:
+ * @ctxt:  the XInclude context
+ * @txt:  the new text node
+ * @url:  the associated URL
+ * 
+ * Add a new txtument to the list
+ */
+void
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const URL url) {
+    if (ctxt->txtMax == 0) {
+	ctxt->txtMax = 4;
+        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
+		                          sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+        ctxt->txturlTab = (URL *) xmlMalloc(ctxt->txtMax *
+		                          sizeof(ctxt->txturlTab[0]));
+        if (ctxt->txturlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "malloc failed !\n");
+	    return;
+	}
+    }
+    if (ctxt->txtNr >= ctxt->txtMax) {
+	ctxt->txtMax *= 2;
+        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
+	             ctxt->txtMax * sizeof(ctxt->txtTab[0]));
+        if (ctxt->txtTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+        ctxt->txturlTab = (URL *) xmlRealloc(ctxt->txturlTab,
+	             ctxt->txtMax * sizeof(ctxt->urlTab[0]));
+        if (ctxt->txturlTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "realloc failed !\n");
+	    return;
+	}
+    }
+    ctxt->txtTab[ctxt->txtNr] = txt;
+    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
+    ctxt->txtNr++;
+}
+
+/**
+ * xmlXIncludeNewContext:
+ * @doc:  an XML Document
+ *
+ * Creates a new XInclude context
+ *
+ * Returns the new set
+ */
+xmlXIncludeCtxtPtr
+xmlXIncludeNewContext(xmlDocPtr doc) {
+    xmlXIncludeCtxtPtr ret;
+
+    if (doc == NULL)
+	return(NULL);
+    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
+    if (ret == NULL)
+	return(NULL);
+    memset(ret, 0, sizeof(xmlXIncludeCtxt));
+    ret->doc = doc;
+    ret->incNr = 0;
+    ret->incMax = 0;
+    ret->incTab = NULL;
+    ret->repTab = NULL;
+    ret->docNr = 0;
+    ret->docMax = 0;
+    ret->docTab = NULL;
+    ret->urlTab = NULL;
+    return(ret);
+}
+
+/**
+ * xmlXIncludeFreeContext:
+ * @ctxt: the XInclude context
+ *
+ * Free an XInclude context
+ */
+void
+xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
+    int i;
+
+    if (ctxt == NULL)
+	return;
+    for (i = 0;i < ctxt->docNr;i++) {
+	xmlFreeDoc(ctxt->docTab[i]);
+	if (ctxt->urlTab[i] != NULL)
+	    xmlFree(ctxt->urlTab[i]);
+    }
+    for (i = 0;i < ctxt->txtNr;i++) {
+	if (ctxt->txturlTab[i] != NULL)
+	    xmlFree(ctxt->txturlTab[i]);
+    }
+    if (ctxt->incTab != NULL)
+	xmlFree(ctxt->incTab);
+    if (ctxt->repTab != NULL)
+	xmlFree(ctxt->repTab);
+    if (ctxt->urlTab != NULL)
+	xmlFree(ctxt->urlTab);
+    if (ctxt->docTab != NULL)
+	xmlFree(ctxt->docTab);
+    if (ctxt->txtTab != NULL)
+	xmlFree(ctxt->txtTab);
+    if (ctxt->txturlTab != NULL)
+	xmlFree(ctxt->txturlTab);
+    memset(ctxt, 0xeb, sizeof(xmlXIncludeCtxt));
+    xmlFree(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *			XInclude I/O handling				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXIncludeLoadDoc:
+ * @ctxt:  the XInclude context
+ * @url:  the associated URL
+ * @nr:  the xinclude node number
+ * 
+ * Load the document, and store the result in the XInclude context
+ */
+void
+xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
+    xmlDocPtr doc;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    xmlChar *fragment = NULL;
+    int i;
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)url);
+    if (uri == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+    if (uri->fragment != NULL) {
+	fragment = (xmlChar *) uri->fragment;
+	uri->fragment = NULL;
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	if (fragment != NULL)
+	    xmlFree(fragment);
+	return;
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if ((URL[0] == 0) || (URL[0] == '#')) {
+	doc = NULL;
+        goto loaded;
+    }
+
+    /*
+     * Prevent reloading twice the document.
+     */
+    for (i = 0; i < ctxt->docNr; i++) {
+	if (xmlStrEqual(URL, ctxt->urlTab[i])) {
+	    doc = ctxt->docTab[i];
+	    goto loaded;
+	}
+    }
+    /*
+     * Load it.
+     */
+    doc = xmlParseFile((const char *)URL);
+    if (doc == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: could not load %s\n", URL);
+	xmlFree(URL);
+	if (fragment != NULL)
+	    xmlFree(fragment);
+	return;
+    }
+    xmlXIncludeAddDoc(ctxt, doc, URL);
+
+loaded:
+    if (fragment == NULL) {
+	/*
+	 * Add the top children list as the replacement copy.
+	 * ISSUE: seems we should scrap DTD info from the copied list.
+	 */
+	if (doc == NULL)
+	    ctxt->repTab[nr] = xmlCopyNodeList(ctxt->doc->children);
+	else
+	    ctxt->repTab[nr] = xmlCopyNodeList(doc->children);
+    } else {
+	/*
+	 * Computes the XPointer expression and make a copy used
+	 * as the replacement copy.
+	 */
+	xmlXPathObjectPtr xptr;
+	xmlXPathContextPtr xptrctxt;
+
+	if (doc == NULL) {
+	    xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr], NULL);
+	} else {
+	    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
+	}
+	if (xptrctxt == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+			"XInclude: could create XPointer context\n");
+	    xmlFree(URL);
+	    xmlFree(fragment);
+	    return;
+	}
+	xptr = xmlXPtrEval(fragment, xptrctxt);
+	if (xptr == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+			"XInclude: XPointer evaluation failed: #%s\n",
+			fragment);
+	    xmlXPathFreeContext(xptrctxt);
+	    xmlFree(URL);
+	    xmlFree(fragment);
+	    return;
+	}
+	ctxt->repTab[nr] = xmlXPtrBuildNodeList(xptr);
+	xmlXPathFreeObject(xptr);
+	xmlXPathFreeContext(xptrctxt);
+	xmlFree(fragment);
+    }
+    xmlFree(URL);
+}
+
+/**
+ * xmlXIncludeLoadTxt:
+ * @ctxt:  the XInclude context
+ * @url:  the associated URL
+ * @nr:  the xinclude node number
+ * 
+ * Load the content, and store the result in the XInclude context
+ */
+void
+xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
+    xmlParserInputBufferPtr buf;
+    xmlNodePtr node;
+    xmlURIPtr uri;
+    xmlChar *URL;
+    int i;
+    /*
+     * Check the URL and remove any fragment identifier
+     */
+    uri = xmlParseURI((const char *)url);
+    if (uri == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+    if (uri->fragment != NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"XInclude: fragment identifier forbidden for text: %s\n",
+		uri->fragment);
+	xmlFreeURI(uri);
+	return;
+    }
+    URL = xmlSaveUri(uri);
+    xmlFreeURI(uri);
+    if (URL == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value URI %s\n", url);
+	return;
+    }
+
+    /*
+     * Handling of references to the local document are done
+     * directly through ctxt->doc.
+     */
+    if (URL[0] == 0) {
+	xmlGenericError(xmlGenericErrorContext,
+		"XInclude: text serialization of document not available\n");
+	xmlFree(URL);
+	return;
+    }
+
+    /*
+     * Prevent reloading twice the document.
+     */
+    for (i = 0; i < ctxt->txtNr; i++) {
+	if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
+	    node = xmlCopyNode(ctxt->txtTab[i], 1);
+	    goto loaded;
+	}
+    }
+    /*
+     * Load it.
+     * Issue 62: how to detect the encoding
+     */
+    buf = xmlParserInputBufferCreateFilename((const char *)URL, 0);
+    if (buf == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: could not load %s\n", URL);
+	xmlFree(URL);
+	return;
+    }
+    node = xmlNewText(NULL);
+
+    /*
+     * Scan all chars from the resource and add the to the node
+     */
+    while (xmlParserInputBufferRead(buf, 128) > 0) {
+	int len;
+	const xmlChar *content;
+
+	content = xmlBufferContent(buf->buffer);
+	len = xmlBufferLength(buf->buffer);
+	for (i = 0;i < len; i++) {
+	    /*
+	     * TODO: if the encoding issue is solved, scan UTF8 chars instead
+	     */
+	    if (!IS_CHAR(content[i])) {
+		xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: %s contains invalid char %d\n", URL, content[i]);
+	    } else {
+		xmlNodeAddContentLen(node, &content[i], 1);
+	    }
+	}
+	xmlBufferShrink(buf->buffer, len);
+    }
+    xmlFreeParserInputBuffer(buf);
+    xmlXIncludeAddTxt(ctxt, node, URL);
+
+loaded:
+    /*
+     * Add the element as the replacement copy.
+     */
+    ctxt->repTab[nr] = node;
+    xmlFree(URL);
+}
+
+/************************************************************************
+ *									*
+ *			XInclude Processing				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXIncludePreProcessNode:
+ * @ctxt: an XInclude context
+ * @node: an XInclude node
+ *
+ * Implement the infoset replacement lookup on the XML element @node
+ *
+ * Returns the result list or NULL in case of error
+ */
+xmlNodePtr
+xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
+    xmlXIncludeAddNode(ctxt, node);
+    return(0);
+}
+
+/**
+ * xmlXIncludeLoadNode:
+ * @ctxt: an XInclude context
+ * @nr: the node number
+ *
+ * Find and load the infoset replacement for the given node.
+ *
+ * Returns 0 if substition succeeded, -1 if some processing failed
+ */
+int
+xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
+    xmlNodePtr cur;
+    xmlChar *href;
+    xmlChar *parse;
+    xmlChar *base;
+    xmlChar *URI;
+    int xml = 1; /* default Issue 64 */
+
+    if (ctxt == NULL)
+	return(-1);
+    if ((nr < 0) || (nr >= ctxt->incNr))
+	return(-1);
+    cur = ctxt->incTab[nr];
+    if (cur == NULL)
+	return(-1);
+
+#ifdef DEBUG_XINCLUDE
+    xmlDebugDumpNode(stdout, cur, 0);
+#endif
+    /*
+     * read the attributes
+     */
+    href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
+    if (href == NULL) {
+	href = xmlGetProp(cur, XINCLUDE_HREF);
+	if (href == NULL) {
+	    xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
+	    return(-1);
+	}
+    }
+    parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
+    if (parse == NULL) {
+	parse = xmlGetProp(cur, XINCLUDE_PARSE);
+    }
+    if (parse != NULL) {
+	if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
+	    xml = 1;
+	else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
+	    xml = 0;
+	else {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "XInclude: invalid value %s for %s\n",
+		            parse, XINCLUDE_PARSE);
+	    if (href != NULL)
+		xmlFree(href);
+	    if (parse != NULL)
+		xmlFree(parse);
+	    return(-1);
+	}
+    }
+
+    /*
+     * compute the URI
+     */
+    base = xmlNodeGetBase(ctxt->doc, cur);
+    if (base == NULL) {
+	URI = xmlBuildURI(href, ctxt->doc->URL);
+    } else {
+	URI = xmlBuildURI(href, base);
+    }
+    if (URI == NULL) {
+	xmlChar *escbase;
+	xmlChar *eschref;
+	/*
+	 * Some escapeing may be needed
+	 */
+	escbase = xmlURIEscape(base);
+	eschref = xmlURIEscape(href);
+	URI = xmlBuildURI(eschref, escbase);
+	if (escbase != NULL)
+	    xmlFree(escbase);
+	if (eschref != NULL)
+	    xmlFree(eschref);
+    }
+    if (URI == NULL) {
+	xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
+	if (parse != NULL)
+	    xmlFree(parse);
+	if (href != NULL)
+	    xmlFree(href);
+	if (base != NULL)
+	    xmlFree(base);
+	return(-1);
+    }
+#ifdef DEBUG_XINCLUDE
+    xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
+	    xml ? "xml": "text");
+    xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
+#endif
+
+    /*
+     * Cleanup
+     */
+    if (xml) {
+	xmlXIncludeLoadDoc(ctxt, URI, nr);
+	/* xmlXIncludeGetFragment(ctxt, cur, URI); */
+    } else {
+	xmlXIncludeLoadTxt(ctxt, URI, nr);
+    }
+
+    /*
+     * Cleanup
+     */
+    if (URI != NULL)
+	xmlFree(URI);
+    if (parse != NULL)
+	xmlFree(parse);
+    if (href != NULL)
+	xmlFree(href);
+    if (base != NULL)
+	xmlFree(base);
+    return(0);
+}
+
+/**
+ * xmlXIncludeIncludeNode:
+ * @ctxt: an XInclude context
+ * @nr: the node number
+ *
+ * Inplement the infoset replacement for the given node
+ *
+ * Returns 0 if substition succeeded, -1 if some processing failed
+ */
+int
+xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
+    xmlNodePtr cur, end, list;
+
+    if (ctxt == NULL)
+	return(-1);
+    if ((nr < 0) || (nr >= ctxt->incNr))
+	return(-1);
+    cur = ctxt->incTab[nr];
+    if (cur == NULL)
+	return(-1);
+
+    /*
+     * Change the current node as an XInclude start one, and add an
+     * entity end one
+     */
+    cur->type = XML_XINCLUDE_START;
+    end = xmlNewNode(cur->ns, cur->name);
+    if (end == NULL) {
+	xmlGenericError(xmlGenericErrorContext, 
+		"XInclude: failed to build node\n");
+	return(-1);
+    }
+    end->type = XML_XINCLUDE_END;
+    xmlAddNextSibling(cur, end);
+
+    /*
+     * Add the list of nodes
+     */
+    list = ctxt->repTab[nr];
+    ctxt->repTab[nr] = NULL;
+    while (list != NULL) {
+	cur = list;
+	list = list->next;
+
+        xmlAddPrevSibling(end, cur);
+    }
+    return(0);
+}
+
+/**
+ * xmlXIncludeTestNode:
+ * @doc: an XML document
+ * @node: an XInclude node
+ *
+ * test if the node is an XInclude node
+ *
+ * Returns 1 true, 0 otherwise
+ */
+int
+xmlXIncludeTestNode(xmlDocPtr doc, xmlNodePtr node) {
+    if (node == NULL)
+	return(0);
+    if (node->ns == NULL)
+	return(0);
+    if ((xmlStrEqual(node->name, XINCLUDE_NODE)) &&
+	(xmlStrEqual(node->ns->href, XINCLUDE_NS))) return(1);
+    return(0);
+}
+
+/**
+ * xmlXIncludeProcess:
+ * @doc: an XML document
+ *
+ * Implement the XInclude substitution on the XML document @doc
+ *
+ * Returns 0 if no substition were done, -1 if some processing failed
+ *    or the number of substitutions done.
+ */
+int
+xmlXIncludeProcess(xmlDocPtr doc) {
+    xmlXIncludeCtxtPtr ctxt;
+    xmlNodePtr cur;
+    int ret = 0;
+    int i;
+
+    if (doc == NULL)
+	return(-1);
+    ctxt = xmlXIncludeNewContext(doc);
+    if (ctxt == NULL)
+	return(-1);
+
+    /*
+     * First phase: lookup the elements in the document
+     */
+    cur = xmlDocGetRootElement(doc);
+    if (xmlXIncludeTestNode(doc, cur))
+	xmlXIncludePreProcessNode(ctxt, cur);
+    while (cur != NULL) {
+	/* TODO: need to work on entities -> stack */
+	if ((cur->children != NULL) &&
+	    (cur->children->type != XML_ENTITY_DECL)) {
+	    cur = cur->children;
+	    if (xmlXIncludeTestNode(doc, cur))
+		xmlXIncludePreProcessNode(ctxt, cur);
+	} else if (cur->next != NULL) {
+	    cur = cur->next;
+	    if (xmlXIncludeTestNode(doc, cur))
+		xmlXIncludePreProcessNode(ctxt, cur);
+	} else {
+	    do {
+		cur = cur->parent;
+		if (cur == NULL) break; /* do */
+		if (cur->next != NULL) {
+		    cur = cur->next;
+		    if (xmlXIncludeTestNode(doc, cur))
+			xmlXIncludePreProcessNode(ctxt, cur);
+		    break; /* do */
+		}
+	    } while (cur != NULL);
+	}
+    }
+
+    /*
+     * Second Phase : collect the infosets fragments
+     */
+    for (i = 0;i < ctxt->incNr; i++) {
+        xmlXIncludeLoadNode(ctxt, i);
+    }
+
+    /*
+     * Third phase: extend the original document infoset.
+     */
+    for (i = 0;i < ctxt->incNr; i++) {
+	xmlXIncludeIncludeNode(ctxt, i);
+    }
+
+    /*
+     * Cleanup
+     */
+    xmlXIncludeFreeContext(ctxt);
+    return(ret);
+}
+
+#else /* !LIBXML_XINCLUDE_ENABLED */
+#endif
diff --git a/xinclude.h b/xinclude.h
new file mode 100644
index 0000000..eca4588
--- /dev/null
+++ b/xinclude.h
@@ -0,0 +1,26 @@
+/*
+ * xinclude.c : API to handle XInclude processing
+ *
+ * World Wide Web Consortium Working Draft 26 October 2000
+ * http://www.w3.org/TR/2000/WD-xinclude-20001026
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XINCLUDE_H__
+#define __XML_XINCLUDE_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int	xmlXIncludeProcess	(xmlDocPtr doc);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XINCLUDE_H__ */
diff --git a/xlink.c b/xlink.c
new file mode 100644
index 0000000..6821490
--- /dev/null
+++ b/xlink.c
@@ -0,0 +1,187 @@
+/*
+ * xlink.c : implementation of the hyperlinks detection module
+ *           This version supports both XML XLinks and HTML simple links
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h> /* for memset() only */
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/valid.h>
+#include <libxml/xlink.h>
+
+#define XLINK_NAMESPACE (BAD_CAST "http://www.w3.org/1999/xlink/namespace/")
+#define XHTML_NAMESPACE (BAD_CAST "http://www.w3.org/1999/xhtml/")
+
+/****************************************************************
+ *								*
+ *           Default setting and related functions		*
+ *								*
+ ****************************************************************/
+ 
+xlinkHandlerPtr xlinkDefaultHandler = NULL;
+xlinkNodeDetectFunc	xlinkDefaultDetect = NULL;
+
+/**
+ * xlinkGetDefaultHandler:
+ *
+ * Get the default xlink handler.
+ *
+ * Returns the current xlinkHandlerPtr value.
+ */
+xlinkHandlerPtr
+xlinkGetDefaultHandler(void) {
+    return(xlinkDefaultHandler);
+}
+
+
+/**
+ * xlinkSetDefaultHandler:
+ * @handler:  the new value for the xlink handler block
+ *
+ * Set the default xlink handlers
+ */
+void
+xlinkSetDefaultHandler(xlinkHandlerPtr handler) {
+    xlinkDefaultHandler = handler;
+}
+
+/**
+ * xlinkGetDefaultDetect:
+ *
+ * Get the default xlink detection routine
+ *
+ * Returns the current function or NULL;
+ */
+xlinkNodeDetectFunc
+xlinkGetDefaultDetect	(void) {
+    return(xlinkDefaultDetect);
+}
+
+/**
+ * xlinkSetDefaultDetect:
+ * @func: pointer to the new detction routine.
+ *
+ * Set the default xlink detection routine
+ */
+void 
+xlinkSetDefaultDetect	(xlinkNodeDetectFunc func) {
+    xlinkDefaultDetect = func;
+}
+
+/****************************************************************
+ *								*
+ *                  The detection routines			*
+ *								*
+ ****************************************************************/
+
+ 
+/**
+ * xlinkIsLink:
+ * @doc:  the document containing the node
+ * @node:  the node pointer itself
+ *
+ * Check whether the given node carries the attributes needed
+ * to be a link element (or is one of the linking elements issued
+ * from the (X)HTML DtDs).
+ * This routine don't try to do full checking of the link validity
+ * but tries to detect and return the appropriate link type.
+ *
+ * Returns the xlinkType of the node (XLINK_TYPE_NONE if there is no
+ *         link detected.
+ */
+xlinkType 
+xlinkIsLink	(xmlDocPtr doc, xmlNodePtr node) {
+    xmlChar *type = NULL, *role = NULL;
+    xlinkType ret = XLINK_TYPE_NONE;
+
+    if (node == NULL) return(XLINK_TYPE_NONE);
+    if (doc == NULL) doc = node->doc;
+    if ((doc != NULL) && (doc->type == XML_HTML_DOCUMENT_NODE)) {
+        /*
+	 * This is an HTML document.
+	 */
+    } else if ((node->ns != NULL) &&
+               (xmlStrEqual(node->ns->href, XHTML_NAMESPACE))) {
+	/*
+	 * !!!! We really need an IS_XHTML_ELEMENT function from HTMLtree.h @@@
+	 */
+        /*
+	 * This is an XHTML element within an XML document
+	 * Check whether it's one of the element able to carry links
+	 * and in that case if it holds the attributes.
+	 */
+    }
+
+    /*
+     * We don't prevent a-priori having XML Linking constructs on
+     * XHTML elements
+     */
+    type = xmlGetNsProp(node, BAD_CAST"type", XLINK_NAMESPACE);
+    if (type != NULL) {
+	if (!xmlStrEqual(type, BAD_CAST "simple")) {
+            ret = XLINK_TYPE_SIMPLE;
+	} if (!xmlStrEqual(type, BAD_CAST "extended")) {
+	    role = xmlGetNsProp(node, BAD_CAST "role", XLINK_NAMESPACE);
+	    if (role != NULL) {
+		xmlNsPtr xlink;
+		xlink = xmlSearchNs(doc, node, XLINK_NAMESPACE);
+		if (xlink == NULL) {
+		    /* Humm, fallback method */
+		    if (xmlStrEqual(role, BAD_CAST"xlink:external-linkset")) 
+			ret = XLINK_TYPE_EXTENDED_SET;
+		} else {
+		    xmlChar buf[200];
+#ifdef HAVE_SNPRINTF
+		    snprintf((char *) buf, sizeof(buf), "%s:external-linkset",
+			     (char *) xlink->prefix);
+#else
+		    sprintf((char *) buf, "%s:external-linkset",
+			    (char *) xlink->prefix);
+#endif
+                    buf[sizeof(buf) - 1] = 0;
+		    if (xmlStrEqual(role, buf))
+			ret = XLINK_TYPE_EXTENDED_SET;
+
+		}
+
+	    }
+	    ret = XLINK_TYPE_EXTENDED;
+	}
+    }
+
+    if (type != NULL) xmlFree(type);
+    if (role != NULL) xmlFree(role);
+    return(ret);
+}
diff --git a/xlink.h b/xlink.h
new file mode 100644
index 0000000..37a5415
--- /dev/null
+++ b/xlink.h
@@ -0,0 +1,182 @@
+/*
+ * xlink.h : interfaces to the hyperlinks detection module
+ *
+ * See Copyright for the status of this software.
+ *
+ * Related specification: http://www.w3.org/TR/xlink
+ *                        http://www.w3.org/HTML/
+ *     and XBase 
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XLINK_H__
+#define __XML_XLINK_H__
+
+#include <libxml/tree.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/**
+ * Various defines for the various Link properties.
+ *
+ * NOTE: the link detection layer will try to resolve QName expansion
+ *       of namespaces, if "foo" is the prefix for "http://foo.com/"
+ *       then the link detection layer will expand role="foo:myrole"
+ *       to "http://foo.com/:myrole"
+ * NOTE: the link detection layer will expand URI-Refences found on
+ *       href attributes by using the base mechanism if found.
+ */
+typedef xmlChar *xlinkHRef;
+typedef xmlChar *xlinkRole;
+typedef xmlChar *xlinkTitle;
+
+typedef enum {
+    XLINK_TYPE_NONE = 0,
+    XLINK_TYPE_SIMPLE,
+    XLINK_TYPE_EXTENDED,
+    XLINK_TYPE_EXTENDED_SET
+} xlinkType;
+
+typedef enum {
+    XLINK_SHOW_NONE = 0,
+    XLINK_SHOW_NEW,
+    XLINK_SHOW_EMBED,
+    XLINK_SHOW_REPLACE
+} xlinkShow;
+
+typedef enum {
+    XLINK_ACTUATE_NONE = 0,
+    XLINK_ACTUATE_AUTO,
+    XLINK_ACTUATE_ONREQUEST
+} xlinkActuate;
+
+/**
+ * xlinkNodeDetectFunc:
+ * @ctx:  user data pointer
+ * @node:  the node to check
+ * 
+ * This is the prototype for the link detection routine
+ * It calls the default link detection callbacks upon link detection.
+ */
+typedef void
+(*xlinkNodeDetectFunc)	(void *ctx,
+		 	 xmlNodePtr node);
+
+/**
+ * The link detection module interract with the upper layers using
+ * a set of callback registered at parsing time.
+ */
+
+/**
+ * xlinkSimpleLinkFunk:
+ * @ctx:  user data pointer
+ * @node:  the node carrying the link
+ * @href:  the target of the link
+ * @role:  the role string
+ * @title:  the link title
+ *
+ * This is the prototype for a simple link detection callback.
+ */
+typedef void
+(*xlinkSimpleLinkFunk)	(void *ctx,
+			 xmlNodePtr node,
+			 const xlinkHRef href,
+			 const xlinkRole role,
+			 const xlinkTitle title);
+
+/**
+ * xlinkExtendedLinkFunk:
+ * @ctx:  user data pointer
+ * @node:  the node carrying the link
+ * @nbLocators: the number of locators detected on the link
+ * @hrefs:  pointer to the array of locator hrefs
+ * @roles:  pointer to the array of locator roles
+ * @nbArcs: the number of arcs detected on the link
+ * @from:  pointer to the array of source roles found on the arcs
+ * @to:  pointer to the array of target roles found on the arcs
+ * @show:  array of values for the show attributes found on the arcs
+ * @actuate:  array of values for the actuate attributes found on the arcs
+ * @nbTitles: the number of titles detected on the link
+ * @title:  array of titles detected on the link
+ * @langs:  array of xml:lang values for the titles
+ *
+ * This is the prototype for a extended link detection callback.
+ */
+typedef void
+(*xlinkExtendedLinkFunk)(void *ctx,
+			 xmlNodePtr node,
+			 int nbLocators,
+			 const xlinkHRef *hrefs,
+			 const xlinkRole *roles,
+			 int nbArcs,
+			 const xlinkRole *from,
+			 const xlinkRole *to,
+			 xlinkShow *show,
+			 xlinkActuate *actuate,
+			 int nbTitles,
+			 const xlinkTitle *titles,
+			 const xmlChar **langs);
+
+/**
+ * xlinkExtendedLinkSetFunk:
+ * @ctx:  user data pointer
+ * @node:  the node carrying the link
+ * @nbLocators: the number of locators detected on the link
+ * @hrefs:  pointer to the array of locator hrefs
+ * @roles:  pointer to the array of locator roles
+ * @nbTitles: the number of titles detected on the link
+ * @title:  array of titles detected on the link
+ * @langs:  array of xml:lang values for the titles
+ *
+ * This is the prototype for a extended link set detection callback.
+ */
+typedef void
+(*xlinkExtendedLinkSetFunk)	(void *ctx,
+				 xmlNodePtr node,
+				 int nbLocators,
+				 const xlinkHRef *hrefs,
+				 const xlinkRole *roles,
+				 int nbTitles,
+				 const xlinkTitle *titles,
+				 const xmlChar **langs);
+
+/**
+ * This is the structure containing a set of Links detection callbacks
+ *
+ * There is no default xlink callbacks, if one want to get link
+ * recognition activated, those call backs must be provided before parsing.
+ */
+typedef struct _xlinkHandler xlinkHandler;
+typedef xlinkHandler *xlinkHandlerPtr;
+struct _xlinkHandler {
+    xlinkSimpleLinkFunk simple;
+    xlinkExtendedLinkFunk extended;
+    xlinkExtendedLinkSetFunk set;
+};
+
+/**
+ * the default detection routine, can be overriden, they call the default
+ * detection callbacks. 
+ */
+
+xlinkNodeDetectFunc	xlinkGetDefaultDetect	(void);
+void			xlinkSetDefaultDetect	(xlinkNodeDetectFunc func);
+
+/**
+ * Routines to set/get the default handlers.
+ */
+xlinkHandlerPtr	xlinkGetDefaultHandler	(void);
+void		xlinkSetDefaultHandler	(xlinkHandlerPtr handler);
+
+/*
+ * Link detection module itself.
+ */
+xlinkType	 xlinkIsLink		(xmlDocPtr doc,
+					 xmlNodePtr node);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XLINK_H__ */
diff --git a/xml2-config.1 b/xml2-config.1
new file mode 100644
index 0000000..8a25962
--- /dev/null
+++ b/xml2-config.1
@@ -0,0 +1,31 @@
+.TH GNOME-XML 1 "3 July 1999" Version 1.1.0
+.SH NAME
+xml-config - script to get information about the installed version of GNOME-XML
+.SH SYNOPSIS
+.B xml-config
+[\-\-prefix\fI[=DIR]\fP] [\-\-libs] [\-\-cflags] [\-\-version] [\-\-help]
+.SH DESCRIPTION
+\fIxml-config\fP is a tool that is used to determine the compile and
+linker flags that should be used to compile and link programs that use
+\fIGNOME-XML\fP.
+.SH OPTIONS
+.l
+\fIxml-config\fP accepts the following options:
+.TP 8
+.B  \-\-version
+Print the currently installed version of \fIGNOME-XML\fP on the standard output.
+.TP 8
+.B  \-\-libs
+Print the linker flags that are necessary to link a \fIGNOME-XML\fP program.
+.TP 8
+.B  \-\-cflags
+Print the compiler flags that are necessary to compile a \fIGNOME-XML\fP program.
+.TP 8
+.B  \-\-prefix=PREFIX
+If specified, use PREFIX instead of the installation prefix that
+\fIGNOME-XML\fP was built with when computing the output for the
+\-\-cflags and \-\-libs options. This option must be specified before
+any \-\-libs or \-\-cflags options.
+.SH AUTHOR
+This manual page was written by Fredrik Hallenberg <hallon@lysator.liu.se>,
+for the Debian GNU/linux system (but may be used by others).
diff --git a/xml2-config.in b/xml2-config.in
new file mode 100644
index 0000000..768e336
--- /dev/null
+++ b/xml2-config.in
@@ -0,0 +1,72 @@
+#! /bin/sh
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+includedir=@includedir@
+libdir=@libdir@
+
+usage()
+{
+    cat <<EOF
+Usage: xml-config [OPTION]
+
+Known values for OPTION are:
+
+  --prefix=DIR		change libxml prefix [default $prefix]
+  --libs		print library linking information
+  --cflags		print pre-processor and compiler flags
+  --help		display this help and exit
+  --version		output version information
+EOF
+
+    exit $1
+}
+
+if test $# -eq 0; then
+    usage 1
+fi
+
+cflags=false
+libs=false
+
+while test $# -gt 0; do
+    case "$1" in
+    -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+    *) optarg= ;;
+    esac
+
+    case "$1" in
+    --prefix=*)
+	prefix=$optarg
+	;;
+
+    --prefix)
+	echo $prefix
+	;;
+
+    --version)
+	echo @VERSION@
+	exit 0
+	;;
+
+    --help)
+	usage 0
+	;;
+
+    --cflags)
+       	echo @XML_INCLUDEDIR@ @XML_CFLAGS@
+       	;;
+
+    --libs)
+       	echo @XML_LIBDIR@ @XML_LIBS@ 
+       	;;
+
+    *)
+	usage
+	exit 1
+	;;
+    esac
+    shift
+done
+
+exit 0
diff --git a/xml2Conf.sh.in b/xml2Conf.sh.in
new file mode 100644
index 0000000..264ab0b
--- /dev/null
+++ b/xml2Conf.sh.in
@@ -0,0 +1,8 @@
+#
+# Configuration file for using the XML library in GNOME applications
+#
+XML_LIBDIR="@XML_LIBDIR@"
+XML_LIBS="@XML_LIBS@"
+XML_INCLUDEDIR="@XML_INCLUDEDIR@"
+MODULE_VERSION="xml-@VERSION@"
+
diff --git a/xmlIO.c b/xmlIO.c
new file mode 100644
index 0000000..290ceab
--- /dev/null
+++ b/xmlIO.c
@@ -0,0 +1,1743 @@
+/*
+ * xmlIO.c : implementation of the I/O interfaces used by the parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - for VMS, truncated name of long functions to under 32 char
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+
+/* Figure a portable way to know if a file is a directory. */
+#ifndef HAVE_STAT
+#  ifdef HAVE__STAT
+#    define stat(x,y) _stat(x,y)
+#    define HAVE_STAT
+#  endif
+#endif
+#ifdef HAVE_STAT
+#  ifndef S_ISDIR
+#    ifdef _S_ISDIR
+#      define S_ISDIR(x) _S_ISDIR(x)
+#    else
+#      ifdef S_IFDIR
+#        ifndef S_IFMT
+#          ifdef _S_IFMT
+#            define S_IFMT _S_IFMT
+#          endif
+#        endif
+#        ifdef S_IFMT
+#          define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#        endif
+#      endif
+#    endif
+#  endif
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/parser.h>
+#include <libxml/parserInternals.h>
+#include <libxml/xmlIO.h>
+#include <libxml/nanohttp.h>
+#include <libxml/nanoftp.h>
+#include <libxml/xmlerror.h>
+
+#ifdef VMS
+#define xmlRegisterDefaultInputCallbacks xmlRegisterDefInputCallbacks
+#define xmlRegisterDefaultOutputCallbacks xmlRegisterDefOutputCallbacks
+#endif
+
+/* #define VERBOSE_FAILURE */
+/* #define DEBUG_EXTERNAL_ENTITIES */
+/* #define DEBUG_INPUT */
+
+#ifdef DEBUG_INPUT
+#define MINLEN 40
+#else
+#define MINLEN 4000
+#endif
+
+/*
+ * Input I/O callback sets
+ */
+typedef struct _xmlInputCallback {
+    xmlInputMatchCallback matchcallback;
+    xmlInputOpenCallback opencallback;
+    xmlInputReadCallback readcallback;
+    xmlInputCloseCallback closecallback;
+} xmlInputCallback;
+
+#define MAX_INPUT_CALLBACK 15
+
+xmlInputCallback xmlInputCallbackTable[MAX_INPUT_CALLBACK];
+int xmlInputCallbackNr = 0;
+int xmlInputCallbackInitialized = 0;
+
+/*
+ * Output I/O callback sets
+ */
+typedef struct _xmlOutputCallback {
+    xmlOutputMatchCallback matchcallback;
+    xmlOutputOpenCallback opencallback;
+    xmlOutputWriteCallback writecallback;
+    xmlOutputCloseCallback closecallback;
+} xmlOutputCallback;
+
+#define MAX_OUTPUT_CALLBACK 15
+
+xmlOutputCallback xmlOutputCallbackTable[MAX_OUTPUT_CALLBACK];
+int xmlOutputCallbackNr = 0;
+int xmlOutputCallbackInitialized = 0;
+
+/************************************************************************
+ *									*
+ *		Standard I/O for file accesses				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlCheckFilename
+ * @path:  the path to check
+ *
+ * function checks to see if @path is a valid source
+ * (file, socket...) for XML.
+ *
+ * if stat is not available on the target machine,
+ * returns 1.  if stat fails, returns 0 (if calling
+ * stat on the filename fails, it can't be right).
+ * if stat succeeds and the file is a directory,
+ * sets errno to EISDIR and returns 0.  otherwise
+ * returns 1.
+ */
+
+static int
+xmlCheckFilename (const char *path)
+{
+#ifdef HAVE_STAT
+#ifdef S_ISDIR
+    struct stat stat_buffer;
+
+    if (stat(path, &stat_buffer) == -1)
+        return 0;
+
+    if (S_ISDIR(stat_buffer.st_mode)) {
+        errno = EISDIR;
+        return 0;
+    }
+
+#endif
+#endif
+    return 1;
+}
+
+int
+xmlNop(void) {
+    return(0);
+}
+
+/**
+ * xmlFdMatch:
+ * @filename:  the URI for matching
+ *
+ * input from file descriptor
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlFdMatch (const char *filename) {
+    return(1);
+}
+
+/**
+ * xmlFdOpen:
+ * @filename:  the URI for matching
+ *
+ * input from file descriptor, supports compressed input
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlFdOpen (const char *filename) {
+    const char *path = NULL;
+    int fd;
+
+    if (!strcmp(filename, "-")) {
+	fd = 0;
+	return((void *) fd);
+    }
+
+    if (!strncmp(filename, "file://localhost", 16))
+	path = &filename[16];
+    else if (!strncmp(filename, "file:///", 8))
+	path = &filename[8];
+    else if (filename[0] == '/')
+	path = filename;
+    if (path == NULL)
+	return(NULL);
+
+#ifdef WIN32
+    fd = _open (path, O_RDONLY | _O_BINARY);
+#else
+    fd = open (path, O_RDONLY);
+#endif
+
+    return((void *) fd);
+}
+
+/**
+ * xmlFdOpenW:
+ * @filename:  the URI for matching
+ *
+ * input from file descriptor,
+ * if @filename is "-" then the standard output is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlFdOpenW (const char *filename) {
+    const char *path = NULL;
+    int fd;
+
+    if (!strcmp(filename, "-")) {
+	fd = 1;
+	return((void *) fd);
+    }
+
+    if (!strncmp(filename, "file://localhost", 16))
+	path = &filename[16];
+    else if (!strncmp(filename, "file:///", 8))
+	path = &filename[8];
+    else if (filename[0] == '/')
+	path = filename;
+    if (path == NULL)
+	return(NULL);
+
+    fd = open (path, O_WRONLY);
+
+    return((void *) fd);
+}
+
+/**
+ * xmlFdRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to read
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlFdRead (void * context, char * buffer, int len) {
+    return(read((int) context, &buffer[0], len));
+}
+
+/**
+ * xmlFdWrite:
+ * @context:  the I/O context
+ * @buffer:  where to get data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlFdWrite (void * context, const char * buffer, int len) {
+    return(write((int) context, &buffer[0], len));
+}
+
+/**
+ * xmlFdClose:
+ * @context:  the I/O context
+ *
+ * Close an I/O channel
+ */
+void
+xmlFdClose (void * context) {
+    close((int) context);
+}
+
+/**
+ * xmlFileMatch:
+ * @filename:  the URI for matching
+ *
+ * input from FILE *
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlFileMatch (const char *filename) {
+    return(1);
+}
+
+/**
+ * xmlFileOpen:
+ * @filename:  the URI for matching
+ *
+ * input from FILE *, supports compressed input
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlFileOpen (const char *filename) {
+    const char *path = NULL;
+    FILE *fd;
+
+    if (!strcmp(filename, "-")) {
+	fd = stdin;
+	return((void *) fd);
+    }
+
+    if (!strncmp(filename, "file://localhost", 16))
+	path = &filename[16];
+    else if (!strncmp(filename, "file:///", 8))
+	path = &filename[8];
+    else 
+	path = filename;
+
+    if (path == NULL)
+	return(NULL);
+    if (!xmlCheckFilename(path))
+        return(NULL);
+
+#ifdef WIN32
+    fd = fopen(path, "rb");
+#else
+    fd = fopen(path, "r");
+#endif /* WIN32 */
+    return((void *) fd);
+}
+
+/**
+ * xmlFileOpenW:
+ * @filename:  the URI for matching
+ *
+ * output to from FILE *,
+ * if @filename is "-" then the standard output is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlFileOpenW (const char *filename) {
+    const char *path = NULL;
+    FILE *fd;
+
+    if (!strcmp(filename, "-")) {
+	fd = stdout;
+	return((void *) fd);
+    }
+
+    if (!strncmp(filename, "file://localhost", 16))
+	path = &filename[16];
+    else if (!strncmp(filename, "file:///", 8))
+	path = &filename[8];
+    else 
+	path = filename;
+
+    if (path == NULL)
+	return(NULL);
+
+    fd = fopen(path, "w");
+    return((void *) fd);
+}
+
+/**
+ * xmlFileRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlFileRead (void * context, char * buffer, int len) {
+    return(fread(&buffer[0], 1,  len, (FILE *) context));
+}
+
+/**
+ * xmlFileWrite:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlFileWrite (void * context, const char * buffer, int len) {
+    return(fwrite(&buffer[0], 1,  len, (FILE *) context));
+}
+
+/**
+ * xmlFileClose:
+ * @context:  the I/O context
+ *
+ * Close an I/O channel
+ */
+void
+xmlFileClose (void * context) {
+    fclose((FILE *) context);
+}
+
+/**
+ * xmlFileFlush:
+ * @context:  the I/O context
+ *
+ * Flush an I/O channel
+ */
+void
+xmlFileFlush (void * context) {
+    fflush((FILE *) context);
+}
+
+#ifdef HAVE_ZLIB_H
+/************************************************************************
+ *									*
+ *		I/O for compressed file accesses			*
+ *									*
+ ************************************************************************/
+/**
+ * xmlGzfileMatch:
+ * @filename:  the URI for matching
+ *
+ * input from compressed file test
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlGzfileMatch (const char *filename) {
+    return(1);
+}
+
+/**
+ * xmlGzfileOpen:
+ * @filename:  the URI for matching
+ *
+ * input from compressed file open
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlGzfileOpen (const char *filename) {
+    const char *path = NULL;
+    gzFile fd;
+
+    if (!strcmp(filename, "-")) {
+        fd = gzdopen(fileno(stdin), "rb");
+	return((void *) fd);
+    }
+
+    if (!strncmp(filename, "file://localhost", 16))
+	path = &filename[16];
+    else if (!strncmp(filename, "file:///", 8))
+	path = &filename[7];
+    else 
+	path = filename;
+
+    if (path == NULL)
+	return(NULL);
+    if (!xmlCheckFilename(path))
+        return(NULL);
+
+    fd = gzopen(path, "rb");
+    return((void *) fd);
+}
+
+/**
+ * xmlGzfileOpenW:
+ * @filename:  the URI for matching
+ * @compression:  the compression factor (0 - 9 included)
+ *
+ * input from compressed file open
+ * if @filename is " " then the standard input is used
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlGzfileOpenW (const char *filename, int compression) {
+    const char *path = NULL;
+    char mode[15];
+    gzFile fd;
+
+    sprintf(mode, "wb%d", compression);
+    if (!strcmp(filename, "-")) {
+        fd = gzdopen(1, mode);
+	return((void *) fd);
+    }
+
+    if (!strncmp(filename, "file://localhost", 16))
+	path = &filename[16];
+    else if (!strncmp(filename, "file:///", 8))
+	path = &filename[8];
+    else 
+	path = filename;
+
+    if (path == NULL)
+	return(NULL);
+
+    fd = gzopen(path, mode);
+    return((void *) fd);
+}
+
+/**
+ * xmlGzfileRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the compressed I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlGzfileRead (void * context, char * buffer, int len) {
+    return(gzread((gzFile) context, &buffer[0], len));
+}
+
+/**
+ * xmlGzfileWrite:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Write @len bytes from @buffer to the compressed I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int
+xmlGzfileWrite (void * context, const char * buffer, int len) {
+    return(gzwrite((gzFile) context, (char *) &buffer[0], len));
+}
+
+/**
+ * xmlGzfileClose:
+ * @context:  the I/O context
+ *
+ * Close a compressed I/O channel
+ */
+void
+xmlGzfileClose (void * context) {
+    gzclose((gzFile) context);
+}
+#endif /* HAVE_ZLIB_H */
+
+#ifdef LIBXML_HTTP_ENABLED
+/************************************************************************
+ *									*
+ *			I/O for HTTP file accesses			*
+ *									*
+ ************************************************************************/
+/**
+ * xmlIOHTTPMatch:
+ * @filename:  the URI for matching
+ *
+ * check if the URI matches an HTTP one
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlIOHTTPMatch (const char *filename) {
+    if (!strncmp(filename, "http://", 7))
+	return(1);
+    return(0);
+}
+
+/**
+ * xmlIOHTTPOpen:
+ * @filename:  the URI for matching
+ *
+ * open an HTTP I/O channel
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlIOHTTPOpen (const char *filename) {
+    return(xmlNanoHTTPOpen(filename, NULL));
+}
+
+/**
+ * xmlIOHTTPRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int 
+xmlIOHTTPRead(void * context, char * buffer, int len) {
+    return(xmlNanoHTTPRead(context, &buffer[0], len));
+}
+
+/**
+ * xmlIOHTTPClose:
+ * @context:  the I/O context
+ *
+ * Close an HTTP I/O channel
+ */
+void
+xmlIOHTTPClose (void * context) {
+    xmlNanoHTTPClose(context);
+}
+#endif /* LIBXML_HTTP_ENABLED */
+
+#ifdef LIBXML_FTP_ENABLED
+/************************************************************************
+ *									*
+ *			I/O for FTP file accesses			*
+ *									*
+ ************************************************************************/
+/**
+ * xmlIOFTPMatch:
+ * @filename:  the URI for matching
+ *
+ * check if the URI matches an FTP one
+ *
+ * Returns 1 if matches, 0 otherwise
+ */
+int
+xmlIOFTPMatch (const char *filename) {
+    if (!strncmp(filename, "ftp://", 6))
+	return(1);
+    return(0);
+}
+
+/**
+ * xmlIOFTPOpen:
+ * @filename:  the URI for matching
+ *
+ * open an FTP I/O channel
+ *
+ * Returns an I/O context or NULL in case of error
+ */
+void *
+xmlIOFTPOpen (const char *filename) {
+    return(xmlNanoFTPOpen(filename));
+}
+
+/**
+ * xmlIOFTPRead:
+ * @context:  the I/O context
+ * @buffer:  where to drop data
+ * @len:  number of bytes to write
+ *
+ * Read @len bytes to @buffer from the I/O channel.
+ *
+ * Returns the number of bytes written
+ */
+int 
+xmlIOFTPRead(void * context, char * buffer, int len) {
+    return(xmlNanoFTPRead(context, &buffer[0], len));
+}
+
+/**
+ * xmlIOFTPClose:
+ * @context:  the I/O context
+ *
+ * Close an FTP I/O channel
+ */
+void
+xmlIOFTPClose (void * context) {
+    xmlNanoFTPClose(context);
+}
+#endif /* LIBXML_FTP_ENABLED */
+
+
+/**
+ * xmlRegisterInputCallbacks:
+ * @match:  the xmlInputMatchCallback
+ * @open:  the xmlInputOpenCallback
+ * @read:  the xmlInputReadCallback
+ * @close:  the xmlInputCloseCallback
+ *
+ * Register a new set of I/O callback for handling parser input.
+ *
+ * Returns the registered handler number or -1 in case of error
+ */
+int
+xmlRegisterInputCallbacks(xmlInputMatchCallback match,
+	xmlInputOpenCallback open, xmlInputReadCallback read,
+	xmlInputCloseCallback close) {
+    if (xmlInputCallbackNr >= MAX_INPUT_CALLBACK) {
+	return(-1);
+    }
+    xmlInputCallbackTable[xmlInputCallbackNr].matchcallback = match;
+    xmlInputCallbackTable[xmlInputCallbackNr].opencallback = open;
+    xmlInputCallbackTable[xmlInputCallbackNr].readcallback = read;
+    xmlInputCallbackTable[xmlInputCallbackNr].closecallback = close;
+    return(xmlInputCallbackNr++);
+}
+
+/**
+ * xmlRegisterOutputCallbacks:
+ * @match:  the xmlOutputMatchCallback
+ * @open:  the xmlOutputOpenCallback
+ * @write:  the xmlOutputWriteCallback
+ * @close:  the xmlOutputCloseCallback
+ *
+ * Register a new set of I/O callback for handling output.
+ *
+ * Returns the registered handler number or -1 in case of error
+ */
+int
+xmlRegisterOutputCallbacks(xmlOutputMatchCallback match,
+	xmlOutputOpenCallback open, xmlOutputWriteCallback write,
+	xmlOutputCloseCallback close) {
+    if (xmlOutputCallbackNr >= MAX_INPUT_CALLBACK) {
+	return(-1);
+    }
+    xmlOutputCallbackTable[xmlOutputCallbackNr].matchcallback = match;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].opencallback = open;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].writecallback = write;
+    xmlOutputCallbackTable[xmlOutputCallbackNr].closecallback = close;
+    return(xmlOutputCallbackNr++);
+}
+
+/**
+ * xmlRegisterDefaultInputCallbacks:
+ *
+ * Registers the default compiled-in I/O handlers.
+ */
+void
+#ifdef VMS
+xmlRegisterDefInputCallbacks
+#else
+xmlRegisterDefaultInputCallbacks
+#endif
+(void) {
+    if (xmlInputCallbackInitialized)
+	return;
+
+    xmlRegisterInputCallbacks(xmlFileMatch, xmlFileOpen,
+	                      xmlFileRead, xmlFileClose);
+#ifdef HAVE_ZLIB_H
+    xmlRegisterInputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
+	                      xmlGzfileRead, xmlGzfileClose);
+#endif /* HAVE_ZLIB_H */
+
+#ifdef LIBXML_HTTP_ENABLED
+    xmlRegisterInputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
+	                      xmlIOHTTPRead, xmlIOHTTPClose);
+#endif /* LIBXML_HTTP_ENABLED */
+
+#ifdef LIBXML_FTP_ENABLED
+    xmlRegisterInputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
+	                      xmlIOFTPRead, xmlIOFTPClose);
+#endif /* LIBXML_FTP_ENABLED */
+    xmlInputCallbackInitialized = 1;
+}
+
+/**
+ * xmlRegisterDefaultOutputCallbacks:
+ *
+ * Registers the default compiled-in I/O handlers.
+ */
+void
+#ifdef VMS
+xmlRegisterDefOutputCallbacks
+#else
+xmlRegisterDefaultOutputCallbacks
+#endif
+(void) {
+    if (xmlOutputCallbackInitialized)
+	return;
+
+    xmlRegisterOutputCallbacks(xmlFileMatch, xmlFileOpenW,
+	                      xmlFileWrite, xmlFileClose);
+/*********************************
+ No way a-priori to distinguish between gzipped files from
+ uncompressed ones except opening if existing then closing
+ and saving with same compression ratio ... a pain.
+
+#ifdef HAVE_ZLIB_H
+    xmlRegisterOutputCallbacks(xmlGzfileMatch, xmlGzfileOpen,
+	                       xmlGzfileWrite, xmlGzfileClose);
+#endif
+ No HTTP PUT support yet, patches welcome
+
+#ifdef LIBXML_HTTP_ENABLED
+    xmlRegisterOutputCallbacks(xmlIOHTTPMatch, xmlIOHTTPOpen,
+	                       xmlIOHTTPWrite, xmlIOHTTPClose);
+#endif
+
+ Nor FTP PUT ....
+#ifdef LIBXML_FTP_ENABLED
+    xmlRegisterOutputCallbacks(xmlIOFTPMatch, xmlIOFTPOpen,
+	                       xmlIOFTPWrite, xmlIOFTPClose);
+#endif
+ **********************************/
+    xmlOutputCallbackInitialized = 1;
+}
+
+/**
+ * xmlAllocParserInputBuffer:
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for progressive parsing
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlAllocParserInputBuffer(xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    ret = (xmlParserInputBufferPtr) xmlMalloc(sizeof(xmlParserInputBuffer));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAllocParserInputBuffer : out of memory!\n");
+	return(NULL);
+    }
+    memset(ret, 0, (size_t) sizeof(xmlParserInputBuffer));
+    ret->buffer = xmlBufferCreate();
+    if (ret->buffer == NULL) {
+        xmlFree(ret);
+	return(NULL);
+    }
+    ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
+    ret->encoder = xmlGetCharEncodingHandler(enc);
+    if (ret->encoder != NULL)
+        ret->raw = xmlBufferCreate();
+    else
+        ret->raw = NULL;
+    ret->readcallback = NULL;
+    ret->closecallback = NULL;
+    ret->context = NULL;
+
+    return(ret);
+}
+
+/**
+ * xmlAllocOutputBuffer:
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered parser output
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlAllocOutputBuffer(xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    ret = (xmlOutputBufferPtr) xmlMalloc(sizeof(xmlOutputBuffer));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlAllocOutputBuffer : out of memory!\n");
+	return(NULL);
+    }
+    memset(ret, 0, (size_t) sizeof(xmlOutputBuffer));
+    ret->buffer = xmlBufferCreate();
+    if (ret->buffer == NULL) {
+        xmlFree(ret);
+	return(NULL);
+    }
+    ret->buffer->alloc = XML_BUFFER_ALLOC_DOUBLEIT;
+    ret->encoder = encoder;
+    if (encoder != NULL) {
+        ret->conv = xmlBufferCreateSize(4000);
+	/*
+	 * This call is designed to initiate the encoder state
+	 */
+	xmlCharEncOutFunc(encoder, ret->conv, NULL); 
+    } else
+        ret->conv = NULL;
+    ret->writecallback = NULL;
+    ret->closecallback = NULL;
+    ret->context = NULL;
+    ret->written = 0;
+
+    return(ret);
+}
+
+/**
+ * xmlFreeParserInputBuffer:
+ * @in:  a buffered parser input
+ *
+ * Free up the memory used by a buffered parser input
+ */
+void
+xmlFreeParserInputBuffer(xmlParserInputBufferPtr in) {
+    if (in->raw) {
+        xmlBufferFree(in->raw);
+	in->raw = NULL;
+    }
+    if (in->encoder != NULL) {
+        xmlCharEncCloseFunc(in->encoder);
+    }
+    if (in->closecallback != NULL) {
+	in->closecallback(in->context);
+    }
+    if (in->buffer != NULL) {
+        xmlBufferFree(in->buffer);
+	in->buffer = NULL;
+    }
+
+    memset(in, 0xbe, (size_t) sizeof(xmlParserInputBuffer));
+    xmlFree(in);
+}
+
+/**
+ * xmlOutputBufferClose:
+ * @out:  a buffered output
+ *
+ * flushes and close the output I/O channel
+ * and free up all the associated resources
+ *
+ * Returns the number of byte written or -1 in case of error.
+ */
+int
+xmlOutputBufferClose(xmlOutputBufferPtr out) {
+    int written;
+
+    if (out == NULL)
+        return(-1);
+    if (out->writecallback != NULL)
+	xmlOutputBufferFlush(out);
+    if (out->closecallback != NULL) {
+	out->closecallback(out->context);
+    }
+    written = out->written;
+    if (out->conv) {
+        xmlBufferFree(out->conv);
+	out->conv = NULL;
+    }
+    if (out->encoder != NULL) {
+        xmlCharEncCloseFunc(out->encoder);
+    }
+    if (out->buffer != NULL) {
+        xmlBufferFree(out->buffer);
+	out->buffer = NULL;
+    }
+
+    memset(out, 0xbe, (size_t) sizeof(xmlOutputBuffer));
+    xmlFree(out);
+    return(written);
+}
+
+/**
+ * xmlParserInputBufferCreateFilename:
+ * @URI:  a C string containing the URI or filename
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing of a file
+ * If filename is "-' then we use stdin as the input.
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ * Do an encoding check if enc == XML_CHAR_ENCODING_NONE
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+#ifdef VMS
+xmlParserInputBufferCreateFname
+#else
+xmlParserInputBufferCreateFilename
+#endif
+(const char *URI, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+    int i;
+    void *context = NULL;
+
+    if (xmlInputCallbackInitialized == 0)
+	xmlRegisterDefaultInputCallbacks();
+
+    if (URI == NULL) return(NULL);
+
+    /*
+     * Try to find one of the input accept method accepting taht scheme
+     * Go in reverse to give precedence to user defined handlers.
+     */
+    for (i = xmlInputCallbackNr - 1;i >= 0;i--) {
+	if ((xmlInputCallbackTable[i].matchcallback != NULL) &&
+	    (xmlInputCallbackTable[i].matchcallback(URI) != 0)) {
+	    context = xmlInputCallbackTable[i].opencallback(URI);
+	    if (context != NULL)
+		break;
+	}
+    }
+    if (context == NULL) {
+	return(NULL);
+    }
+
+    /*
+     * Allocate the Input buffer front-end.
+     */
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+	ret->context = context;
+	ret->readcallback = xmlInputCallbackTable[i].readcallback;
+	ret->closecallback = xmlInputCallbackTable[i].closecallback;
+    }
+    return(ret);
+}
+
+/**
+ * xmlOutputBufferCreateFilename:
+ * @URI:  a C string containing the URI or filename
+ * @encoder:  the encoding converter or NULL
+ * @compression:  the compression ration (0 none, 9 max).
+ *
+ * Create a buffered  output for the progressive saving of a file
+ * If filename is "-' then we use stdout as the output.
+ * Automatic support for ZLIB/Compress compressed document is provided
+ * by default if found at compile-time.
+ * TODO: currently if compression is set, the library only support
+ *       writing to a local file.
+ *
+ * Returns the new output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateFilename(const char *URI,
+                              xmlCharEncodingHandlerPtr encoder,
+			      int compression) {
+    xmlOutputBufferPtr ret;
+    int i;
+    void *context = NULL;
+
+    if (xmlOutputCallbackInitialized == 0)
+	xmlRegisterDefaultOutputCallbacks();
+
+    if (URI == NULL) return(NULL);
+
+#ifdef HAVE_ZLIB_H
+    if ((compression > 0) && (compression <= 9)) {
+        context = xmlGzfileOpenW(URI, compression);
+	if (context != NULL) {
+	    ret = xmlAllocOutputBuffer(encoder);
+	    if (ret != NULL) {
+		ret->context = context;
+		ret->writecallback = xmlGzfileWrite;
+		ret->closecallback = xmlGzfileClose;
+	    }
+	    return(ret);
+	}
+    }
+#endif
+
+    /*
+     * Try to find one of the output accept method accepting taht scheme
+     * Go in reverse to give precedence to user defined handlers.
+     */
+    for (i = xmlOutputCallbackNr - 1;i >= 0;i--) {
+	if ((xmlOutputCallbackTable[i].matchcallback != NULL) &&
+	    (xmlOutputCallbackTable[i].matchcallback(URI) != 0)) {
+	    context = xmlOutputCallbackTable[i].opencallback(URI);
+	    if (context != NULL)
+		break;
+	}
+    }
+    if (context == NULL) {
+	return(NULL);
+    }
+
+    /*
+     * Allocate the Output buffer front-end.
+     */
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+	ret->context = context;
+	ret->writecallback = xmlOutputCallbackTable[i].writecallback;
+	ret->closecallback = xmlOutputCallbackTable[i].closecallback;
+    }
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferCreateFile:
+ * @file:  a FILE* 
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing of a FILE *
+ * buffered C I/O
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateFile(FILE *file, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (xmlInputCallbackInitialized == 0)
+	xmlRegisterDefaultInputCallbacks();
+
+    if (file == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = file;
+	ret->readcallback = xmlFileRead;
+	ret->closecallback = xmlFileFlush;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlOutputBufferCreateFile:
+ * @file:  a FILE* 
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered output for the progressive saving to a FILE *
+ * buffered C I/O
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateFile(FILE *file, xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (xmlOutputCallbackInitialized == 0)
+	xmlRegisterDefaultOutputCallbacks();
+
+    if (file == NULL) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = file;
+	ret->writecallback = xmlFileWrite;
+	ret->closecallback = xmlFileFlush;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferCreateFd:
+ * @fd:  a file descriptor number
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from a file descriptor
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateFd(int fd, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (fd < 0) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = (void *) fd;
+	ret->readcallback = xmlFdRead;
+	ret->closecallback = xmlFdClose;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferCreateMem:
+ * @mem:  the memory input
+ * @size:  the length of the memory block
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from a memory area.
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateMem(const char *mem, int size, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (size <= 0) return(NULL);
+    if (mem == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = (void *) mem;
+	ret->readcallback = (xmlInputReadCallback) xmlNop;
+	ret->closecallback = NULL;
+	xmlBufferAdd(ret->buffer, (const xmlChar *) mem, size);
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlOutputBufferCreateFd:
+ * @fd:  a file descriptor number
+ * @encoder:  the encoding converter or NULL
+ *
+ * Create a buffered output for the progressive saving 
+ * to a file descriptor
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateFd(int fd, xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (fd < 0) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = (void *) fd;
+	ret->writecallback = xmlFdWrite;
+	ret->closecallback = xmlFdClose;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferCreateIO:
+ * @ioread:  an I/O read function
+ * @ioclose:  an I/O close function
+ * @ioctx:  an I/O handler
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered parser input for the progressive parsing for the input
+ * from an I/O handler
+ *
+ * Returns the new parser input or NULL
+ */
+xmlParserInputBufferPtr
+xmlParserInputBufferCreateIO(xmlInputReadCallback   ioread,
+	 xmlInputCloseCallback  ioclose, void *ioctx, xmlCharEncoding enc) {
+    xmlParserInputBufferPtr ret;
+
+    if (ioread == NULL) return(NULL);
+
+    ret = xmlAllocParserInputBuffer(enc);
+    if (ret != NULL) {
+        ret->context = (void *) ioctx;
+	ret->readcallback = ioread;
+	ret->closecallback = ioclose;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlOutputBufferCreateIO:
+ * @iowrite:  an I/O write function
+ * @ioclose:  an I/O close function
+ * @ioctx:  an I/O handler
+ * @enc:  the charset encoding if known
+ *
+ * Create a buffered output for the progressive saving
+ * to an I/O handler
+ *
+ * Returns the new parser output or NULL
+ */
+xmlOutputBufferPtr
+xmlOutputBufferCreateIO(xmlOutputWriteCallback   iowrite,
+	 xmlOutputCloseCallback  ioclose, void *ioctx,
+	 xmlCharEncodingHandlerPtr encoder) {
+    xmlOutputBufferPtr ret;
+
+    if (iowrite == NULL) return(NULL);
+
+    ret = xmlAllocOutputBuffer(encoder);
+    if (ret != NULL) {
+        ret->context = (void *) ioctx;
+	ret->writecallback = iowrite;
+	ret->closecallback = ioclose;
+    }
+
+    return(ret);
+}
+
+/**
+ * xmlParserInputBufferPush:
+ * @in:  a buffered parser input
+ * @len:  the size in bytes of the array.
+ * @buf:  an char array
+ *
+ * Push the content of the arry in the input buffer
+ * This routine handle the I18N transcoding to internal UTF-8
+ * This is used when operating the parser in progressive (push) mode.
+ *
+ * Returns the number of chars read and stored in the buffer, or -1
+ *         in case of error.
+ */
+int
+xmlParserInputBufferPush(xmlParserInputBufferPtr in,
+	                 int len, const char *buf) {
+    int nbchars = 0;
+
+    if (len < 0) return(0);
+    if (in->encoder != NULL) {
+        /*
+	 * Store the data in the incoming raw buffer
+	 */
+        if (in->raw == NULL) {
+	    in->raw = xmlBufferCreate();
+	}
+	xmlBufferAdd(in->raw, (const xmlChar *) buf, len);
+
+	/*
+	 * convert as much as possible to the parser reading buffer.
+	 */
+	nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
+	if (nbchars < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlParserInputBufferPush: encoder error\n");
+	    return(-1);
+	}
+    } else {
+	nbchars = len;
+        xmlBufferAdd(in->buffer, (xmlChar *) buf, nbchars);
+    }
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+	    "I/O: pushed %d chars, buffer %d/%d\n",
+            nbchars, in->buffer->use, in->buffer->size);
+#endif
+    return(nbchars);
+}
+
+/**
+ * xmlParserInputBufferGrow:
+ * @in:  a buffered parser input
+ * @len:  indicative value of the amount of chars to read
+ *
+ * Grow up the content of the input buffer, the old data are preserved
+ * This routine handle the I18N transcoding to internal UTF-8
+ * This routine is used when operating the parser in normal (pull) mode
+ *
+ * TODO: one should be able to remove one extra copy by copying directy
+ *       onto in->buffer or in->raw
+ *
+ * Returns the number of chars read and stored in the buffer, or -1
+ *         in case of error.
+ */
+int
+xmlParserInputBufferGrow(xmlParserInputBufferPtr in, int len) {
+    char *buffer = NULL;
+    int res = 0;
+    int nbchars = 0;
+    int buffree;
+
+    if ((len <= MINLEN) && (len != 4)) 
+        len = MINLEN;
+    buffree = in->buffer->size - in->buffer->use;
+    if (buffree <= 0) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlParserInputBufferGrow : buffer full !\n");
+	return(0);
+    }
+    if (len > buffree) 
+        len = buffree;
+
+    buffer = (char *) xmlMalloc((len + 1) * sizeof(char));
+    if (buffer == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlParserInputBufferGrow : out of memory !\n");
+	return(-1);
+    }
+
+    /*
+     * Call the read method for this I/O type.
+     */
+    if (in->readcallback != NULL) {
+	res = in->readcallback(in->context, &buffer[0], len);
+    } else {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlParserInputBufferGrow : no input !\n");
+	xmlFree(buffer);
+	return(-1);
+    }
+    if (res < 0) {
+	perror ("read error");
+	xmlFree(buffer);
+	return(-1);
+    }
+    len = res;
+    if (in->encoder != NULL) {
+        /*
+	 * Store the data in the incoming raw buffer
+	 */
+        if (in->raw == NULL) {
+	    in->raw = xmlBufferCreate();
+	}
+	xmlBufferAdd(in->raw, (const xmlChar *) buffer, len);
+
+	/*
+	 * convert as much as possible to the parser reading buffer.
+	 */
+	nbchars = xmlCharEncInFunc(in->encoder, in->buffer, in->raw);
+	if (nbchars < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlParserInputBufferGrow: encoder error\n");
+	    return(-1);
+	}
+    } else {
+	nbchars = len;
+        buffer[nbchars] = 0;
+        xmlBufferAdd(in->buffer, (xmlChar *) buffer, nbchars);
+    }
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+	    "I/O: read %d chars, buffer %d/%d\n",
+            nbchars, in->buffer->use, in->buffer->size);
+#endif
+    xmlFree(buffer);
+    return(nbchars);
+}
+
+/**
+ * xmlParserInputBufferRead:
+ * @in:  a buffered parser input
+ * @len:  indicative value of the amount of chars to read
+ *
+ * Refresh the content of the input buffer, the old data are considered
+ * consumed
+ * This routine handle the I18N transcoding to internal UTF-8
+ *
+ * Returns the number of chars read and stored in the buffer, or -1
+ *         in case of error.
+ */
+int
+xmlParserInputBufferRead(xmlParserInputBufferPtr in, int len) {
+    /* xmlBufferEmpty(in->buffer); */
+    if (in->readcallback != NULL)
+	return(xmlParserInputBufferGrow(in, len));
+    else
+        return(-1);
+}
+
+/**
+ * xmlOutputBufferWrite:
+ * @out:  a buffered parser output
+ * @len:  the size in bytes of the array.
+ * @buf:  an char array
+ *
+ * Write the content of the array in the output I/O buffer
+ * This routine handle the I18N transcoding from internal UTF-8
+ * The buffer is lossless, i.e. will store in case of partial
+ * or delayed writes.
+ *
+ * Returns the number of chars immediately written, or -1
+ *         in case of error.
+ */
+int
+xmlOutputBufferWrite(xmlOutputBufferPtr out, int len, const char *buf) {
+    int nbchars = 0; /* number of chars to output to I/O */
+    int ret;         /* return from function call */
+    int written = 0; /* number of char written to I/O so far */
+    int chunk;       /* number of byte curreent processed from buf */
+
+    if (len < 0) return(0);
+
+    do {
+	chunk = len;
+	if (chunk > 4 * MINLEN)
+	    chunk = 4 * MINLEN;
+
+	/*
+	 * first handle encoding stuff.
+	 */
+	if (out->encoder != NULL) {
+	    /*
+	     * Store the data in the incoming raw buffer
+	     */
+	    if (out->conv == NULL) {
+		out->conv = xmlBufferCreate();
+	    }
+	    xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
+
+	    if ((out->buffer->use < MINLEN) && (chunk == len))
+		goto done;
+
+	    /*
+	     * convert as much as possible to the parser reading buffer.
+	     */
+	    ret = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
+	    if (ret < 0) {
+		xmlGenericError(xmlGenericErrorContext,
+			"xmlOutputBufferWrite: encoder error\n");
+		return(-1);
+	    }
+	    nbchars = out->conv->use;
+	} else {
+	    xmlBufferAdd(out->buffer, (const xmlChar *) buf, chunk);
+	    nbchars = out->buffer->use;
+	}
+	buf += chunk;
+	len -= chunk;
+
+	if ((nbchars < MINLEN) && (len <= 0))
+	    goto done;
+
+	if (out->writecallback) {
+	    /*
+	     * second write the stuff to the I/O channel
+	     */
+	    if (out->encoder != NULL) {
+		ret = out->writecallback(out->context, 
+				 (const char *)out->conv->content, nbchars);
+		if (ret >= 0)
+		    xmlBufferShrink(out->conv, nbchars);
+	    } else {
+		ret = out->writecallback(out->context, 
+				 (const char *)out->buffer->content, nbchars);
+		if (ret >= 0)
+		    xmlBufferShrink(out->buffer, nbchars);
+	    }
+	    if (ret < 0) {
+		xmlGenericError(xmlGenericErrorContext,
+			"I/O: error %d writing %d bytes\n", ret, nbchars);
+		return(ret);
+	    }
+	    out->written += ret;
+	}
+	written += nbchars;
+    } while (len > 0);
+
+done:
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+	    "I/O: wrote %d chars\n", written);
+#endif
+    return(written);
+}
+
+/**
+ * xmlOutputBufferWriteString:
+ * @out:  a buffered parser output
+ * @str:  a zero terminated C string
+ *
+ * Write the content of the string in the output I/O buffer
+ * This routine handle the I18N transcoding from internal UTF-8
+ * The buffer is lossless, i.e. will store in case of partial
+ * or delayed writes.
+ *
+ * Returns the number of chars immediately written, or -1
+ *         in case of error.
+ */
+int
+xmlOutputBufferWriteString(xmlOutputBufferPtr out, const char *str) {
+    int len;
+    
+    if (str == NULL)
+        return(-1);
+    len = strlen(str);
+
+    if (len > 0)
+	return(xmlOutputBufferWrite(out, len, str));
+    return(len);
+}
+
+/**
+ * xmlOutputBufferFlush:
+ * @out:  a buffered output
+ *
+ * flushes the output I/O channel
+ *
+ * Returns the number of byte written or -1 in case of error.
+ */
+int
+xmlOutputBufferFlush(xmlOutputBufferPtr out) {
+    int nbchars = 0, ret = 0;
+
+    /*
+     * first handle encoding stuff.
+     */
+    if ((out->conv != NULL) && (out->encoder != NULL)) {
+	/*
+	 * convert as much as possible to the parser reading buffer.
+	 */
+	nbchars = xmlCharEncOutFunc(out->encoder, out->conv, out->buffer);
+	if (nbchars < 0) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlOutputBufferWrite: encoder error\n");
+	    return(-1);
+	}
+    }
+
+    /*
+     * second flush the stuff to the I/O channel
+     */
+    if ((out->conv != NULL) && (out->encoder != NULL) &&
+	(out->writecallback != NULL)) {
+	ret = out->writecallback(out->context,
+	           (const char *)out->conv->content, out->conv->use);
+	if (ret >= 0)
+	    xmlBufferShrink(out->conv, ret);
+    } else if (out->writecallback != NULL) {
+	ret = out->writecallback(out->context,
+	           (const char *)out->buffer->content, out->buffer->use);
+	if (ret >= 0)
+	    xmlBufferShrink(out->buffer, ret);
+    }
+    if (ret < 0) {
+        xmlGenericError(xmlGenericErrorContext,
+		"I/O: error %d flushing %d bytes\n", ret, nbchars);
+	return(ret);
+    }
+    out->written += ret;
+
+#ifdef DEBUG_INPUT
+    xmlGenericError(xmlGenericErrorContext,
+	    "I/O: flushed %d chars\n", ret);
+#endif
+    return(ret);
+}
+
+/*
+ * xmlParserGetDirectory:
+ * @filename:  the path to a file
+ *
+ * lookup the directory for that file
+ *
+ * Returns a new allocated string containing the directory, or NULL.
+ */
+char *
+xmlParserGetDirectory(const char *filename) {
+    char *ret = NULL;
+    char dir[1024];
+    char *cur;
+    char sep = '/';
+
+    if (xmlInputCallbackInitialized == 0)
+	xmlRegisterDefaultInputCallbacks();
+
+    if (filename == NULL) return(NULL);
+#ifdef WIN32
+    sep = '\\';
+#endif
+
+    strncpy(dir, filename, 1023);
+    dir[1023] = 0;
+    cur = &dir[strlen(dir)];
+    while (cur > dir) {
+         if (*cur == sep) break;
+	 cur --;
+    }
+    if (*cur == sep) {
+        if (cur == dir) dir[1] = 0;
+	else *cur = 0;
+	ret = xmlMemStrdup(dir);
+    } else {
+        if (getcwd(dir, 1024) != NULL) {
+	    dir[1023] = 0;
+	    ret = xmlMemStrdup(dir);
+	}
+    }
+    return(ret);
+}
+
+/****************************************************************
+ *								*
+ *		External entities loading			*
+ *								*
+ ****************************************************************/
+
+/*
+ * xmlDefaultExternalEntityLoader:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * By default we don't load external entitites, yet.
+ *
+ * Returns a new allocated xmlParserInputPtr, or NULL.
+ */
+static
+xmlParserInputPtr
+xmlDefaultExternalEntityLoader(const char *URL, const char *ID,
+                               xmlParserCtxtPtr ctxt) {
+    xmlParserInputPtr ret = NULL;
+
+#ifdef DEBUG_EXTERNAL_ENTITIES
+    xmlGenericError(xmlGenericErrorContext,
+	    "xmlDefaultExternalEntityLoader(%s, xxx)\n", URL);
+#endif
+    if (URL == NULL) {
+        if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	    ctxt->sax->warning(ctxt,
+		    "failed to load external entity \"%s\"\n", ID);
+        return(NULL);
+    }
+    ret = xmlNewInputFromFile(ctxt, URL);
+    if (ret == NULL) {
+        if ((ctxt->sax != NULL) && (ctxt->sax->warning != NULL))
+	    ctxt->sax->warning(ctxt,
+		    "failed to load external entity \"%s\"\n", URL);
+    }
+    return(ret);
+}
+
+static xmlExternalEntityLoader xmlCurrentExternalEntityLoader =
+       xmlDefaultExternalEntityLoader;
+
+/*
+ * xmlSetExternalEntityLoader:
+ * @f:  the new entity resolver function
+ *
+ * Changes the defaultexternal entity resolver function for the application
+ */
+void
+xmlSetExternalEntityLoader(xmlExternalEntityLoader f) {
+    xmlCurrentExternalEntityLoader = f;
+}
+
+/*
+ * xmlGetExternalEntityLoader:
+ *
+ * Get the default external entity resolver function for the application
+ *
+ * Returns the xmlExternalEntityLoader function pointer
+ */
+xmlExternalEntityLoader
+xmlGetExternalEntityLoader(void) {
+    return(xmlCurrentExternalEntityLoader);
+}
+
+/*
+ * xmlLoadExternalEntity:
+ * @URL:  the URL for the entity to load
+ * @ID:  the System ID for the entity to load
+ * @ctxt:  the context in which the entity is called or NULL
+ *
+ * Load an external entity, note that the use of this function for
+ * unparsed entities may generate problems
+ * TODO: a more generic External entitiy API must be designed
+ *
+ * Returns the xmlParserInputPtr or NULL
+ */
+xmlParserInputPtr
+xmlLoadExternalEntity(const char *URL, const char *ID,
+                      xmlParserCtxtPtr ctxt) {
+    return(xmlCurrentExternalEntityLoader(URL, ID, ctxt));
+}
+
diff --git a/xmlIO.h b/xmlIO.h
new file mode 100644
index 0000000..ecff73b
--- /dev/null
+++ b/xmlIO.h
@@ -0,0 +1,178 @@
+/*
+ * xmlIO.h : interface for the I/O interfaces used by the parser
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ *
+ * 15 Nov 2000 ht - modified for VMS
+ */
+
+#ifndef __XML_IO_H__
+#define __XML_IO_H__
+
+#include <stdio.h>
+#include <libxml/tree.h>
+#include <libxml/parser.h>
+#include <libxml/encoding.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Those are the functions and datatypes for the parser input
+ * I/O structures.
+ */
+
+typedef int (*xmlInputMatchCallback) (char const *filename);
+typedef void * (*xmlInputOpenCallback) (char const *filename);
+typedef int (*xmlInputReadCallback) (void * context, char * buffer, int len);
+typedef void (*xmlInputCloseCallback) (void * context);
+
+typedef struct _xmlParserInputBuffer xmlParserInputBuffer;
+typedef xmlParserInputBuffer *xmlParserInputBufferPtr;
+struct _xmlParserInputBuffer {
+    void*                  context;
+    xmlInputReadCallback   readcallback;
+    xmlInputCloseCallback  closecallback;
+    
+    xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */
+    
+    xmlBufferPtr buffer;    /* Local buffer encoded in UTF-8 */
+    xmlBufferPtr raw;       /* if encoder != NULL buffer for raw input */
+};
+
+
+/*
+ * Those are the functions and datatypes for the library output
+ * I/O structures.
+ */
+
+typedef int (*xmlOutputMatchCallback) (char const *filename);
+typedef void * (*xmlOutputOpenCallback) (char const *filename);
+typedef int (*xmlOutputWriteCallback) (void * context, const char * buffer,
+                                       int len);
+typedef void (*xmlOutputCloseCallback) (void * context);
+
+typedef struct _xmlOutputBuffer xmlOutputBuffer;
+typedef xmlOutputBuffer *xmlOutputBufferPtr;
+struct _xmlOutputBuffer {
+    void*                   context;
+    xmlOutputWriteCallback  writecallback;
+    xmlOutputCloseCallback  closecallback;
+    
+    xmlCharEncodingHandlerPtr encoder; /* I18N conversions to UTF-8 */
+    
+    xmlBufferPtr buffer;    /* Local buffer encoded in UTF-8 or ISOLatin */
+    xmlBufferPtr conv;      /* if encoder != NULL buffer for output */
+    int written;            /* total number of byte written */
+};
+
+/*
+ * Interfaces for input
+ */
+
+void	xmlRegisterDefaultInputCallbacks	(void);
+xmlParserInputBufferPtr
+	xmlAllocParserInputBuffer		(xmlCharEncoding enc);
+
+#ifdef VMS
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFname		(const char *URI,
+                                                 xmlCharEncoding enc);
+#define xmlParserInputBufferCreateFilename xmlParserInputBufferCreateFname
+#else
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFilename	(const char *URI,
+                                                 xmlCharEncoding enc);
+#endif
+
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFile		(FILE *file,
+                                                 xmlCharEncoding enc);
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateFd		(int fd,
+	                                         xmlCharEncoding enc);
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateMem		(const char *mem, int size,
+	                                         xmlCharEncoding enc);
+xmlParserInputBufferPtr
+	xmlParserInputBufferCreateIO		(xmlInputReadCallback   ioread,
+						 xmlInputCloseCallback  ioclose,
+						 void *ioctx,
+	                                         xmlCharEncoding enc);
+int	xmlParserInputBufferRead		(xmlParserInputBufferPtr in,
+						 int len);
+int	xmlParserInputBufferGrow		(xmlParserInputBufferPtr in,
+						 int len);
+int	xmlParserInputBufferPush		(xmlParserInputBufferPtr in,
+						 int len,
+						 const char *buf);
+void	xmlFreeParserInputBuffer		(xmlParserInputBufferPtr in);
+char *	xmlParserGetDirectory			(const char *filename);
+
+int     xmlRegisterInputCallbacks		(xmlInputMatchCallback match,
+						 xmlInputOpenCallback open,
+						 xmlInputReadCallback read,
+						 xmlInputCloseCallback close);
+/*
+ * Interfaces for output
+ */
+void	xmlRegisterDefaultOutputCallbacks(void);
+xmlOutputBufferPtr
+	xmlAllocOutputBuffer		(xmlCharEncodingHandlerPtr encoder);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateFilename	(const char *URI,
+					 xmlCharEncodingHandlerPtr encoder,
+					 int compression);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateFile	(FILE *file,
+					 xmlCharEncodingHandlerPtr encoder);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateFd		(int fd,
+					 xmlCharEncodingHandlerPtr encoder);
+
+xmlOutputBufferPtr
+	xmlOutputBufferCreateIO		(xmlOutputWriteCallback   iowrite,
+					 xmlOutputCloseCallback  ioclose,
+					 void *ioctx,
+					 xmlCharEncodingHandlerPtr encoder);
+
+int	xmlOutputBufferWrite		(xmlOutputBufferPtr out,
+					 int len,
+					 const char *buf);
+int	xmlOutputBufferWriteString	(xmlOutputBufferPtr out,
+					 const char *str);
+
+int	xmlOutputBufferFlush		(xmlOutputBufferPtr out);
+int	xmlOutputBufferClose		(xmlOutputBufferPtr out);
+
+int     xmlRegisterOutputCallbacks	(xmlOutputMatchCallback match,
+					 xmlOutputOpenCallback open,
+					 xmlOutputWriteCallback write,
+					 xmlOutputCloseCallback close);
+
+/*
+ * This save function are part of tree.h and HTMLtree.h actually
+ */
+int		xmlSaveFileTo		(xmlOutputBuffer *buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+void		xmlNodeDumpOutput	(xmlOutputBufferPtr buf,
+					 xmlDocPtr doc,
+					 xmlNodePtr cur,
+					 int level,
+					 int format,
+					 const char *encoding);
+void		htmlDocContentDumpOutput(xmlOutputBufferPtr buf,
+					 xmlDocPtr cur,
+					 const char *encoding);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_IO_H__ */
diff --git a/xmlerror.h b/xmlerror.h
new file mode 100644
index 0000000..53c5751
--- /dev/null
+++ b/xmlerror.h
@@ -0,0 +1,180 @@
+#ifndef __XML_ERROR_H__
+#define __XML_ERROR_H__
+
+#include <libxml/parser.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+    XML_ERR_OK = 0,
+    XML_ERR_INTERNAL_ERROR,
+    XML_ERR_NO_MEMORY,
+    
+    XML_ERR_DOCUMENT_START, /* 3 */
+    XML_ERR_DOCUMENT_EMPTY,
+    XML_ERR_DOCUMENT_END,
+
+    XML_ERR_INVALID_HEX_CHARREF, /* 6 */
+    XML_ERR_INVALID_DEC_CHARREF,
+    XML_ERR_INVALID_CHARREF,
+    XML_ERR_INVALID_CHAR,
+
+    XML_ERR_CHARREF_AT_EOF, /* 10 */
+    XML_ERR_CHARREF_IN_PROLOG,
+    XML_ERR_CHARREF_IN_EPILOG,
+    XML_ERR_CHARREF_IN_DTD,
+    XML_ERR_ENTITYREF_AT_EOF,
+    XML_ERR_ENTITYREF_IN_PROLOG,
+    XML_ERR_ENTITYREF_IN_EPILOG,
+    XML_ERR_ENTITYREF_IN_DTD,
+    XML_ERR_PEREF_AT_EOF,
+    XML_ERR_PEREF_IN_PROLOG,
+    XML_ERR_PEREF_IN_EPILOG,
+    XML_ERR_PEREF_IN_INT_SUBSET,
+
+    XML_ERR_ENTITYREF_NO_NAME, /* 22 */
+    XML_ERR_ENTITYREF_SEMICOL_MISSING,
+
+    XML_ERR_PEREF_NO_NAME, /* 24 */
+    XML_ERR_PEREF_SEMICOL_MISSING,
+
+    XML_ERR_UNDECLARED_ENTITY, /* 26 */
+    XML_WAR_UNDECLARED_ENTITY,
+    XML_ERR_UNPARSED_ENTITY,
+    XML_ERR_ENTITY_IS_EXTERNAL,
+    XML_ERR_ENTITY_IS_PARAMETER,
+
+    XML_ERR_UNKNOWN_ENCODING, /* 31 */
+    XML_ERR_UNSUPPORTED_ENCODING,
+
+    XML_ERR_STRING_NOT_STARTED, /* 33 */
+    XML_ERR_STRING_NOT_CLOSED,
+    XML_ERR_NS_DECL_ERROR,
+
+    XML_ERR_ENTITY_NOT_STARTED, /* 36 */
+    XML_ERR_ENTITY_NOT_FINISHED,
+    
+    XML_ERR_LT_IN_ATTRIBUTE, /* 38 */
+    XML_ERR_ATTRIBUTE_NOT_STARTED,
+    XML_ERR_ATTRIBUTE_NOT_FINISHED,
+    XML_ERR_ATTRIBUTE_WITHOUT_VALUE,
+    XML_ERR_ATTRIBUTE_REDEFINED,
+
+    XML_ERR_LITERAL_NOT_STARTED, /* 43 */
+    XML_ERR_LITERAL_NOT_FINISHED,
+    
+    XML_ERR_COMMENT_NOT_FINISHED, /* 45 */
+
+    XML_ERR_PI_NOT_STARTED, /* 47 */
+    XML_ERR_PI_NOT_FINISHED,
+
+    XML_ERR_NOTATION_NOT_STARTED, /* 49 */
+    XML_ERR_NOTATION_NOT_FINISHED,
+
+    XML_ERR_ATTLIST_NOT_STARTED, /* 51 */
+    XML_ERR_ATTLIST_NOT_FINISHED,
+
+    XML_ERR_MIXED_NOT_STARTED, /* 53 */
+    XML_ERR_MIXED_NOT_FINISHED,
+
+    XML_ERR_ELEMCONTENT_NOT_STARTED, /* 55 */
+    XML_ERR_ELEMCONTENT_NOT_FINISHED,
+
+    XML_ERR_XMLDECL_NOT_STARTED, /* 57 */
+    XML_ERR_XMLDECL_NOT_FINISHED,
+
+    XML_ERR_CONDSEC_NOT_STARTED, /* 59 */
+    XML_ERR_CONDSEC_NOT_FINISHED,
+
+    XML_ERR_EXT_SUBSET_NOT_FINISHED, /* 61 */
+
+    XML_ERR_DOCTYPE_NOT_FINISHED, /* 62 */
+
+    XML_ERR_MISPLACED_CDATA_END, /* 63 */
+    XML_ERR_CDATA_NOT_FINISHED,
+
+    XML_ERR_RESERVED_XML_NAME, /* 65 */
+
+    XML_ERR_SPACE_REQUIRED, /* 66 */
+    XML_ERR_SEPARATOR_REQUIRED,
+    XML_ERR_NMTOKEN_REQUIRED,
+    XML_ERR_NAME_REQUIRED,
+    XML_ERR_PCDATA_REQUIRED,
+    XML_ERR_URI_REQUIRED,
+    XML_ERR_PUBID_REQUIRED,
+    XML_ERR_LT_REQUIRED,
+    XML_ERR_GT_REQUIRED,
+    XML_ERR_LTSLASH_REQUIRED,
+    XML_ERR_EQUAL_REQUIRED,
+
+    XML_ERR_TAG_NAME_MISMATCH, /* 77 */
+    XML_ERR_TAG_NOT_FINISED,
+
+    XML_ERR_STANDALONE_VALUE, /* 79 */
+
+    XML_ERR_ENCODING_NAME, /* 80 */
+
+    XML_ERR_HYPHEN_IN_COMMENT, /* 81 */
+
+    XML_ERR_INVALID_ENCODING, /* 82 */
+
+    XML_ERR_EXT_ENTITY_STANDALONE, /* 83 */
+
+    XML_ERR_CONDSEC_INVALID, /* 84 */
+
+    XML_ERR_VALUE_REQUIRED, /* 85 */
+
+    XML_ERR_NOT_WELL_BALANCED, /* 86 */
+    XML_ERR_EXTRA_CONTENT, /* 87 */
+    XML_ERR_ENTITY_CHAR_ERROR, /* 88 */
+    XML_ERR_ENTITY_PE_INTERNAL, /* 88 */
+    XML_ERR_ENTITY_LOOP, /* 89 */
+    XML_ERR_ENTITY_BOUNDARY, /* 90 */
+    XML_ERR_INVALID_URI, /* 91 */
+    XML_ERR_URI_FRAGMENT /* 92 */
+}xmlParserErrors;
+
+/*
+ * Signature of the function to use when there is an error and
+ * no parsing or validity context available 
+ */
+typedef void (*xmlGenericErrorFunc) (void *ctx, const char *msg, ...);
+
+/*
+ * Those are the default error function and associated context to use
+ * when when there is an error and no parsing or validity context available
+ */
+
+LIBXML_DLL_IMPORT extern xmlGenericErrorFunc xmlGenericError;
+LIBXML_DLL_IMPORT extern void *xmlGenericErrorContext;
+
+/*
+ * Use the following function to reset the two previous global variables.
+ */
+void	xmlSetGenericErrorFunc	(void *ctx,
+				 xmlGenericErrorFunc handler);
+
+/*
+ * Default message routines used by SAX and Valid context for error
+ * and warning reporting
+ */
+void	xmlParserError		(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserWarning	(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserValidityError	(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserValidityWarning(void *ctx,
+				 const char *msg,
+				 ...);
+void	xmlParserPrintFileInfo	(xmlParserInputPtr input);
+void	xmlParserPrintFileContext(xmlParserInputPtr input);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_ERROR_H__ */
diff --git a/xmlmemory.c b/xmlmemory.c
new file mode 100644
index 0000000..4cf1603
--- /dev/null
+++ b/xmlmemory.c
@@ -0,0 +1,707 @@
+/*
+ * memory.c:  libxml memory allocator wrapper.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+
+#include <libxml/xmlmemory.h>
+#include <libxml/xmlerror.h>
+
+#ifdef xmlMalloc
+#undef xmlMalloc
+#endif
+#ifdef xmlRealloc
+#undef xmlRealloc
+#endif
+#ifdef xmlMemStrdup
+#undef xmlMemStrdup
+#endif
+
+
+/*
+ * Each of the blocks allocated begin with a header containing informations
+ */
+
+#define MEMTAG 0x5aa5
+
+#define MALLOC_TYPE 1
+#define REALLOC_TYPE 2
+#define STRDUP_TYPE 3
+
+typedef struct memnod {
+    unsigned int   mh_tag;
+    unsigned int   mh_type;
+    unsigned long  mh_number;
+    size_t         mh_size;
+#ifdef MEM_LIST
+   struct memnod *mh_next;
+   struct memnod *mh_prev;
+#endif
+   const char    *mh_file;
+   unsigned int   mh_line;
+}  MEMHDR;
+
+
+#ifdef SUN4
+#define ALIGN_SIZE  16
+#else
+#define ALIGN_SIZE  sizeof(double)
+#endif
+#define HDR_SIZE    sizeof(MEMHDR)
+#define RESERVE_SIZE (((HDR_SIZE + (ALIGN_SIZE-1)) \
+		      / ALIGN_SIZE ) * ALIGN_SIZE)
+
+
+#define CLIENT_2_HDR(a) ((MEMHDR *) (((char *) (a)) - RESERVE_SIZE))
+#define HDR_2_CLIENT(a)    ((void *) (((char *) (a)) + RESERVE_SIZE))
+
+
+static unsigned long  debugMemSize = 0;
+static unsigned long  debugMaxMemSize = 0;
+static int block=0;
+int xmlMemStopAtBlock = 0;
+int xmlMemInitialized = 0;
+#ifdef MEM_LIST
+static MEMHDR *memlist = NULL;
+#endif
+
+void debugmem_tag_error(void *addr);
+#ifdef MEM_LIST
+void  debugmem_list_add(MEMHDR *);
+void debugmem_list_delete(MEMHDR *);
+#endif
+#define Mem_Tag_Err(a) debugmem_tag_error(a);
+
+#ifndef TEST_POINT
+#define TEST_POINT
+#endif
+
+/**
+ * xmlMallocBreakpoint:
+ *
+ * Breakpoint to use in conjunction with xmlMemStopAtBlock. When the block
+ * number reaches the specified value this function is called. One need to add a breakpoint
+ * to it to get the context in which the given block is allocated.
+ */
+
+void
+xmlMallocBreakpoint(void) {
+    xmlGenericError(xmlGenericErrorContext,
+	    "xmlMallocBreakpoint reached on block %d\n", xmlMemStopAtBlock);
+}
+
+/**
+ * xmlMallocLoc:
+ * @size:  an int specifying the size in byte to allocate.
+ * @file:  the file name or NULL
+ * @line:  the line number
+ *
+ * a malloc() equivalent, with logging of the allocation info.
+ *
+ * Returns a pointer to the allocated area or NULL in case of lack of memory.
+ */
+
+void *
+xmlMallocLoc(int size, const char * file, int line)
+{
+    MEMHDR *p;
+    
+    if (!xmlMemInitialized) xmlInitMemory();
+#ifdef DEBUG_MEMORY
+    xmlGenericError(xmlGenericErrorContext,
+	    "Malloc(%d)\n",size);
+#endif
+
+    TEST_POINT
+    
+    p = (MEMHDR *) malloc(RESERVE_SIZE+size);
+
+    if (!p) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlMalloc : Out of free space\n");
+	xmlMemoryDump();
+	return(NULL);
+    }   
+    p->mh_tag = MEMTAG;
+    p->mh_number = ++block;
+    p->mh_size = size;
+    p->mh_type = MALLOC_TYPE;
+    p->mh_file = file;
+    p->mh_line = line;
+    debugMemSize += size;
+    if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
+#ifdef MEM_LIST
+    debugmem_list_add(p);
+#endif
+
+#ifdef DEBUG_MEMORY
+    xmlGenericError(xmlGenericErrorContext,
+	    "Malloc(%d) Ok\n",size);
+#endif
+    
+    if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
+
+    TEST_POINT
+
+    return(HDR_2_CLIENT(p));
+}
+
+/**
+ * xmlMemMalloc:
+ * @size:  an int specifying the size in byte to allocate.
+ *
+ * a malloc() equivalent, with logging of the allocation info.
+ *
+ * Returns a pointer to the allocated area or NULL in case of lack of memory.
+ */
+
+void *
+xmlMemMalloc(int size)
+{
+    return(xmlMallocLoc(size, "none", 0));
+}
+
+/**
+ * xmlReallocLoc:
+ * @ptr:  the initial memory block pointer
+ * @size:  an int specifying the size in byte to allocate.
+ * @file:  the file name or NULL
+ * @line:  the line number
+ *
+ * a realloc() equivalent, with logging of the allocation info.
+ *
+ * Returns a pointer to the allocated area or NULL in case of lack of memory.
+ */
+
+void *
+xmlReallocLoc(void *ptr,int size, const char * file, int line)
+{
+    MEMHDR *p;
+    unsigned long number;
+
+    if (!xmlMemInitialized) xmlInitMemory();
+    TEST_POINT
+
+    p = CLIENT_2_HDR(ptr);
+    number = p->mh_number;
+    if (p->mh_tag != MEMTAG) {
+       Mem_Tag_Err(p);
+	 goto error;
+    }
+    p->mh_tag = ~MEMTAG;
+    debugMemSize -= p->mh_size;
+#ifdef MEM_LIST
+    debugmem_list_delete(p);
+#endif
+
+    p = (MEMHDR *) realloc(p,RESERVE_SIZE+size);
+    if (!p) {
+	 goto error;
+    }
+    p->mh_tag = MEMTAG;
+    p->mh_number = number;
+    p->mh_type = REALLOC_TYPE;
+    p->mh_size = size;
+    p->mh_file = file;
+    p->mh_line = line;
+    debugMemSize += size;
+    if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
+#ifdef MEM_LIST
+    debugmem_list_add(p);
+#endif
+
+    TEST_POINT
+
+    return(HDR_2_CLIENT(p));
+    
+error:    
+    return(NULL);
+}
+
+/**
+ * xmlMemRealloc:
+ * @ptr:  the initial memory block pointer
+ * @size:  an int specifying the size in byte to allocate.
+ *
+ * a realloc() equivalent, with logging of the allocation info.
+ *
+ * Returns a pointer to the allocated area or NULL in case of lack of memory.
+ */
+
+void *
+xmlMemRealloc(void *ptr,int size) {
+    return(xmlReallocLoc(ptr, size, "none", 0));
+}
+
+/**
+ * xmlMemFree:
+ * @ptr:  the memory block pointer
+ *
+ * a free() equivalent, with error checking.
+ */
+void
+xmlMemFree(void *ptr)
+{
+    MEMHDR *p;
+
+    TEST_POINT
+
+    p = CLIENT_2_HDR(ptr);
+    if (p->mh_tag != MEMTAG) {
+       Mem_Tag_Err(p);
+       goto error;
+    }
+    p->mh_tag = ~MEMTAG;
+    debugMemSize -= p->mh_size;
+
+#ifdef MEM_LIST
+    debugmem_list_delete(p);
+#endif
+    free(p);
+
+    TEST_POINT
+
+    return;
+    
+error:    
+    xmlGenericError(xmlGenericErrorContext,
+	    "xmlFree(%X) error\n", (unsigned int) ptr);
+    return;
+}
+
+/**
+ * xmlMemStrdupLoc:
+ * @ptr:  the initial string pointer
+ * @file:  the file name or NULL
+ * @line:  the line number
+ *
+ * a strdup() equivalent, with logging of the allocation info.
+ *
+ * Returns a pointer to the new string or NULL if allocation error occured.
+ */
+
+char *
+xmlMemStrdupLoc(const char *str, const char *file, int line)
+{
+    char *s;
+    size_t size = strlen(str) + 1;
+    MEMHDR *p;
+
+    if (!xmlMemInitialized) xmlInitMemory();
+    TEST_POINT
+
+    p = (MEMHDR *) malloc(RESERVE_SIZE+size);
+    if (!p) {
+      goto error;
+    }
+    p->mh_tag = MEMTAG;
+    p->mh_number = ++block;
+    p->mh_size = size;
+    p->mh_type = STRDUP_TYPE;
+    p->mh_file = file;
+    p->mh_line = line;
+    debugMemSize += size;
+    if (debugMemSize > debugMaxMemSize) debugMaxMemSize = debugMemSize;
+#ifdef MEM_LIST
+    debugmem_list_add(p);
+#endif
+    s = (char *) HDR_2_CLIENT(p);
+    
+    if (xmlMemStopAtBlock == block) xmlMallocBreakpoint();
+
+    if (s != NULL)
+      strcpy(s,str);
+    else
+      goto error;
+    
+    TEST_POINT
+
+    return(s);
+
+error:
+    return(NULL);
+}
+
+/**
+ * xmlMemoryStrdup:
+ * @ptr:  the initial string pointer
+ *
+ * a strdup() equivalent, with logging of the allocation info.
+ *
+ * Returns a pointer to the new string or NULL if allocation error occured.
+ */
+
+char *
+xmlMemoryStrdup(const char *str) {
+    return(xmlMemStrdupLoc(str, "none", 0));
+}
+
+/**
+ * xmlMemUsed:
+ *
+ * returns the amount of memory currenly allocated
+ *
+ * Returns an int representing the amount of memory allocated.
+ */
+
+int
+xmlMemUsed(void) {
+     return(debugMemSize);
+}
+
+#ifdef MEM_LIST
+/**
+ * xmlMemContentShow:
+ * @fp:  a FILE descriptor used as the output file
+ * @p:  a memory block header
+ *
+ * tries to show some content from the memory block
+ */
+
+void
+xmlMemContentShow(FILE *fp, MEMHDR *p)
+{
+    int i,j,len = p->mh_size;
+    const char *buf = (const char *) HDR_2_CLIENT(p);
+
+    if (p == NULL) {
+	fprintf(fp, " NULL");
+	return;
+    }
+
+    for (i = 0;i < len;i++) {
+        if (buf[i] == 0) break;
+	if (!isprint(buf[i])) break;
+    }
+    if ((i < 4) && ((buf[i] != 0) || (i == 0))) {
+        if (len >= 4) {
+	    MEMHDR *q;
+	    void *cur;
+
+            for (j = 0;j < len -3;j += 4) {
+		cur = *((void **) &buf[j]);
+		q = CLIENT_2_HDR(cur);
+		p = memlist;
+		while (p != NULL) {
+		    if (p == q) break;
+		    p = p->mh_next;
+		}
+		if ((p != NULL) && (p == q)) {
+		    fprintf(fp, " pointer to #%lu at index %d",
+		            p->mh_number, j);
+		    return;
+		}
+	    }
+	}
+    } else if ((i == 0) && (buf[i] == 0)) {
+        fprintf(fp," null");
+    } else {
+        if (buf[i] == 0) fprintf(fp," \"%.25s\"", buf); 
+	else {
+            fprintf(fp," [");
+	    for (j = 0;j < i;j++)
+                fprintf(fp,"%c", buf[j]);
+            fprintf(fp,"]");
+	}
+    }
+}
+#endif
+
+/**
+ * xmlMemShow:
+ * @fp:  a FILE descriptor used as the output file
+ * @nr:  number of entries to dump
+ *
+ * show a show display of the memory allocated, and dump
+ * the @nr last allocated areas which were not freed
+ */
+
+void
+xmlMemShow(FILE *fp, int nr)
+{
+#ifdef MEM_LIST
+    MEMHDR *p;
+#endif
+
+    if (fp != NULL)
+	fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
+		debugMemSize, debugMaxMemSize);
+#ifdef MEM_LIST
+    if (nr > 0) {
+	fprintf(fp,"NUMBER   SIZE  TYPE   WHERE\n");
+	p = memlist;
+	while ((p) && nr > 0) {
+	      fprintf(fp,"%6lu %6u ",p->mh_number,p->mh_size);
+	    switch (p->mh_type) {
+	       case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
+	       case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
+	      case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
+			default:fprintf(fp,"   ???    in ");break;
+	    }
+	    if (p->mh_file != NULL)
+	        fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
+	    if (p->mh_tag != MEMTAG)
+		fprintf(fp,"  INVALID");
+	    xmlMemContentShow(fp, p);
+	    fprintf(fp,"\n");
+	    nr--;
+	    p = p->mh_next;
+	}
+    }
+#endif /* MEM_LIST */    
+}
+
+/**
+ * xmlMemDisplay:
+ * @fp:  a FILE descriptor used as the output file, if NULL, the result is
+ *       written to the file .memorylist
+ *
+ * show in-extenso the memory blocks allocated
+ */
+
+void
+xmlMemDisplay(FILE *fp)
+{
+#ifdef MEM_LIST
+    MEMHDR *p;
+    int     idx;
+#if defined(HAVE_LOCALTIME) && defined(HAVE_STRFTIME)
+    time_t currentTime;
+    char buf[500];
+    struct tm * tstruct;
+
+    currentTime = time(NULL);
+    tstruct = localtime(&currentTime);
+    strftime(buf, sizeof(buf) - 1, "%c", tstruct);
+    fprintf(fp,"      %s\n\n", buf);
+#endif
+
+    
+    fprintf(fp,"      MEMORY ALLOCATED : %lu, MAX was %lu\n",
+            debugMemSize, debugMaxMemSize);
+    fprintf(fp,"BLOCK  NUMBER   SIZE  TYPE\n");
+    idx = 0;
+    p = memlist;
+    while (p) {
+	  fprintf(fp,"%-5u  %6lu %6u ",idx++,p->mh_number,p->mh_size);
+        switch (p->mh_type) {
+           case STRDUP_TYPE:fprintf(fp,"strdup()  in ");break;
+           case MALLOC_TYPE:fprintf(fp,"malloc()  in ");break;
+          case REALLOC_TYPE:fprintf(fp,"realloc() in ");break;
+                    default:fprintf(fp,"   ???    in ");break;
+        }
+	  if (p->mh_file != NULL) fprintf(fp,"%s(%d)", p->mh_file, p->mh_line);
+        if (p->mh_tag != MEMTAG)
+	      fprintf(fp,"  INVALID");
+	xmlMemContentShow(fp, p);
+        fprintf(fp,"\n");
+        p = p->mh_next;
+    }
+#else
+    fprintf(fp,"Memory list not compiled (MEM_LIST not defined !)\n");
+#endif
+}
+
+#ifdef MEM_LIST
+
+void debugmem_list_add(MEMHDR *p)
+{
+     p->mh_next = memlist;
+     p->mh_prev = NULL;
+     if (memlist) memlist->mh_prev = p;
+     memlist = p;
+#ifdef MEM_LIST_DEBUG
+     if (stderr)
+     Mem_Display(stderr);
+#endif
+}
+
+void debugmem_list_delete(MEMHDR *p)
+{
+     if (p->mh_next)
+     p->mh_next->mh_prev = p->mh_prev;
+     if (p->mh_prev)
+     p->mh_prev->mh_next = p->mh_next;
+     else memlist = p->mh_next;
+#ifdef MEM_LIST_DEBUG
+     if (stderr)
+     Mem_Display(stderr);
+#endif
+}
+
+#endif
+
+/*
+ * debugmem_tag_error : internal error function.
+ */
+ 
+void debugmem_tag_error(void *p)
+{
+     xmlGenericError(xmlGenericErrorContext,
+	     "Memory tag error occurs :%p \n\t bye\n", p);
+#ifdef MEM_LIST
+     if (stderr)
+     xmlMemDisplay(stderr);
+#endif
+}
+
+FILE *xmlMemoryDumpFile = NULL;
+
+
+/**
+ * xmlMemoryDump:
+ *
+ * Dump in-extenso the memory blocks allocated to the file .memorylist
+ */
+
+void
+xmlMemoryDump(void)
+{
+#if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY)
+    FILE *dump;
+
+    dump = fopen(".memdump", "w");
+    if (dump == NULL) xmlMemoryDumpFile = stdout;
+    else xmlMemoryDumpFile = dump;
+
+    xmlMemDisplay(xmlMemoryDumpFile);
+
+    if (dump != NULL) fclose(dump);
+#endif
+}
+
+
+/****************************************************************
+ *								*
+ *		Initialization Routines				*
+ *								*
+ ****************************************************************/
+
+#if defined(DEBUG_MEMORY_LOCATION) | defined(DEBUG_MEMORY)
+xmlFreeFunc xmlFree = (xmlFreeFunc) xmlMemFree;
+xmlMallocFunc xmlMalloc = (xmlMallocFunc) xmlMemMalloc;
+xmlReallocFunc xmlRealloc = (xmlReallocFunc) xmlMemRealloc;
+xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) xmlMemoryStrdup;
+#else
+xmlFreeFunc xmlFree = (xmlFreeFunc) free;
+xmlMallocFunc xmlMalloc = (xmlMallocFunc) malloc;
+xmlReallocFunc xmlRealloc = (xmlReallocFunc) realloc;
+xmlStrdupFunc xmlMemStrdup = (xmlStrdupFunc) strdup;
+#endif
+
+/**
+ * xmlInitMemory:
+ *
+ * Initialize the memory layer.
+ *
+ * Returns 0 on success
+ */
+
+static int xmlInitMemoryDone = 0;
+
+int
+xmlInitMemory(void)
+{
+     int ret;
+     
+#ifdef HAVE_STDLIB_H
+     char *breakpoint;
+#endif     
+
+     if (xmlInitMemoryDone) return(-1);
+
+#ifdef HAVE_STDLIB_H
+     breakpoint = getenv("XML_MEM_BREAKPOINT");
+     if (breakpoint != NULL) {
+         sscanf(breakpoint, "%d", &xmlMemStopAtBlock);
+     }
+#endif     
+    
+#ifdef DEBUG_MEMORY
+     xmlGenericError(xmlGenericErrorContext,
+	     "xmlInitMemory() Ok\n");
+#endif     
+     ret = 0;
+     return(ret);
+}
+
+/**
+ * xmlMemSetup:
+ * @freeFunc: the free() function to use
+ * @mallocFunc: the malloc() function to use
+ * @reallocFunc: the realloc() function to use
+ * @strdupFunc: the strdup() function to use
+ *
+ * Override the default memory access functions with a new set
+ * This has to be called before any other libxml routines !
+ *
+ * Should this be blocked if there was already some allocations
+ * done ?
+ *
+ * Returns 0 on success
+ */
+int
+xmlMemSetup(xmlFreeFunc freeFunc, xmlMallocFunc mallocFunc,
+            xmlReallocFunc reallocFunc, xmlStrdupFunc strdupFunc) {
+    if (freeFunc == NULL)
+	return(-1);
+    if (mallocFunc == NULL)
+	return(-1);
+    if (reallocFunc == NULL)
+	return(-1);
+    if (strdupFunc == NULL)
+	return(-1);
+    xmlFree = freeFunc;
+    xmlMalloc = mallocFunc;
+    xmlRealloc = reallocFunc;
+    xmlMemStrdup = strdupFunc;
+    return(0);
+}
+
+/**
+ * xmlMemGet:
+ * @freeFunc: the free() function in use
+ * @mallocFunc: the malloc() function in use
+ * @reallocFunc: the realloc() function in use
+ * @strdupFunc: the strdup() function in use
+ *
+ * Return the memory access functions set currently in use
+ *
+ * Returns 0 on success
+ */
+int
+xmlMemGet(xmlFreeFunc *freeFunc, xmlMallocFunc *mallocFunc,
+	  xmlReallocFunc *reallocFunc, xmlStrdupFunc *strdupFunc) {
+    if (freeFunc != NULL) *freeFunc = xmlFree;
+    if (mallocFunc != NULL) *mallocFunc = xmlMalloc;
+    if (reallocFunc != NULL) *reallocFunc = xmlRealloc;
+    if (strdupFunc != NULL) *strdupFunc = xmlMemStrdup;
+    return(0);
+}
+
diff --git a/xmlmemory.h b/xmlmemory.h
new file mode 100644
index 0000000..1e533d1
--- /dev/null
+++ b/xmlmemory.h
@@ -0,0 +1,91 @@
+/*
+ * xmlmemory.h: interface for the memory allocation debug.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+
+#ifndef _DEBUG_MEMORY_ALLOC_
+#define _DEBUG_MEMORY_ALLOC_
+
+#include <stdio.h>
+#include <libxml/xmlversion.h>
+
+/*
+ * DEBUG_MEMORY_LOCATION should be activated only done when debugging 
+ * libxml.
+ */
+/* #define DEBUG_MEMORY_LOCATION */
+
+#ifdef DEBUG
+#ifndef DEBUG_MEMORY
+#define DEBUG_MEMORY
+#endif
+#endif
+
+#ifdef DEBUG_MEMORY_LOCATION
+#define MEM_LIST /* keep a list of all the allocated memory blocks */
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The XML memory wrapper support 4 basic overloadable functions
+ */
+typedef void (*xmlFreeFunc)(void *);
+typedef void *(*xmlMallocFunc)(int);
+typedef void *(*xmlReallocFunc)(void *, int);
+typedef char *(*xmlStrdupFunc)(const char *);
+
+/*
+ * The 4 interfaces used for all memory handling within libxml
+ */
+LIBXML_DLL_IMPORT extern xmlFreeFunc xmlFree;
+LIBXML_DLL_IMPORT extern xmlMallocFunc xmlMalloc;
+LIBXML_DLL_IMPORT extern xmlReallocFunc xmlRealloc;
+LIBXML_DLL_IMPORT extern xmlStrdupFunc xmlMemStrdup;
+
+/*
+ * The way to overload the existing functions
+ */
+int     xmlMemSetup	(xmlFreeFunc freeFunc,
+			 xmlMallocFunc mallocFunc,
+			 xmlReallocFunc reallocFunc,
+			 xmlStrdupFunc strdupFunc);
+int     xmlMemGet	(xmlFreeFunc *freeFunc,
+			 xmlMallocFunc *mallocFunc,
+			 xmlReallocFunc *reallocFunc,
+			 xmlStrdupFunc *strdupFunc);
+
+/*
+ * Initialization of the memory layer
+ */
+int	xmlInitMemory	(void);
+
+/*
+ * Those are specific to the XML debug memory wrapper
+ */
+int	xmlMemUsed	(void);
+void	xmlMemDisplay	(FILE *fp);
+void	xmlMemShow	(FILE *fp, int nr);
+void	xmlMemoryDump	(void);
+int	xmlInitMemory	(void);
+
+#ifdef DEBUG_MEMORY_LOCATION
+#define xmlMalloc(x) xmlMallocLoc((x), __FILE__, __LINE__)
+#define xmlRealloc(p, x) xmlReallocLoc((p), (x), __FILE__, __LINE__)
+#define xmlMemStrdup(x) xmlMemStrdupLoc((x), __FILE__, __LINE__)
+
+void *	xmlMallocLoc(int size, const char *file, int line);
+void *	xmlReallocLoc(void *ptr,int size, const char *file, int line);
+char *	xmlMemStrdupLoc(const char *str, const char *file, int line);
+#endif /* DEBUG_MEMORY_LOCATION */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif  /* _DEBUG_MEMORY_ALLOC_ */
+
diff --git a/xmlversion.h.in b/xmlversion.h.in
new file mode 100644
index 0000000..71ab184
--- /dev/null
+++ b/xmlversion.h.in
@@ -0,0 +1,129 @@
+/*
+ * xmlversion.h : compile-time version informations for the XML parser.
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_VERSION_H__
+#define __XML_VERSION_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * use those to be sure nothing nasty will happen if
+ * your library and includes mismatch
+ */
+extern void xmlCheckVersion(int version);
+#define LIBXML_DOTTED_VERSION "@VERSION@"
+#define LIBXML_VERSION @LIBXML_VERSION_NUMBER@
+#define LIBXML_VERSION_STRING "@LIBXML_VERSION_NUMBER@"
+#define LIBXML_TEST_VERSION xmlCheckVersion(@LIBXML_VERSION_NUMBER@);
+
+/*
+ * Whether the FTP support is configured in
+ */
+#if @WITH_FTP@
+#define LIBXML_FTP_ENABLED
+#else
+#define LIBXML_FTP_DISABLED
+#endif
+
+/*
+ * Whether the HTTP support is configured in
+ */
+#if @WITH_HTTP@
+#define LIBXML_HTTP_ENABLED
+#else
+#define LIBXML_HTTP_DISABLED
+#endif
+
+/*
+ * Whether the HTML support is configured in
+ */
+#if @WITH_HTML@
+#define LIBXML_HTML_ENABLED
+#else
+#define LIBXML_HTML_DISABLED
+#endif
+
+/*
+ * Whether the Docbook support is configured in
+#if @WITH_SGML@
+#define LIBXML_SGML_ENABLED
+#else
+#define LIBXML_SGML_DISABLED
+#endif
+ */
+
+/*
+ * Whether XPath is configured in
+ */
+#if @WITH_XPATH@
+#define LIBXML_XPATH_ENABLED
+#else
+#define LIBXML_XPATH_DISABLED
+#endif
+
+/*
+ * Whether XPointer is configured in
+ */
+#if @WITH_XPTR@
+#define LIBXML_XPTR_ENABLED
+#else
+#define LIBXML_XPTR_DISABLED
+#endif
+
+/*
+ * Whether XInclude is configured in
+ */
+#if @WITH_XINCLUDE@
+#define LIBXML_XINCLUDE_ENABLED
+#else
+#define LIBXML_XINCLUDE_DISABLED
+#endif
+
+/*
+ * Whether iconv support is available
+ */
+#ifndef WIN32
+#if @WITH_ICONV@
+#define LIBXML_ICONV_ENABLED
+#else
+#define LIBXML_ICONV_DISABLED
+#endif
+#endif
+
+/*
+ * Whether Debugging module is configured in
+ */
+#if @WITH_DEBUG@
+#define LIBXML_DEBUG_ENABLED
+#else
+#define LIBXML_DEBUG_DISABLED
+#endif
+
+/*
+ * Whether the memory debugging is configured in
+ */
+#if @WITH_MEM_DEBUG@
+#define DEBUG_MEMORY_LOCATION
+#endif
+
+#ifndef LIBXML_DLL_IMPORT
+#if defined(WIN32) && !defined(STATIC)
+#define LIBXML_DLL_IMPORT __declspec(dllimport)
+#else
+#define LIBXML_DLL_IMPORT
+#endif
+#endif
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+#endif
+
+
diff --git a/xpath.c b/xpath.c
new file mode 100644
index 0000000..669e4cd
--- /dev/null
+++ b/xpath.c
@@ -0,0 +1,6498 @@
+/*
+ * xpath.c: XML Path Language implementation
+ *          XPath is a language for addressing parts of an XML document,
+ *          designed to be used by both XSLT and XPointer
+ *
+ * Reference: W3C Recommendation 16 November 1999
+ *     http://www.w3.org/TR/1999/REC-xpath-19991116
+ * Public reference:
+ *     http://www.w3.org/TR/xpath
+ *
+ * See COPYRIGHT for the status of this software
+ *
+ * Author: Daniel.Veillard@w3.org
+ *
+ * 14 Nov 2000 ht - truncated declaration of xmlXPathEvalRelativeLocationPath
+ * for VMS
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+#include <libxml/xmlversion.h>
+#ifdef LIBXML_XPATH_ENABLED
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_MATH_H
+#include <math.h>
+#endif
+#ifdef HAVE_FLOAT_H
+#include <float.h>
+#endif
+#ifdef HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif
+#ifdef HAVE_NAN_H
+#include <nan.h>
+#endif
+#ifdef HAVE_CTYPE_H
+#include <ctype.h>
+#endif
+
+#include <libxml/xmlmemory.h>
+#include <libxml/tree.h>
+#include <libxml/valid.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#include <libxml/parserInternals.h>
+#include <libxml/hash.h>
+#ifdef LIBXML_XPTR_ENABLED
+#include <libxml/xpointer.h>
+#endif
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
+#include <libxml/xmlerror.h>
+
+/* #define DEBUG */
+/* #define DEBUG_STEP */
+/* #define DEBUG_EXPR */
+
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+double xmlXPathStringEvalNumber(const xmlChar *str);
+
+/*
+ * Setup stuff for floating point
+ * The lack of portability of this section of the libc is annoying !
+ */
+double xmlXPathNAN = 0;
+double xmlXPathPINF = 1;
+double xmlXPathNINF = -1;
+
+#ifndef isinf
+#ifndef HAVE_ISINF
+
+#if HAVE_FPCLASS
+
+int isinf(double d) {
+    fpclass_t	type = fpclass(d);
+    switch (type) {
+	case FP_NINF:
+	    return(-1);
+	case FP_PINF:
+	    return(1);
+    }
+    return(0);
+}
+
+#elif defined(HAVE_FP_CLASS) || defined(HAVE_FP_CLASS_D)
+
+#if HAVE_FP_CLASS_H
+#include <fp_class.h>
+#endif
+
+int isinf(double d) {
+#if HAVE_FP_CLASS
+    int	fpclass = fp_class(d);
+#else
+    int	fpclass = fp_class_d(d);
+#endif
+    if (fpclass == FP_POS_INF)
+	return(1);
+    if (fpclass == FP_NEG_INF)
+	return(-1);
+    return(0);
+}
+
+#elif defined(HAVE_CLASS)
+
+int isinf(double d) {
+    int	fpclass = class(d);
+    if (fpclass == FP_PLUS_INF)
+	return(1);
+    if (fpclass == FP_MINUS_INF)
+	return(-1);
+    return(0);
+}
+#elif defined(finite) || defined(HAVE_FINITE)
+int isinf(double x) { return !finite(x) && x==x; }
+#elif defined(HUGE_VAL)
+int isinf(double x)
+{
+    if (x == HUGE_VAL)
+        return(1);
+    if (x == -HUGE_VAL)
+        return(-1);
+    return(0);
+}
+#endif 
+
+#endif /* ! HAVE_ISINF */
+#endif /* ! defined(isinf) */
+
+#ifndef isnan
+#ifndef HAVE_ISNAN
+
+#ifdef HAVE_ISNAND
+#define isnan(f) isnand(f)
+#endif /* HAVE_iSNAND */
+
+#endif /* ! HAVE_iSNAN */
+#endif /* ! defined(isnan) */
+
+/**
+ * xmlXPathInit:
+ *
+ * Initialize the XPath environment
+ */
+void
+xmlXPathInit(void) {
+    static int initialized = 0;
+
+    if (initialized) return;
+
+    xmlXPathNAN = 0;
+    xmlXPathNAN /= 0;
+
+    xmlXPathPINF = 1;
+    xmlXPathPINF /= 0;
+
+    xmlXPathNINF = -1;
+    xmlXPathNINF /= 0;
+
+    initialized = 1;
+}
+
+/************************************************************************
+ *									*
+ * 		Debugging related functions				*
+ *									*
+ ************************************************************************/
+
+#define TODO 								\
+    xmlGenericError(xmlGenericErrorContext,				\
+	    "Unimplemented block at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+#define STRANGE 							\
+    xmlGenericError(xmlGenericErrorContext,				\
+	    "Internal error at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+#ifdef LIBXML_DEBUG_ENABLED
+void xmlXPathDebugDumpNode(FILE *output, xmlNodePtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+    if (cur == NULL) {
+	fprintf(output, shift);
+	fprintf(output, "Node is NULL !\n");
+	return;
+        
+    }
+
+    if ((cur->type == XML_DOCUMENT_NODE) ||
+	     (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	fprintf(output, shift);
+	fprintf(output, " /\n");
+    } else if (cur->type == XML_ATTRIBUTE_NODE)
+	xmlDebugDumpAttr(output, (xmlAttrPtr)cur, depth);
+    else
+	xmlDebugDumpOneNode(output, cur, depth);
+}
+
+void xmlXPathDebugDumpNodeSet(FILE *output, xmlNodeSetPtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    if (cur == NULL) {
+	fprintf(output, shift);
+	fprintf(output, "NodeSet is NULL !\n");
+	return;
+        
+    }
+
+    fprintf(output, "Set contains %d nodes:\n", cur->nodeNr);
+    for (i = 0;i < cur->nodeNr;i++) {
+	fprintf(output, shift);
+        fprintf(output, "%d", i + 1);
+	xmlXPathDebugDumpNode(output, cur->nodeTab[i], depth + 1);
+    }
+}
+
+#if defined(LIBXML_XPTR_ENABLED)
+void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
+void xmlXPathDebugDumpLocationSet(FILE *output, xmlLocationSetPtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    if (cur == NULL) {
+	fprintf(output, shift);
+	fprintf(output, "LocationSet is NULL !\n");
+	return;
+        
+    }
+
+    for (i = 0;i < cur->locNr;i++) {
+	fprintf(output, shift);
+        fprintf(output, "%d : ", i + 1);
+	xmlXPathDebugDumpObject(output, cur->locTab[i], depth + 1);
+    }
+}
+#endif
+
+void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth) {
+    int i;
+    char shift[100];
+
+    for (i = 0;((i < depth) && (i < 25));i++)
+        shift[2 * i] = shift[2 * i + 1] = ' ';
+    shift[2 * i] = shift[2 * i + 1] = 0;
+
+    fprintf(output, shift);
+
+    if (cur == NULL) {
+        fprintf(output, "Object is empty (NULL)\n");
+	return;
+    }
+    switch(cur->type) {
+        case XPATH_UNDEFINED:
+	    fprintf(output, "Object is uninitialized\n");
+	    break;
+        case XPATH_NODESET:
+	    fprintf(output, "Object is a Node Set :\n");
+	    xmlXPathDebugDumpNodeSet(output, cur->nodesetval, depth);
+	    break;
+	case XPATH_XSLT_TREE:
+	    fprintf(output, "Object is an XSLT value tree :\n");
+	    xmlXPathDebugDumpNode(output, cur->user, depth);
+	    break;
+        case XPATH_BOOLEAN:
+	    fprintf(output, "Object is a Boolean : ");
+	    if (cur->boolval) fprintf(output, "true\n");
+	    else fprintf(output, "false\n");
+	    break;
+        case XPATH_NUMBER:
+	    fprintf(output, "Object is a number : %0g\n", cur->floatval);
+	    break;
+        case XPATH_STRING:
+	    fprintf(output, "Object is a string : ");
+	    xmlDebugDumpString(output, cur->stringval);
+	    fprintf(output, "\n");
+	    break;
+	case XPATH_POINT:
+	    fprintf(output, "Object is a point : index %d in node", cur->index);
+	    xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user, depth + 1);
+	    fprintf(output, "\n");
+	    break;
+	case XPATH_RANGE:
+	    if ((cur->user2 == NULL) ||
+		((cur->user2 == cur->user) && (cur->index == cur->index2))) {
+		fprintf(output, "Object is a collapsed range :\n");
+		fprintf(output, shift);
+		if (cur->index >= 0)
+		    fprintf(output, "index %d in ", cur->index);
+		fprintf(output, "node\n");
+		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
+			              depth + 1);
+	    } else  {
+		fprintf(output, "Object is a range :\n");
+		fprintf(output, shift);
+		fprintf(output, "From ");
+		if (cur->index >= 0)
+		    fprintf(output, "index %d in ", cur->index);
+		fprintf(output, "node\n");
+		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user,
+			              depth + 1);
+		fprintf(output, shift);
+		fprintf(output, "To ");
+		if (cur->index2 >= 0)
+		    fprintf(output, "index %d in ", cur->index2);
+		fprintf(output, "node\n");
+		xmlXPathDebugDumpNode(output, (xmlNodePtr) cur->user2,
+			              depth + 1);
+		fprintf(output, "\n");
+	    }
+	    break;
+	case XPATH_LOCATIONSET:
+#if defined(LIBXML_XPTR_ENABLED)
+	    fprintf(output, "Object is a Location Set:\n");
+	    xmlXPathDebugDumpLocationSet(output,
+		    (xmlLocationSetPtr) cur->user, depth);
+#endif
+	    break;
+	case XPATH_USERS:
+	    fprintf(output, "Object is user defined\n");
+	    break;
+    }
+}
+#endif
+
+/************************************************************************
+ *									*
+ * 		Parser stacks related functions and macros		*
+ *									*
+ ************************************************************************/
+
+/*
+ * Generic function for accessing stacks in the Parser Context
+ */
+
+#define PUSH_AND_POP(type, name)					\
+extern int name##Push(xmlXPathParserContextPtr ctxt, type value) {	\
+    if (ctxt->name##Nr >= ctxt->name##Max) {				\
+	ctxt->name##Max *= 2;						\
+        ctxt->name##Tab = (type *) xmlRealloc(ctxt->name##Tab,		\
+	             ctxt->name##Max * sizeof(ctxt->name##Tab[0]));	\
+        if (ctxt->name##Tab == NULL) {					\
+	    xmlGenericError(xmlGenericErrorContext,			\
+		    "realloc failed !\n");				\
+	    return(0);							\
+	}								\
+    }									\
+    ctxt->name##Tab[ctxt->name##Nr] = value;				\
+    ctxt->name = value;							\
+    return(ctxt->name##Nr++);						\
+}									\
+extern type name##Pop(xmlXPathParserContextPtr ctxt) {			\
+    type ret;								\
+    if (ctxt->name##Nr <= 0) return(0);					\
+    ctxt->name##Nr--;							\
+    if (ctxt->name##Nr > 0)						\
+	ctxt->name = ctxt->name##Tab[ctxt->name##Nr - 1];		\
+    else								\
+        ctxt->name = NULL;						\
+    ret = ctxt->name##Tab[ctxt->name##Nr];				\
+    ctxt->name##Tab[ctxt->name##Nr] = 0;				\
+    return(ret);							\
+}									\
+
+PUSH_AND_POP(xmlXPathObjectPtr, value)
+
+/*
+ * Macros for accessing the content. Those should be used only by the parser,
+ * and not exported.
+ *
+ * Dirty macros, i.e. one need to make assumption on the context to use them
+ *
+ *   CUR_PTR return the current pointer to the xmlChar to be parsed.
+ *   CUR     returns the current xmlChar value, i.e. a 8 bit value
+ *           in ISO-Latin or UTF-8.
+ *           This should be used internally by the parser
+ *           only to compare to ASCII values otherwise it would break when
+ *           running with UTF-8 encoding.
+ *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
+ *           to compare on ASCII based substring.
+ *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
+ *           strings within the parser.
+ *   CURRENT Returns the current char value, with the full decoding of
+ *           UTF-8 if we are using this mode. It returns an int.
+ *   NEXT    Skip to the next character, this does the proper decoding
+ *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
+ *           It returns the pointer to the current xmlChar.
+ */
+
+#define CUR (*ctxt->cur)
+#define SKIP(val) ctxt->cur += (val)
+#define NXT(val) ctxt->cur[(val)]
+#define CUR_PTR ctxt->cur
+
+#define SKIP_BLANKS 							\
+    while (IS_BLANK(*(ctxt->cur))) NEXT
+
+#define CURRENT (*ctxt->cur)
+#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
+
+/************************************************************************
+ *									*
+ *			Error handling routines				*
+ *									*
+ ************************************************************************/
+
+
+const char *xmlXPathErrorMessages[] = {
+    "Ok",
+    "Number encoding",
+    "Unfinished litteral",
+    "Start of litteral",
+    "Expected $ for variable reference",
+    "Undefined variable",
+    "Invalid predicate",
+    "Invalid expression",
+    "Missing closing curly brace",
+    "Unregistered function",
+    "Invalid operand",
+    "Invalid type",
+    "Invalid number of arguments",
+    "Invalid context size",
+    "Invalid context position",
+    "Memory allocation error",
+    "Syntax error",
+    "Resource error",
+    "Sub resource error",
+    "Undefined namespace prefix"
+};
+
+/**
+ * xmlXPathError:
+ * @ctxt:  the XPath Parser context
+ * @file:  the file name
+ * @line:  the line number
+ * @no:  the error number
+ *
+ * Create a new xmlNodeSetPtr of type double and of value @val
+ *
+ * Returns the newly created object.
+ */
+void
+xmlXPatherror(xmlXPathParserContextPtr ctxt, const char *file,
+              int line, int no) {
+    int n;
+    const xmlChar *cur;
+    const xmlChar *base;
+
+    xmlGenericError(xmlGenericErrorContext,
+	    "Error %s:%d: %s\n", file, line,
+            xmlXPathErrorMessages[no]);
+
+    cur = ctxt->cur;
+    base = ctxt->base;
+    while ((cur > base) && ((*cur == '\n') || (*cur == '\r'))) {
+	cur--;
+    }
+    n = 0;
+    while ((n++ < 80) && (cur > base) && (*cur != '\n') && (*cur != '\r'))
+        cur--;
+    if ((*cur == '\n') || (*cur == '\r')) cur++;
+    base = cur;
+    n = 0;
+    while ((*cur != 0) && (*cur != '\n') && (*cur != '\r') && (n < 79)) {
+        xmlGenericError(xmlGenericErrorContext, "%c", (unsigned char) *cur++);
+	n++;
+    }
+    xmlGenericError(xmlGenericErrorContext, "\n");
+    cur = ctxt->cur;
+    while ((*cur == '\n') || (*cur == '\r'))
+	cur--;
+    n = 0;
+    while ((cur != base) && (n++ < 80)) {
+        xmlGenericError(xmlGenericErrorContext, " ");
+        base++;
+    }
+    xmlGenericError(xmlGenericErrorContext,"^\n");
+}
+
+
+/************************************************************************
+ *									*
+ *			Routines to handle NodeSets			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathCmpNodes:
+ * @node1:  the first node
+ * @node2:  the second node
+ *
+ * Compare two nodes w.r.t document order
+ *
+ * Returns -2 in case of error 1 if first point < second point, 0 if
+ *         that's the same node, -1 otherwise
+ */
+int
+xmlXPathCmpNodes(xmlNodePtr node1, xmlNodePtr node2) {
+    int depth1, depth2;
+    xmlNodePtr cur, root;
+
+    if ((node1 == NULL) || (node2 == NULL))
+	return(-2);
+    /*
+     * a couple of optimizations which will avoid computations in most cases
+     */
+    if (node1 == node2)
+	return(0);
+    if (node1 == node2->prev)
+	return(1);
+    if (node1 == node2->next)
+	return(-1);
+
+    /*
+     * compute depth to root
+     */
+    for (depth2 = 0, cur = node2;cur->parent != NULL;cur = cur->parent) {
+	if (cur == node1)
+	    return(1);
+	depth2++;
+    }
+    root = cur;
+    for (depth1 = 0, cur = node1;cur->parent != NULL;cur = cur->parent) {
+	if (cur == node2)
+	    return(-1);
+	depth1++;
+    }
+    /*
+     * Distinct document (or distinct entities :-( ) case.
+     */
+    if (root != cur) {
+	return(-2);
+    }
+    /*
+     * get the nearest common ancestor.
+     */
+    while (depth1 > depth2) {
+	depth1--;
+	node1 = node1->parent;
+    }
+    while (depth2 > depth1) {
+	depth2--;
+	node2 = node2->parent;
+    }
+    while (node1->parent != node2->parent) {
+	node1 = node1->parent;
+	node2 = node2->parent;
+	/* should not happen but just in case ... */
+	if ((node1 == NULL) || (node2 == NULL))
+	    return(-2);
+    }
+    /*
+     * Find who's first.
+     */
+    if (node1 == node2->next)
+	return(-1);
+    for (cur = node1->next;cur != NULL;cur = cur->next)
+	if (cur == node2)
+	    return(1);
+    return(-1); /* assume there is no sibling list corruption */
+}
+
+/**
+ * xmlXPathNodeSetSort:
+ * @set:  the node set
+ *
+ * Sort the node set in document order
+ */
+void
+xmlXPathNodeSetSort(xmlNodeSetPtr set) {
+    int i, j, incr, len, rc;
+    xmlNodePtr tmp;
+
+    if (set == NULL)
+	return;
+
+    /* Use Shell's sort to sort the node-set */
+    len = set->nodeNr;
+    for (incr = len / 2; incr > 0; incr /= 2) {
+	for (i = incr; i < len; i++) {
+	    j = i - incr;
+	    while (j >= 0) {
+		rc = xmlXPathCmpNodes(set->nodeTab[j], set->nodeTab[j + incr]);
+		if (rc != 1 && rc != -2) {
+		    tmp = set->nodeTab[j];
+		    set->nodeTab[j] = set->nodeTab[j + incr];
+		    set->nodeTab[j + incr] = tmp;
+		    j -= incr;
+		} else
+		    break;
+	    }
+	}
+    }
+}
+
+#define XML_NODESET_DEFAULT	10
+/**
+ * xmlXPathNodeSetCreate:
+ * @val:  an initial xmlNodePtr, or NULL
+ *
+ * Create a new xmlNodeSetPtr of type double and of value @val
+ *
+ * Returns the newly created object.
+ */
+xmlNodeSetPtr
+xmlXPathNodeSetCreate(xmlNodePtr val) {
+    xmlNodeSetPtr ret;
+
+    ret = (xmlNodeSetPtr) xmlMalloc(sizeof(xmlNodeSet));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewNodeSet: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlNodeSet));
+    if (val != NULL) {
+        ret->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
+					     sizeof(xmlNodePtr));
+	if (ret->nodeTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPathNewNodeSet: out of memory\n");
+	    return(NULL);
+	}
+	memset(ret->nodeTab, 0 ,
+	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
+        ret->nodeMax = XML_NODESET_DEFAULT;
+	ret->nodeTab[ret->nodeNr++] = val;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathNodeSetAdd:
+ * @cur:  the initial node set
+ * @val:  a new xmlNodePtr
+ *
+ * add a new xmlNodePtr ot an existing NodeSet
+ */
+void
+xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val) {
+    int i;
+
+    if (val == NULL) return;
+
+    /*
+     * check against doublons
+     */
+    for (i = 0;i < cur->nodeNr;i++)
+        if (cur->nodeTab[i] == val) return;
+
+    /*
+     * grow the nodeTab if needed
+     */
+    if (cur->nodeMax == 0) {
+        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
+					     sizeof(xmlNodePtr));
+	if (cur->nodeTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPathNodeSetAdd: out of memory\n");
+	    return;
+	}
+	memset(cur->nodeTab, 0 ,
+	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
+        cur->nodeMax = XML_NODESET_DEFAULT;
+    } else if (cur->nodeNr == cur->nodeMax) {
+        xmlNodePtr *temp;
+
+        cur->nodeMax *= 2;
+	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
+				      sizeof(xmlNodePtr));
+	if (temp == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPathNodeSetAdd: out of memory\n");
+	    return;
+	}
+	cur->nodeTab = temp;
+    }
+    cur->nodeTab[cur->nodeNr++] = val;
+}
+
+/**
+ * xmlXPathNodeSetAddUnique:
+ * @cur:  the initial node set
+ * @val:  a new xmlNodePtr
+ *
+ * add a new xmlNodePtr ot an existing NodeSet, optimized version
+ * when we are sure the node is not already in the set.
+ */
+void
+xmlXPathNodeSetAddUnique(xmlNodeSetPtr cur, xmlNodePtr val) {
+    if (val == NULL) return;
+
+    /*
+     * grow the nodeTab if needed
+     */
+    if (cur->nodeMax == 0) {
+        cur->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
+					     sizeof(xmlNodePtr));
+	if (cur->nodeTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPathNodeSetAddUnique: out of memory\n");
+	    return;
+	}
+	memset(cur->nodeTab, 0 ,
+	       XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
+        cur->nodeMax = XML_NODESET_DEFAULT;
+    } else if (cur->nodeNr == cur->nodeMax) {
+        xmlNodePtr *temp;
+
+        cur->nodeMax *= 2;
+	temp = (xmlNodePtr *) xmlRealloc(cur->nodeTab, cur->nodeMax *
+				      sizeof(xmlNodePtr));
+	if (temp == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPathNodeSetAddUnique: out of memory\n");
+	    return;
+	}
+	cur->nodeTab = temp;
+    }
+    cur->nodeTab[cur->nodeNr++] = val;
+}
+
+/**
+ * xmlXPathNodeSetMerge:
+ * @val1:  the first NodeSet or NULL
+ * @val2:  the second NodeSet
+ *
+ * Merges two nodesets, all nodes from @val2 are added to @val1
+ * if @val1 is NULL, a new set is created and copied from @val2
+ *
+ * Returns val1 once extended or NULL in case of error.
+ */
+xmlNodeSetPtr
+xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2) {
+    int i, j, initNr;
+
+    if (val2 == NULL) return(val1);
+    if (val1 == NULL) {
+	val1 = xmlXPathNodeSetCreate(NULL);
+    }
+
+    initNr = val1->nodeNr;
+
+    for (i = 0;i < val2->nodeNr;i++) {
+	/*
+	 * check against doublons
+	 */
+	for (j = 0; j < initNr; j++)
+	    if (val1->nodeTab[j] == val2->nodeTab[i]) continue;
+
+	/*
+	 * grow the nodeTab if needed
+	 */
+	if (val1->nodeMax == 0) {
+	    val1->nodeTab = (xmlNodePtr *) xmlMalloc(XML_NODESET_DEFAULT *
+						    sizeof(xmlNodePtr));
+	    if (val1->nodeTab == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+				"xmlXPathNodeSetMerge: out of memory\n");
+		return(NULL);
+	    }
+	    memset(val1->nodeTab, 0 ,
+		   XML_NODESET_DEFAULT * (size_t) sizeof(xmlNodePtr));
+	    val1->nodeMax = XML_NODESET_DEFAULT;
+	} else if (val1->nodeNr == val1->nodeMax) {
+	    xmlNodePtr *temp;
+
+	    val1->nodeMax *= 2;
+	    temp = (xmlNodePtr *) xmlRealloc(val1->nodeTab, val1->nodeMax *
+					     sizeof(xmlNodePtr));
+	    if (temp == NULL) {
+		xmlGenericError(xmlGenericErrorContext,
+				"xmlXPathNodeSetMerge: out of memory\n");
+		return(NULL);
+	    }
+	    val1->nodeTab = temp;
+	}
+	val1->nodeTab[val1->nodeNr++] = val2->nodeTab[i];
+    }
+
+    return(val1);
+}
+
+/**
+ * xmlXPathNodeSetDel:
+ * @cur:  the initial node set
+ * @val:  an xmlNodePtr
+ *
+ * Removes an xmlNodePtr from an existing NodeSet
+ */
+void
+xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val) {
+    int i;
+
+    if (cur == NULL) return;
+    if (val == NULL) return;
+
+    /*
+     * check against doublons
+     */
+    for (i = 0;i < cur->nodeNr;i++)
+        if (cur->nodeTab[i] == val) break;
+
+    if (i >= cur->nodeNr) {
+#ifdef DEBUG
+        xmlGenericError(xmlGenericErrorContext, 
+	        "xmlXPathNodeSetDel: Node %s wasn't found in NodeList\n",
+		val->name);
+#endif
+        return;
+    }
+    cur->nodeNr--;
+    for (;i < cur->nodeNr;i++)
+        cur->nodeTab[i] = cur->nodeTab[i + 1];
+    cur->nodeTab[cur->nodeNr] = NULL;
+}
+
+/**
+ * xmlXPathNodeSetRemove:
+ * @cur:  the initial node set
+ * @val:  the index to remove
+ *
+ * Removes an entry from an existing NodeSet list.
+ */
+void
+xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val) {
+    if (cur == NULL) return;
+    if (val >= cur->nodeNr) return;
+    cur->nodeNr--;
+    for (;val < cur->nodeNr;val++)
+        cur->nodeTab[val] = cur->nodeTab[val + 1];
+    cur->nodeTab[cur->nodeNr] = NULL;
+}
+
+/**
+ * xmlXPathFreeNodeSet:
+ * @obj:  the xmlNodeSetPtr to free
+ *
+ * Free the NodeSet compound (not the actual nodes !).
+ */
+void
+xmlXPathFreeNodeSet(xmlNodeSetPtr obj) {
+    if (obj == NULL) return;
+    if (obj->nodeTab != NULL) {
+#ifdef DEBUG
+	memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
+#endif
+	xmlFree(obj->nodeTab);
+    }
+#ifdef DEBUG
+    memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
+#endif
+    xmlFree(obj);
+}
+
+/**
+ * xmlXPathFreeValueTree:
+ * @obj:  the xmlNodeSetPtr to free
+ *
+ * Free the NodeSet compound and the actual tree, this is different
+ * from xmlXPathFreeNodeSet()
+ */
+void
+xmlXPathFreeValueTree(xmlNodeSetPtr obj) {
+    int i;
+
+    if (obj == NULL) return;
+    for (i = 0;i < obj->nodeNr;i++)
+        if (obj->nodeTab[i] != NULL)
+	    xmlFreeNode(obj->nodeTab[i]);
+
+    if (obj->nodeTab != NULL) {
+#ifdef DEBUG
+	memset(obj->nodeTab, 0xB , (size_t) sizeof(xmlNodePtr) * obj->nodeMax);
+#endif
+	xmlFree(obj->nodeTab);
+    }
+#ifdef DEBUG
+    memset(obj, 0xB , (size_t) sizeof(xmlNodeSet));
+#endif
+    xmlFree(obj);
+}
+
+#if defined(DEBUG) || defined(DEBUG_STEP)
+/**
+ * xmlGenericErrorContextNodeSet:
+ * @output:  a FILE * for the output
+ * @obj:  the xmlNodeSetPtr to free
+ *
+ * Quick display of a NodeSet
+ */
+void
+xmlGenericErrorContextNodeSet(FILE *output, xmlNodeSetPtr obj) {
+    int i;
+
+    if (output == NULL) output = xmlGenericErrorContext;
+    if (obj == NULL)  {
+        fprintf(output, "NodeSet == NULL !\n");
+	return;
+    }
+    if (obj->nodeNr == 0) {
+        fprintf(output, "NodeSet is empty\n");
+	return;
+    }
+    if (obj->nodeTab == NULL) {
+	fprintf(output, " nodeTab == NULL !\n");
+	return;
+    }
+    for (i = 0; i < obj->nodeNr; i++) {
+        if (obj->nodeTab[i] == NULL) {
+	    fprintf(output, " NULL !\n");
+	    return;
+        }
+	if ((obj->nodeTab[i]->type == XML_DOCUMENT_NODE) ||
+	    (obj->nodeTab[i]->type == XML_HTML_DOCUMENT_NODE))
+	    fprintf(output, " /");
+	else if (obj->nodeTab[i]->name == NULL)
+	    fprintf(output, " noname!");
+	else fprintf(output, " %s", obj->nodeTab[i]->name);
+    }
+    fprintf(output, "\n");
+}
+#endif
+
+/**
+ * xmlXPathNewNodeSet:
+ * @val:  the NodePtr value
+ *
+ * Create a new xmlXPathObjectPtr of type NodeSet and initialize
+ * it with the single Node @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewNodeSet(xmlNodePtr val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewNodeSet: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_NODESET;
+    ret->nodesetval = xmlXPathNodeSetCreate(val);
+    return(ret);
+}
+
+/**
+ * xmlXPathNewValueTree:
+ * @val:  the NodePtr value
+ *
+ * Create a new xmlXPathObjectPtr of type Value Tree (XSLT) and initialize
+ * it with the tree root @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewValueTree(xmlNodePtr val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewNodeSet: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_XSLT_TREE;
+    ret->nodesetval = xmlXPathNodeSetCreate(val);
+    return(ret);
+}
+
+/**
+ * xmlXPathNewNodeSetList:
+ * @val:  an existing NodeSet
+ *
+ * Create a new xmlXPathObjectPtr of type NodeSet and initialize
+ * it with the Nodeset @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewNodeSetList(xmlNodeSetPtr val) {
+    xmlXPathObjectPtr ret;
+    int i;
+
+    if (val == NULL)
+    	ret = NULL;
+    else if (val->nodeTab == NULL)
+	    ret = xmlXPathNewNodeSet(NULL);
+    else
+    	{
+	    ret = xmlXPathNewNodeSet(val->nodeTab[0]);
+	    for (i = 1; i < val->nodeNr; ++i)
+	    	xmlXPathNodeSetAddUnique(ret->nodesetval, val->nodeTab[i]);
+	    }
+
+    return(ret);
+}
+
+/**
+ * xmlXPathWrapNodeSet:
+ * @val:  the NodePtr value
+ *
+ * Wrap the Nodeset @val in a new xmlXPathObjectPtr
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathWrapNodeSet(xmlNodeSetPtr val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathWrapNodeSet: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_NODESET;
+    ret->nodesetval = val;
+    return(ret);
+}
+
+/**
+ * xmlXPathFreeNodeSetList:
+ * @obj:  an existing NodeSetList object
+ *
+ * Free up the xmlXPathObjectPtr @obj but don't deallocate the objects in
+ * the list contrary to xmlXPathFreeObject().
+ */
+void
+xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj) {
+    if (obj == NULL) return;
+#ifdef DEBUG
+    memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
+#endif
+    xmlFree(obj);
+}
+
+/************************************************************************
+ *									*
+ *		Routines to handle extra functions			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathRegisterFunc:
+ * @ctxt:  the XPath context
+ * @name:  the function name
+ * @f:  the function implementation or NULL
+ *
+ * Register a new function. If @f is NULL it unregisters the function
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int		  
+xmlXPathRegisterFunc(xmlXPathContextPtr ctxt, const xmlChar *name,
+		     xmlXPathFunction f) {
+    return(xmlXPathRegisterFuncNS(ctxt, name, NULL, f));
+}
+
+/**
+ * xmlXPathRegisterFuncNS:
+ * @ctxt:  the XPath context
+ * @name:  the function name
+ * @ns_uri:  the function namespace URI
+ * @f:  the function implementation or NULL
+ *
+ * Register a new function. If @f is NULL it unregisters the function
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xmlXPathRegisterFuncNS(xmlXPathContextPtr ctxt, const xmlChar *name,
+		       const xmlChar *ns_uri, xmlXPathFunction f) {
+    if (ctxt == NULL)
+	return(-1);
+    if (name == NULL)
+	return(-1);
+
+    if (ctxt->funcHash == NULL)
+	ctxt->funcHash = xmlHashCreate(0);
+    if (ctxt->funcHash == NULL)
+	return(-1);
+    return(xmlHashAddEntry2(ctxt->funcHash, name, ns_uri, (void *) f));
+}
+
+/**
+ * xmlXPathFunctionLookup:
+ * @ctxt:  the XPath context
+ * @name:  the function name
+ *
+ * Search in the Function array of the context for the given
+ * function.
+ *
+ * Returns the xmlXPathFunction or NULL if not found
+ */
+xmlXPathFunction
+xmlXPathFunctionLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
+    return(xmlXPathFunctionLookupNS(ctxt, name, NULL));
+}
+
+/**
+ * xmlXPathFunctionLookupNS:
+ * @ctxt:  the XPath context
+ * @name:  the function name
+ * @ns_uri:  the function namespace URI
+ *
+ * Search in the Function array of the context for the given
+ * function.
+ *
+ * Returns the xmlXPathFunction or NULL if not found
+ */
+xmlXPathFunction
+xmlXPathFunctionLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
+			 const xmlChar *ns_uri) {
+    if (ctxt == NULL)
+	return(NULL);
+    if (ctxt->funcHash == NULL)
+	return(NULL);
+    if (name == NULL)
+	return(NULL);
+
+    return((xmlXPathFunction) xmlHashLookup2(ctxt->funcHash, name, ns_uri));
+}
+
+/**
+ * xmlXPathRegisteredFuncsCleanup:
+ * @ctxt:  the XPath context
+ *
+ * Cleanup the XPath context data associated to registered functions
+ */
+void
+xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+
+    xmlHashFree(ctxt->funcHash, NULL);
+    ctxt->funcHash = NULL;
+}
+
+/************************************************************************
+ *									*
+ *			Routines to handle Variable			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathRegisterVariable:
+ * @ctxt:  the XPath context
+ * @name:  the variable name
+ * @value:  the variable value or NULL
+ *
+ * Register a new variable value. If @value is NULL it unregisters
+ * the variable
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int		  
+xmlXPathRegisterVariable(xmlXPathContextPtr ctxt, const xmlChar *name,
+			 xmlXPathObjectPtr value) {
+    return(xmlXPathRegisterVariableNS(ctxt, name, NULL, value));
+}
+
+/**
+ * xmlXPathRegisterVariableNS:
+ * @ctxt:  the XPath context
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ * @value:  the variable value or NULL
+ *
+ * Register a new variable value. If @value is NULL it unregisters
+ * the variable
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xmlXPathRegisterVariableNS(xmlXPathContextPtr ctxt, const xmlChar *name,
+			   const xmlChar *ns_uri,
+			   xmlXPathObjectPtr value) {
+    if (ctxt == NULL)
+	return(-1);
+    if (name == NULL)
+	return(-1);
+
+    if (ctxt->varHash == NULL)
+	ctxt->varHash = xmlHashCreate(0);
+    if (ctxt->varHash == NULL)
+	return(-1);
+    return(xmlHashUpdateEntry2(ctxt->varHash, name, ns_uri,
+			       (void *) value,
+			       (xmlHashDeallocator)xmlXPathFreeObject));
+}
+
+/**
+ * xmlXPathRegisterVariableLookup:
+ * @ctxt:  the XPath context
+ * @f:  the lookup function
+ * @data:  the lookup data
+ *
+ * register an external mechanism to do variable lookup
+ */
+void
+xmlXPathRegisterVariableLookup(xmlXPathContextPtr ctxt,
+	 xmlXPathVariableLookupFunc f, void *data) {
+    if (ctxt == NULL)
+	return;
+    ctxt->varLookupFunc = (void *) f;
+    ctxt->varLookupData = data;
+}
+
+/**
+ * xmlXPathVariableLookup:
+ * @ctxt:  the XPath context
+ * @name:  the variable name
+ *
+ * Search in the Variable array of the context for the given
+ * variable value.
+ *
+ * Returns the value or NULL if not found
+ */
+xmlXPathObjectPtr
+xmlXPathVariableLookup(xmlXPathContextPtr ctxt, const xmlChar *name) {
+    if (ctxt == NULL)
+	return(NULL);
+
+    if (ctxt->varLookupFunc != NULL) {
+	xmlXPathObjectPtr ret;
+
+	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
+	        (ctxt->varLookupData, name, NULL);
+	if (ret != NULL) return(ret);
+    }
+    return(xmlXPathVariableLookupNS(ctxt, name, NULL));
+}
+
+/**
+ * xmlXPathVariableLookupNS:
+ * @ctxt:  the XPath context
+ * @name:  the variable name
+ * @ns_uri:  the variable namespace URI
+ *
+ * Search in the Variable array of the context for the given
+ * variable value.
+ *
+ * Returns the value or NULL if not found
+ */
+xmlXPathObjectPtr
+xmlXPathVariableLookupNS(xmlXPathContextPtr ctxt, const xmlChar *name,
+			 const xmlChar *ns_uri) {
+    if (ctxt == NULL)
+	return(NULL);
+
+    if (ctxt->varLookupFunc != NULL) {
+	xmlXPathObjectPtr ret;
+
+	ret = ((xmlXPathVariableLookupFunc)ctxt->varLookupFunc)
+	        (ctxt->varLookupData, name, ns_uri);
+	if (ret != NULL) return(ret);
+    }
+
+    if (ctxt->varHash == NULL)
+	return(NULL);
+    if (name == NULL)
+	return(NULL);
+
+    return((xmlXPathObjectPtr) xmlHashLookup2(ctxt->varHash, name, ns_uri));
+}
+
+/**
+ * xmlXPathRegisteredVariablesCleanup:
+ * @ctxt:  the XPath context
+ *
+ * Cleanup the XPath context data associated to registered variables
+ */
+void
+xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+
+    xmlHashFree(ctxt->varHash, NULL);
+    ctxt->varHash = NULL;
+}
+
+/**
+ * xmlXPathRegisterNs:
+ * @ctxt:  the XPath context
+ * @prefix:  the namespace prefix
+ * @ns_uri:  the namespace name
+ *
+ * Register a new namespace. If @ns_uri is NULL it unregisters
+ * the namespace
+ *
+ * Returns 0 in case of success, -1 in case of error
+ */
+int
+xmlXPathRegisterNs(xmlXPathContextPtr ctxt, const xmlChar *prefix,
+			   const xmlChar *ns_uri) {
+    if (ctxt == NULL)
+	return(-1);
+    if (prefix == NULL)
+	return(-1);
+
+    if (ctxt->nsHash == NULL)
+	ctxt->nsHash = xmlHashCreate(10);
+    if (ctxt->nsHash == NULL)
+	return(-1);
+    return(xmlHashUpdateEntry(ctxt->nsHash, prefix, (void *) ns_uri,
+			      (xmlHashDeallocator)xmlFree));
+}
+
+/**
+ * xmlXPathNsLookup:
+ * @ctxt:  the XPath context
+ * @prefix:  the namespace prefix value
+ *
+ * Search in the namespace declaration array of the context for the given
+ * namespace name associated to the given prefix
+ *
+ * Returns the value or NULL if not found
+ */
+const xmlChar *
+xmlXPathNsLookup(xmlXPathContextPtr ctxt, const xmlChar *prefix) {
+    if (ctxt == NULL)
+	return(NULL);
+    if (prefix == NULL)
+	return(NULL);
+
+#ifdef XML_XML_NAMESPACE
+    if (xmlStrEqual(prefix, (const xmlChar *) "xml"))
+	return(XML_XML_NAMESPACE);
+#endif
+
+    if (ctxt->nsHash == NULL)
+	return(NULL);
+
+    return((const xmlChar *) xmlHashLookup(ctxt->nsHash, prefix));
+}
+
+/**
+ * xmlXPathRegisteredVariablesCleanup:
+ * @ctxt:  the XPath context
+ *
+ * Cleanup the XPath context data associated to registered variables
+ */
+void
+xmlXPathRegisteredNsCleanup(xmlXPathContextPtr ctxt) {
+    if (ctxt == NULL)
+	return;
+
+    xmlHashFree(ctxt->nsHash, NULL);
+    ctxt->nsHash = NULL;
+}
+
+/************************************************************************
+ *									*
+ *			Routines to handle Values			*
+ *									*
+ ************************************************************************/
+
+/* Allocations are terrible, one need to optimize all this !!! */
+
+/**
+ * xmlXPathNewFloat:
+ * @val:  the double value
+ *
+ * Create a new xmlXPathObjectPtr of type double and of value @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewFloat(double val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewFloat: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_NUMBER;
+    ret->floatval = val;
+    return(ret);
+}
+
+/**
+ * xmlXPathNewBoolean:
+ * @val:  the boolean value
+ *
+ * Create a new xmlXPathObjectPtr of type boolean and of value @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewBoolean(int val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewBoolean: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_BOOLEAN;
+    ret->boolval = (val != 0);
+    return(ret);
+}
+
+/**
+ * xmlXPathNewString:
+ * @val:  the xmlChar * value
+ *
+ * Create a new xmlXPathObjectPtr of type string and of value @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewString(const xmlChar *val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewString: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_STRING;
+    if (val != NULL)
+	ret->stringval = xmlStrdup(val);
+    else
+	ret->stringval = xmlStrdup((const xmlChar *)"");
+    return(ret);
+}
+
+/**
+ * xmlXPathNewCString:
+ * @val:  the char * value
+ *
+ * Create a new xmlXPathObjectPtr of type string and of value @val
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathNewCString(const char *val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewCString: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_STRING;
+    ret->stringval = xmlStrdup(BAD_CAST val);
+    return(ret);
+}
+
+/**
+ * xmlXPathObjectCopy:
+ * @val:  the original object
+ *
+ * allocate a new copy of a given object
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPathObjectCopy(xmlXPathObjectPtr val) {
+    xmlXPathObjectPtr ret;
+
+    if (val == NULL)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathObjectCopy: out of memory\n");
+	return(NULL);
+    }
+    memcpy(ret, val , (size_t) sizeof(xmlXPathObject));
+    switch (val->type) {
+	case XPATH_BOOLEAN:
+	case XPATH_NUMBER:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	    break;
+	case XPATH_STRING:
+	    ret->stringval = xmlStrdup(val->stringval);
+	    break;
+	case XPATH_XSLT_TREE:
+	    if ((val->nodesetval != NULL) &&
+		(val->nodesetval->nodeTab != NULL))
+		ret->nodesetval = xmlXPathNodeSetCreate(
+			xmlCopyNode(val->nodesetval->nodeTab[0], 1));
+	    else
+		ret->nodesetval = xmlXPathNodeSetCreate(NULL);
+	    break;
+	case XPATH_NODESET:
+	    ret->nodesetval = xmlXPathNodeSetMerge(NULL, val->nodesetval);
+	    break;
+	case XPATH_LOCATIONSET:
+#ifdef LIBXML_XPTR_ENABLED
+	{
+	    xmlLocationSetPtr loc = val->user;
+	    ret->user = (void *) xmlXPtrLocationSetMerge(NULL, loc);
+	    break;
+	}
+#endif
+	case XPATH_UNDEFINED:
+	case XPATH_USERS:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPathObjectCopy: unsupported type %d\n",
+		    val->type);
+	    break;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathFreeObject:
+ * @obj:  the object to free
+ *
+ * Free up an xmlXPathObjectPtr object.
+ */
+void
+xmlXPathFreeObject(xmlXPathObjectPtr obj) {
+    if (obj == NULL) return;
+    if (obj->type == XPATH_NODESET) {
+	if (obj->nodesetval != NULL)
+	    xmlXPathFreeNodeSet(obj->nodesetval);
+#ifdef LIBXML_XPTR_ENABLED
+    } else if (obj->type == XPATH_LOCATIONSET) {
+	if (obj->user != NULL)
+	    xmlXPtrFreeLocationSet(obj->user);
+#endif
+    } else if (obj->type == XPATH_STRING) {
+	if (obj->stringval != NULL)
+	    xmlFree(obj->stringval);
+    } else if (obj->type == XPATH_XSLT_TREE) {
+	if (obj->nodesetval != NULL)
+	    xmlXPathFreeValueTree(obj->nodesetval);
+    }
+
+#ifdef DEBUG
+    memset(obj, 0xB , (size_t) sizeof(xmlXPathObject));
+#endif
+    xmlFree(obj);
+}
+
+/************************************************************************
+ *									*
+ *		Routines to handle XPath contexts			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathNewContext:
+ * @doc:  the XML document
+ *
+ * Create a new xmlXPathContext
+ *
+ * Returns the xmlXPathContext just allocated.
+ */
+xmlXPathContextPtr
+xmlXPathNewContext(xmlDocPtr doc) {
+    xmlXPathContextPtr ret;
+
+    ret = (xmlXPathContextPtr) xmlMalloc(sizeof(xmlXPathContext));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewContext: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathContext));
+    ret->doc = doc;
+    ret->node = NULL;
+
+    ret->varHash = NULL;
+
+    ret->nb_types = 0;
+    ret->max_types = 0;
+    ret->types = NULL;
+
+    ret->funcHash = xmlHashCreate(0);
+
+    ret->nb_axis = 0;
+    ret->max_axis = 0;
+    ret->axis = NULL;
+
+    ret->nsHash = NULL;
+    ret->user = NULL;
+
+    ret->contextSize = -1;
+    ret->proximityPosition = -1;
+
+    xmlXPathRegisterAllFunctions(ret);
+    
+    return(ret);
+}
+
+/**
+ * xmlXPathFreeContext:
+ * @ctxt:  the context to free
+ *
+ * Free up an xmlXPathContext
+ */
+void
+xmlXPathFreeContext(xmlXPathContextPtr ctxt) {
+    xmlXPathRegisteredNsCleanup(ctxt);
+    xmlXPathRegisteredFuncsCleanup(ctxt);
+    xmlXPathRegisteredVariablesCleanup(ctxt);
+#ifdef DEBUG
+    memset(ctxt, 0xB , (size_t) sizeof(xmlXPathContext));
+#endif
+    xmlFree(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *		Routines to handle XPath parser contexts		*
+ *									*
+ ************************************************************************/
+
+#define CHECK_CTXT(ctxt)						\
+    if (ctxt == NULL) { 						\
+        xmlGenericError(xmlGenericErrorContext,				\
+		"%s:%d Internal error: ctxt == NULL\n",			\
+	        __FILE__, __LINE__);					\
+    }									\
+
+
+#define CHECK_CONTEXT(ctxt)						\
+    if (ctxt == NULL) { 						\
+        xmlGenericError(xmlGenericErrorContext,				\
+		"%s:%d Internal error: no context\n",			\
+	        __FILE__, __LINE__);					\
+    }									\
+    else if (ctxt->doc == NULL) { 					\
+        xmlGenericError(xmlGenericErrorContext,				\
+		"%s:%d Internal error: no document\n",			\
+	        __FILE__, __LINE__);					\
+    }									\
+    else if (ctxt->doc->children == NULL) { 				\
+        xmlGenericError(xmlGenericErrorContext,				\
+	        "%s:%d Internal error: document without root\n",	\
+	        __FILE__, __LINE__);					\
+    }									\
+
+
+/**
+ * xmlXPathNewParserContext:
+ * @str:  the XPath expression
+ * @ctxt:  the XPath context
+ *
+ * Create a new xmlXPathParserContext
+ *
+ * Returns the xmlXPathParserContext just allocated.
+ */
+xmlXPathParserContextPtr
+xmlXPathNewParserContext(const xmlChar *str, xmlXPathContextPtr ctxt) {
+    xmlXPathParserContextPtr ret;
+
+    ret = (xmlXPathParserContextPtr) xmlMalloc(sizeof(xmlXPathParserContext));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathNewParserContext: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathParserContext));
+    ret->cur = ret->base = str;
+    ret->context = ctxt;
+
+    /* Allocate the value stack */
+    ret->valueTab = (xmlXPathObjectPtr *) 
+                     xmlMalloc(10 * sizeof(xmlXPathObjectPtr));
+    ret->valueNr = 0;
+    ret->valueMax = 10;
+    ret->value = NULL;
+    return(ret);
+}
+
+/**
+ * xmlXPathFreeParserContext:
+ * @ctxt:  the context to free
+ *
+ * Free up an xmlXPathParserContext
+ */
+void
+xmlXPathFreeParserContext(xmlXPathParserContextPtr ctxt) {
+    if (ctxt->valueTab != NULL) {
+#ifdef DEBUG
+        memset(ctxt->valueTab, 0xB , 10 * (size_t) sizeof(xmlXPathObjectPtr));
+#endif
+        xmlFree(ctxt->valueTab);
+    }
+#ifdef DEBUG
+    memset(ctxt, 0xB , (size_t) sizeof(xmlXPathParserContext));
+#endif
+    xmlFree(ctxt);
+}
+
+/************************************************************************
+ *									*
+ *		The implicit core function library			*
+ *									*
+ ************************************************************************/
+
+/*
+ * Auto-pop and cast to a number
+ */
+void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
+
+
+#define POP_FLOAT						\
+    arg = valuePop(ctxt);					\
+    if (arg == NULL) {						\
+	XP_ERROR(XPATH_INVALID_OPERAND);				\
+    }								\
+    if (arg->type != XPATH_NUMBER) {				\
+        valuePush(ctxt, arg);					\
+        xmlXPathNumberFunction(ctxt, 1);			\
+	arg = valuePop(ctxt);					\
+    }
+
+/**
+ * xmlXPathCompareNodeSetFloat:
+ * @ctxt:  the XPath Parser context
+ * @inf:  less than (1) or greater than (0)
+ * @strict:  is the comparison strict
+ * @arg:  the node set
+ * @f:  the value
+ *
+ * Implement the compare operation between a nodeset and a number
+ *     @ns < @val    (1, 1, ...
+ *     @ns <= @val   (1, 0, ...
+ *     @ns > @val    (0, 1, ...
+ *     @ns >= @val   (0, 0, ...
+ *
+ * If one object to be compared is a node-set and the other is a number,
+ * then the comparison will be true if and only if there is a node in the
+ * node-set such that the result of performing the comparison on the number
+ * to be compared and on the result of converting the string-value of that
+ * node to a number using the number function is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathCompareNodeSetFloat(xmlXPathParserContextPtr ctxt, int inf, int strict,
+	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr f) {
+    int i, ret = 0;
+    xmlNodeSetPtr ns;
+    xmlChar *str2;
+
+    if ((f == NULL) || (arg == NULL) ||
+	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
+	xmlXPathFreeObject(arg);
+	xmlXPathFreeObject(f);
+        return(0);
+    }
+    ns = arg->nodesetval;
+    for (i = 0;i < ns->nodeNr;i++) {
+         str2 = xmlNodeGetContent(ns->nodeTab[i]);
+	 if (str2 != NULL) {
+	     valuePush(ctxt,
+		       xmlXPathNewString(str2));
+	     xmlFree(str2);
+	     xmlXPathNumberFunction(ctxt, 1);
+	     valuePush(ctxt, xmlXPathObjectCopy(f));
+	     ret = xmlXPathCompareValues(ctxt, inf, strict);
+	     if (ret)
+		 break;
+	 }
+    }
+    xmlXPathFreeObject(arg);
+    xmlXPathFreeObject(f);
+    return(ret);
+}
+
+/**
+ * xmlXPathCompareNodeSetString:
+ * @ctxt:  the XPath Parser context
+ * @inf:  less than (1) or greater than (0)
+ * @strict:  is the comparison strict
+ * @arg:  the node set
+ * @s:  the value
+ *
+ * Implement the compare operation between a nodeset and a string
+ *     @ns < @val    (1, 1, ...
+ *     @ns <= @val   (1, 0, ...
+ *     @ns > @val    (0, 1, ...
+ *     @ns >= @val   (0, 0, ...
+ *
+ * If one object to be compared is a node-set and the other is a string,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * string-value of the node and the other string is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathCompareNodeSetString(xmlXPathParserContextPtr ctxt, int inf, int strict,
+	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr s) {
+    int i, ret = 0;
+    xmlNodeSetPtr ns;
+    xmlChar *str2;
+
+    if ((s == NULL) || (arg == NULL) ||
+	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE))) {
+	xmlXPathFreeObject(arg);
+	xmlXPathFreeObject(s);
+        return(0);
+    }
+    ns = arg->nodesetval;
+    for (i = 0;i < ns->nodeNr;i++) {
+         str2 = xmlNodeGetContent(ns->nodeTab[i]);
+	 if (str2 != NULL) {
+	     valuePush(ctxt,
+		       xmlXPathNewString(str2));
+	     xmlFree(str2);
+	     valuePush(ctxt, xmlXPathObjectCopy(s));
+	     ret = xmlXPathCompareValues(ctxt, inf, strict);
+	     if (ret)
+		 break;
+	 }
+    }
+    xmlXPathFreeObject(arg);
+    xmlXPathFreeObject(s);
+    return(ret);
+}
+
+/**
+ * xmlXPathCompareNodeSets:
+ * @ctxt:  the XPath Parser context
+ * @op:  less than (-1), equal (0) or greater than (1)
+ * @strict:  is the comparison strict
+ * @arg1:  the fist node set object
+ * @arg2:  the second node set object
+ *
+ * Implement the compare operation on nodesets:
+ *
+ * If both objects to be compared are node-sets, then the comparison
+ * will be true if and only if there is a node in the first node-set
+ * and a node in the second node-set such that the result of performing
+ * the comparison on the string-values of the two nodes is true. 
+ * ....
+ * When neither object to be compared is a node-set and the operator
+ * is <=, <, >= or >, then the objects are compared by converting both
+ * objects to numbers and comparing the numbers according to IEEE 754.
+ * ....
+ * The number function converts its argument to a number as follows:
+ *  - a string that consists of optional whitespace followed by an
+ *    optional minus sign followed by a Number followed by whitespace
+ *    is converted to the IEEE 754 number that is nearest (according
+ *    to the IEEE 754 round-to-nearest rule) to the mathematical value
+ *    represented by the string; any other string is converted to NaN
+ *
+ * Conclusion all nodes need to be converted first to their string value
+ * and then the comparison must be done when possible 
+ */
+int
+xmlXPathCompareNodeSets(xmlXPathParserContextPtr ctxt, int inf, int strict,
+	                xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
+    int i, j, init = 0;
+    double val1;
+    double *values2;
+    int ret = 0;
+    xmlChar *str;
+    xmlNodeSetPtr ns1;
+    xmlNodeSetPtr ns2;
+
+    if ((arg1 == NULL) ||
+	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
+        return(0);
+    if ((arg2 == NULL) ||
+	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
+        return(0);
+
+    ns1 = arg1->nodesetval;
+    ns2 = arg2->nodesetval;
+
+    if (ns1->nodeNr <= 0)
+	return(0);
+    if (ns2->nodeNr <= 0)
+	return(0);
+
+    values2 = (double *) xmlMalloc(ns2->nodeNr * sizeof(double));
+    if (values2 == NULL) {
+	return(0);
+    }
+    for (i = 0;i < ns1->nodeNr;i++) {
+	str = xmlNodeGetContent(ns1->nodeTab[i]);
+	if (str == NULL)
+	    continue;
+	val1 = xmlXPathStringEvalNumber(str);
+	xmlFree(str);
+	if (isnan(val1))
+	    continue;
+	for (j = 0;j < ns2->nodeNr;j++) {
+	    if (init == 0) {
+		str = xmlNodeGetContent(ns2->nodeTab[j]);
+		if (str == NULL) {
+		    values2[j] = xmlXPathNAN;
+		} else {
+		    values2[j] = xmlXPathStringEvalNumber(str);
+		    xmlFree(str);
+		}
+	    }
+	    if (isnan(values2[j]))
+		continue;
+	    if (inf && strict) 
+		ret = (val1 < values2[j]);
+	    else if (inf && !strict)
+		ret = (val1 <= values2[j]);
+	    else if (!inf && strict)
+		ret = (val1 > values2[j]);
+	    else if (!inf && !strict)
+		ret = (val1 >= values2[j]);
+	    if (ret)
+		break;
+	}
+	if (ret)
+	    break;
+	init = 1;
+    }
+    xmlFree(values2);
+    return(ret);
+    return(0);
+}
+
+/**
+ * xmlXPathCompareNodeSetValue:
+ * @ctxt:  the XPath Parser context
+ * @inf:  less than (1) or greater than (0)
+ * @strict:  is the comparison strict
+ * @arg:  the node set
+ * @val:  the value
+ *
+ * Implement the compare operation between a nodeset and a value
+ *     @ns < @val    (1, 1, ...
+ *     @ns <= @val   (1, 0, ...
+ *     @ns > @val    (0, 1, ...
+ *     @ns >= @val   (0, 0, ...
+ *
+ * If one object to be compared is a node-set and the other is a boolean,
+ * then the comparison will be true if and only if the result of performing
+ * the comparison on the boolean and on the result of converting
+ * the node-set to a boolean using the boolean function is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathCompareNodeSetValue(xmlXPathParserContextPtr ctxt, int inf, int strict,
+	                    xmlXPathObjectPtr arg, xmlXPathObjectPtr val) {
+    if ((val == NULL) || (arg == NULL) ||
+	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
+        return(0);
+
+    switch(val->type) {
+        case XPATH_NUMBER:
+	    return(xmlXPathCompareNodeSetFloat(ctxt, inf, strict, arg, val));
+        case XPATH_NODESET:
+        case XPATH_XSLT_TREE:
+	    return(xmlXPathCompareNodeSets(ctxt, inf, strict, arg, val));
+        case XPATH_STRING:
+	    return(xmlXPathCompareNodeSetString(ctxt, inf, strict, arg, val));
+        case XPATH_BOOLEAN:
+	    valuePush(ctxt, arg);
+	    xmlXPathBooleanFunction(ctxt, 1);
+	    valuePush(ctxt, val);
+	    return(xmlXPathCompareValues(ctxt, inf, strict));
+	default:
+	    TODO
+	    return(0);
+    }
+    return(0);
+}
+
+/**
+ * xmlXPathEqualNodeSetString
+ * @arg:  the nodeset object argument
+ * @str:  the string to compare to.
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ * If one object to be compared is a node-set and the other is a string,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * string-value of the node and the other string is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualNodeSetString(xmlXPathObjectPtr arg, const xmlChar *str) {
+    int i;
+    xmlNodeSetPtr ns;
+    xmlChar *str2;
+
+    if ((str == NULL) || (arg == NULL) ||
+	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
+        return(0);
+    ns = arg->nodesetval;
+    if (ns->nodeNr <= 0)
+	return(0);
+    for (i = 0;i < ns->nodeNr;i++) {
+         str2 = xmlNodeGetContent(ns->nodeTab[i]);
+	 if ((str2 != NULL) && (xmlStrEqual(str, str2))) {
+	     xmlFree(str2);
+	     return(1);
+	 }
+	 if (str2 != NULL)
+	     xmlFree(str2);
+    }
+    return(0);
+}
+
+/**
+ * xmlXPathEqualNodeSetFloat
+ * @arg:  the nodeset object argument
+ * @f:  the float to compare to
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ * If one object to be compared is a node-set and the other is a number,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * number to be compared and on the result of converting the string-value
+ * of that node to a number using the number function is true.
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualNodeSetFloat(xmlXPathObjectPtr arg, double f) {
+    char buf[100] = "";
+
+    if ((arg == NULL) ||
+	((arg->type != XPATH_NODESET) && (arg->type != XPATH_XSLT_TREE)))
+        return(0);
+
+    if (isnan(f))
+	sprintf(buf, "NaN");
+    else if (isinf(f) > 0)
+	sprintf(buf, "+Infinity");
+    else if (isinf(f) < 0)
+	sprintf(buf, "-Infinity");
+    else
+	sprintf(buf, "%0g", f);
+
+    return(xmlXPathEqualNodeSetString(arg, BAD_CAST buf));
+}
+
+
+/**
+ * xmlXPathEqualNodeSets
+ * @arg1:  first nodeset object argument
+ * @arg2:  second nodeset object argument
+ *
+ * Implement the equal operation on XPath nodesets: @arg1 == @arg2
+ * If both objects to be compared are node-sets, then the comparison
+ * will be true if and only if there is a node in the first node-set and
+ * a node in the second node-set such that the result of performing the
+ * comparison on the string-values of the two nodes is true.
+ *
+ * (needless to say, this is a costly operation)
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualNodeSets(xmlXPathObjectPtr arg1, xmlXPathObjectPtr arg2) {
+    int i, j;
+    xmlChar **values1;
+    xmlChar **values2;
+    int ret = 0;
+    xmlNodeSetPtr ns1;
+    xmlNodeSetPtr ns2;
+
+    if ((arg1 == NULL) ||
+	((arg1->type != XPATH_NODESET) && (arg1->type != XPATH_XSLT_TREE)))
+        return(0);
+    if ((arg2 == NULL) ||
+	((arg2->type != XPATH_NODESET) && (arg2->type != XPATH_XSLT_TREE)))
+        return(0);
+
+    ns1 = arg1->nodesetval;
+    ns2 = arg2->nodesetval;
+
+    if (ns1->nodeNr <= 0)
+	return(0);
+    if (ns2->nodeNr <= 0)
+	return(0);
+
+    /*
+     * check if there is a node pertaining to both sets
+     */
+    for (i = 0;i < ns1->nodeNr;i++)
+	for (j = 0;j < ns2->nodeNr;j++)
+	    if (ns1->nodeTab[i] == ns2->nodeTab[j])
+		return(1);
+
+    values1 = (xmlChar **) xmlMalloc(ns1->nodeNr * sizeof(xmlChar *));
+    if (values1 == NULL)
+	return(0);
+    memset(values1, 0, ns1->nodeNr * sizeof(xmlChar *));
+    values2 = (xmlChar **) xmlMalloc(ns2->nodeNr * sizeof(xmlChar *));
+    if (values2 == NULL) {
+	xmlFree(values1);
+	return(0);
+    }
+    memset(values2, 0, ns2->nodeNr * sizeof(xmlChar *));
+    for (i = 0;i < ns1->nodeNr;i++) {
+	values1[i] = xmlNodeGetContent(ns1->nodeTab[i]);
+	for (j = 0;j < ns2->nodeNr;j++) {
+	    if (i == 0)
+		values2[j] = xmlNodeGetContent(ns2->nodeTab[j]);
+	    ret = xmlStrEqual(values1[i], values2[j]);
+	    if (ret)
+		break;
+	}
+	if (ret)
+	    break;
+    }
+    for (i = 0;i < ns1->nodeNr;i++)
+	if (values1[i] != NULL)
+	    xmlFree(values1[i]);
+    for (j = 0;j < ns2->nodeNr;j++)
+	if (values2[j] != NULL)
+	    xmlFree(values2[j]);
+    xmlFree(values1);
+    xmlFree(values2);
+    return(ret);
+}
+
+/**
+ * xmlXPathEqualValues:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the equal operation on XPath objects content: @arg1 == @arg2
+ *
+ * Returns 0 or 1 depending on the results of the test.
+ */
+int
+xmlXPathEqualValues(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg1, arg2;
+    int ret = 0;
+
+    arg1 = valuePop(ctxt);
+    if (arg1 == NULL)
+	XP_ERROR0(XPATH_INVALID_OPERAND);
+
+    arg2 = valuePop(ctxt);
+    if (arg2 == NULL) {
+	xmlXPathFreeObject(arg1);
+	XP_ERROR0(XPATH_INVALID_OPERAND);
+    }
+  
+    if (arg1 == arg2) {
+#ifdef DEBUG_EXPR
+        xmlGenericError(xmlGenericErrorContext,
+		"Equal: by pointer\n");
+#endif
+        return(1);
+    }
+
+    switch (arg1->type) {
+        case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+	    xmlGenericError(xmlGenericErrorContext,
+		    "Equal: undefined\n");
+#endif
+	    break;
+        case XPATH_XSLT_TREE:
+        case XPATH_NODESET:
+	    switch (arg2->type) {
+	        case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Equal: undefined\n");
+#endif
+		    break;
+		case XPATH_XSLT_TREE:
+		case XPATH_NODESET:
+		    ret = xmlXPathEqualNodeSets(arg1, arg2);
+		    break;
+		case XPATH_BOOLEAN:
+		    if ((arg1->nodesetval == NULL) ||
+			(arg1->nodesetval->nodeNr == 0)) ret = 0;
+		    else 
+			ret = 1;
+		    ret = (ret == arg2->boolval);
+		    break;
+		case XPATH_NUMBER:
+		    ret = xmlXPathEqualNodeSetFloat(arg1, arg2->floatval);
+		    break;
+		case XPATH_STRING:
+		    ret = xmlXPathEqualNodeSetString(arg1, arg2->stringval);
+		    break;
+		case XPATH_USERS:
+		case XPATH_POINT:
+		case XPATH_RANGE:
+		case XPATH_LOCATIONSET:
+		    TODO
+		    break;
+	    }
+	    break;
+        case XPATH_BOOLEAN:
+	    switch (arg2->type) {
+	        case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Equal: undefined\n");
+#endif
+		    break;
+		case XPATH_NODESET:
+		case XPATH_XSLT_TREE:
+		    if ((arg2->nodesetval == NULL) ||
+			(arg2->nodesetval->nodeNr == 0)) ret = 0;
+		    else 
+			ret = 1;
+		    break;
+		case XPATH_BOOLEAN:
+#ifdef DEBUG_EXPR
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Equal: %d boolean %d \n",
+			    arg1->boolval, arg2->boolval);
+#endif
+		    ret = (arg1->boolval == arg2->boolval);
+		    break;
+		case XPATH_NUMBER:
+		    if (arg2->floatval) ret = 1;
+		    else ret = 0;
+		    ret = (arg1->boolval == ret);
+		    break;
+		case XPATH_STRING:
+		    if ((arg2->stringval == NULL) ||
+			(arg2->stringval[0] == 0)) ret = 0;
+		    else 
+			ret = 1;
+		    ret = (arg1->boolval == ret);
+		    break;
+		case XPATH_USERS:
+		case XPATH_POINT:
+		case XPATH_RANGE:
+		case XPATH_LOCATIONSET:
+		    TODO
+		    break;
+	    }
+	    break;
+        case XPATH_NUMBER:
+	    switch (arg2->type) {
+	        case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Equal: undefined\n");
+#endif
+		    break;
+		case XPATH_NODESET:
+		case XPATH_XSLT_TREE:
+		    ret = xmlXPathEqualNodeSetFloat(arg2, arg1->floatval);
+		    break;
+		case XPATH_BOOLEAN:
+		    if (arg1->floatval) ret = 1;
+		    else ret = 0;
+		    ret = (arg2->boolval == ret);
+		    break;
+		case XPATH_STRING:
+		    valuePush(ctxt, arg2);
+		    xmlXPathNumberFunction(ctxt, 1);
+		    arg2 = valuePop(ctxt);
+		    /* no break on purpose */
+		case XPATH_NUMBER:
+		    ret = (arg1->floatval == arg2->floatval);
+		    break;
+		case XPATH_USERS:
+		case XPATH_POINT:
+		case XPATH_RANGE:
+		case XPATH_LOCATIONSET:
+		    TODO
+		    break;
+	    }
+	    break;
+        case XPATH_STRING:
+	    switch (arg2->type) {
+	        case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+		    xmlGenericError(xmlGenericErrorContext,
+			    "Equal: undefined\n");
+#endif
+		    break;
+		case XPATH_NODESET:
+		case XPATH_XSLT_TREE:
+		    ret = xmlXPathEqualNodeSetString(arg2, arg1->stringval);
+		    break;
+		case XPATH_BOOLEAN:
+		    if ((arg1->stringval == NULL) ||
+			(arg1->stringval[0] == 0)) ret = 0;
+		    else 
+			ret = 1;
+		    ret = (arg2->boolval == ret);
+		    break;
+		case XPATH_STRING:
+		    ret = xmlStrEqual(arg1->stringval, arg2->stringval);
+		    break;
+		case XPATH_NUMBER:
+		    valuePush(ctxt, arg1);
+		    xmlXPathNumberFunction(ctxt, 1);
+		    arg1 = valuePop(ctxt);
+		    ret = (arg1->floatval == arg2->floatval);
+		    break;
+		case XPATH_USERS:
+		case XPATH_POINT:
+		case XPATH_RANGE:
+		case XPATH_LOCATIONSET:
+		    TODO
+		    break;
+	    }
+	    break;
+        case XPATH_USERS:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	case XPATH_LOCATIONSET:
+	    TODO
+	    break;
+    }
+    xmlXPathFreeObject(arg1);
+    xmlXPathFreeObject(arg2);
+    return(ret);
+}
+
+
+/**
+ * xmlXPathCompareValues:
+ * @ctxt:  the XPath Parser context
+ * @inf:  less than (1) or greater than (0)
+ * @strict:  is the comparison strict
+ *
+ * Implement the compare operation on XPath objects: 
+ *     @arg1 < @arg2    (1, 1, ...
+ *     @arg1 <= @arg2   (1, 0, ...
+ *     @arg1 > @arg2    (0, 1, ...
+ *     @arg1 >= @arg2   (0, 0, ...
+ *
+ * When neither object to be compared is a node-set and the operator is
+ * <=, <, >=, >, then the objects are compared by converted both objects
+ * to numbers and comparing the numbers according to IEEE 754. The <
+ * comparison will be true if and only if the first number is less than the
+ * second number. The <= comparison will be true if and only if the first
+ * number is less than or equal to the second number. The > comparison
+ * will be true if and only if the first number is greater than the second
+ * number. The >= comparison will be true if and only if the first number
+ * is greater than or equal to the second number.
+ *
+ * Returns 1 if the comparaison succeeded, 0 if it failed
+ */
+int
+xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict) {
+    int ret = 0;
+    xmlXPathObjectPtr arg1, arg2;
+
+    arg2 = valuePop(ctxt);
+    if (arg2 == NULL) {
+	XP_ERROR0(XPATH_INVALID_OPERAND);
+    }
+  
+    arg1 = valuePop(ctxt);
+    if (arg1 == NULL) {
+	xmlXPathFreeObject(arg2);
+	XP_ERROR0(XPATH_INVALID_OPERAND);
+    }
+
+    if ((arg2->type == XPATH_NODESET) || (arg1->type == XPATH_NODESET)) {
+	if ((arg2->type == XPATH_NODESET) && (arg1->type == XPATH_NODESET)) {
+	    ret = xmlXPathCompareNodeSets(ctxt, inf, strict, arg1, arg2);
+	} else {
+	    if (arg1->type == XPATH_NODESET) {
+		ret = xmlXPathCompareNodeSetValue(ctxt, inf, strict, arg1, arg2);
+	    } else {
+		ret = xmlXPathCompareNodeSetValue(ctxt, !inf, !strict, arg2, arg2);
+	    }
+	}
+	return(ret);
+    }
+
+    if (arg1->type != XPATH_NUMBER) {
+	valuePush(ctxt, arg1);
+	xmlXPathNumberFunction(ctxt, 1);
+	arg1 = valuePop(ctxt);
+    }
+    if (arg1->type != XPATH_NUMBER) {
+	xmlXPathFreeObject(arg1);
+	xmlXPathFreeObject(arg2);
+	XP_ERROR0(XPATH_INVALID_OPERAND);
+    }
+    if (arg2->type != XPATH_NUMBER) {
+	valuePush(ctxt, arg2);
+	xmlXPathNumberFunction(ctxt, 1);
+	arg2 = valuePop(ctxt);
+    }
+    if (arg2->type != XPATH_NUMBER) {
+	xmlXPathFreeObject(arg1);
+	xmlXPathFreeObject(arg2);
+	XP_ERROR0(XPATH_INVALID_OPERAND);
+    }
+    /*
+     * Add tests for infinity and nan
+     * => feedback on 3.4 for Inf and NaN
+     */
+    if (inf && strict) 
+        ret = (arg1->floatval < arg2->floatval);
+    else if (inf && !strict)
+        ret = (arg1->floatval <= arg2->floatval);
+    else if (!inf && strict)
+        ret = (arg1->floatval > arg2->floatval);
+    else if (!inf && !strict)
+        ret = (arg1->floatval >= arg2->floatval);
+    xmlXPathFreeObject(arg1);
+    xmlXPathFreeObject(arg2);
+    return(ret);
+}
+
+/**
+ * xmlXPathValueFlipSign:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the unary - operation on an XPath object
+ * The numeric operators convert their operands to numbers as if
+ * by calling the number function.
+ */
+void
+xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg;
+    
+    POP_FLOAT
+    arg->floatval = -arg->floatval;
+    valuePush(ctxt, arg);
+}
+
+/**
+ * xmlXPathAddValues:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the add operation on XPath objects:
+ * The numeric operators convert their operands to numbers as if
+ * by calling the number function.
+ */
+void
+xmlXPathAddValues(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg;
+    double val;
+
+    POP_FLOAT
+    val = arg->floatval;
+    xmlXPathFreeObject(arg);
+
+    POP_FLOAT
+    arg->floatval += val;
+    valuePush(ctxt, arg);
+}
+
+/**
+ * xmlXPathSubValues:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the substraction operation on XPath objects:
+ * The numeric operators convert their operands to numbers as if
+ * by calling the number function.
+ */
+void
+xmlXPathSubValues(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg;
+    double val;
+
+    POP_FLOAT
+    val = arg->floatval;
+    xmlXPathFreeObject(arg);
+
+    POP_FLOAT
+    arg->floatval -= val;
+    valuePush(ctxt, arg);
+}
+
+/**
+ * xmlXPathMultValues:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the multiply operation on XPath objects:
+ * The numeric operators convert their operands to numbers as if
+ * by calling the number function.
+ */
+void
+xmlXPathMultValues(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg;
+    double val;
+
+    POP_FLOAT
+    val = arg->floatval;
+    xmlXPathFreeObject(arg);
+
+    POP_FLOAT
+    arg->floatval *= val;
+    valuePush(ctxt, arg);
+}
+
+/**
+ * xmlXPathDivValues:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the div operation on XPath objects @arg1 / @arg2:
+ * The numeric operators convert their operands to numbers as if
+ * by calling the number function.
+ */
+void
+xmlXPathDivValues(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg;
+    double val;
+
+    POP_FLOAT
+    val = arg->floatval;
+    xmlXPathFreeObject(arg);
+
+    POP_FLOAT
+    arg->floatval /= val;
+    valuePush(ctxt, arg);
+}
+
+/**
+ * xmlXPathModValues:
+ * @ctxt:  the XPath Parser context
+ *
+ * Implement the mod operation on XPath objects: @arg1 / @arg2
+ * The numeric operators convert their operands to numbers as if
+ * by calling the number function.
+ */
+void
+xmlXPathModValues(xmlXPathParserContextPtr ctxt) {
+    xmlXPathObjectPtr arg;
+    int arg1, arg2;
+
+    POP_FLOAT
+    arg2 = (int) arg->floatval;
+    xmlXPathFreeObject(arg);
+
+    POP_FLOAT
+    arg1 = (int) arg->floatval;
+    arg->floatval = arg1 % arg2;
+    valuePush(ctxt, arg);
+}
+
+/************************************************************************
+ *									*
+ *		The traversal functions					*
+ *									*
+ ************************************************************************/
+
+typedef enum {
+    AXIS_ANCESTOR = 1,
+    AXIS_ANCESTOR_OR_SELF,
+    AXIS_ATTRIBUTE,
+    AXIS_CHILD,
+    AXIS_DESCENDANT,
+    AXIS_DESCENDANT_OR_SELF,
+    AXIS_FOLLOWING,
+    AXIS_FOLLOWING_SIBLING,
+    AXIS_NAMESPACE,
+    AXIS_PARENT,
+    AXIS_PRECEDING,
+    AXIS_PRECEDING_SIBLING,
+    AXIS_SELF
+} xmlXPathAxisVal;
+
+/*
+ * A traversal function enumerates nodes along an axis.
+ * Initially it must be called with NULL, and it indicates
+ * termination on the axis by returning NULL.
+ */
+typedef xmlNodePtr (*xmlXPathTraversalFunction)
+                    (xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+
+/**
+ * xmlXPathNextSelf:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "self" direction
+ * The self axis contains just the context node itself
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur == NULL)
+        return(ctxt->context->node);
+    return(NULL);
+}
+
+/**
+ * xmlXPathNextChild:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "child" direction
+ * The child axis contains the children of the context node in document order.
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextChild(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur == NULL) {
+	if (ctxt->context->node == NULL) return(NULL);
+	switch (ctxt->context->node->type) {
+            case XML_ELEMENT_NODE:
+            case XML_TEXT_NODE:
+            case XML_CDATA_SECTION_NODE:
+            case XML_ENTITY_REF_NODE:
+            case XML_ENTITY_NODE:
+            case XML_PI_NODE:
+            case XML_COMMENT_NODE:
+            case XML_NOTATION_NODE:
+            case XML_DTD_NODE:
+		return(ctxt->context->node->children);
+            case XML_DOCUMENT_NODE:
+            case XML_DOCUMENT_TYPE_NODE:
+            case XML_DOCUMENT_FRAG_NODE:
+            case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_SGML_ENABLED
+	    case XML_SGML_DOCUMENT_NODE:
+#endif
+		return(((xmlDocPtr) ctxt->context->node)->children);
+	    case XML_ELEMENT_DECL:
+	    case XML_ATTRIBUTE_DECL:
+	    case XML_ENTITY_DECL:
+            case XML_ATTRIBUTE_NODE:
+	    case XML_NAMESPACE_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
+		return(NULL);
+	}
+	return(NULL);
+    }
+    if ((cur->type == XML_DOCUMENT_NODE) ||
+        (cur->type == XML_HTML_DOCUMENT_NODE))
+	return(NULL);
+    return(cur->next);
+}
+
+/**
+ * xmlXPathNextDescendant:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "descendant" direction
+ * the descendant axis contains the descendants of the context node in document
+ * order; a descendant is a child or a child of a child and so on.
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextDescendant(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur == NULL) {
+	if (ctxt->context->node == NULL)
+	    return(NULL);
+	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
+	    return(NULL);
+
+        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
+	    return(ctxt->context->doc->children);
+        return(ctxt->context->node->children);
+    }
+
+    if (cur->children != NULL)
+    	{
+    	if (cur->children->type != XML_ENTITY_DECL)
+		   	return(cur->children);
+    	}
+    if (cur->next != NULL) return(cur->next);
+    
+    do {
+        cur = cur->parent;
+	if (cur == NULL) return(NULL);
+	if (cur == ctxt->context->node) return(NULL);
+	if (cur->next != NULL) {
+	    cur = cur->next;
+	    return(cur);
+	}
+    } while (cur != NULL);
+    return(cur);
+}
+
+/**
+ * xmlXPathNextDescendantOrSelf:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "descendant-or-self" direction
+ * the descendant-or-self axis contains the context node and the descendants
+ * of the context node in document order; thus the context node is the first
+ * node on the axis, and the first child of the context node is the second node
+ * on the axis
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextDescendantOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur == NULL) {
+	if (ctxt->context->node == NULL)
+	    return(NULL);
+	if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	    (ctxt->context->node->type == XML_NAMESPACE_DECL))
+	    return(NULL);
+        return(ctxt->context->node);
+    }
+
+    return(xmlXPathNextDescendant(ctxt, cur));
+}
+
+/**
+ * xmlXPathNextParent:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "parent" direction
+ * The parent axis contains the parent of the context node, if there is one.
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextParent(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    /*
+     * the parent of an attribute or namespace node is the element
+     * to which the attribute or namespace node is attached
+     * Namespace handling !!!
+     */
+    if (cur == NULL) {
+	if (ctxt->context->node == NULL) return(NULL);
+	switch (ctxt->context->node->type) {
+            case XML_ELEMENT_NODE:
+            case XML_TEXT_NODE:
+            case XML_CDATA_SECTION_NODE:
+            case XML_ENTITY_REF_NODE:
+            case XML_ENTITY_NODE:
+            case XML_PI_NODE:
+            case XML_COMMENT_NODE:
+            case XML_NOTATION_NODE:
+            case XML_DTD_NODE:
+	    case XML_ELEMENT_DECL:
+	    case XML_ATTRIBUTE_DECL:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
+	    case XML_ENTITY_DECL:
+		if (ctxt->context->node->parent == NULL)
+		    return((xmlNodePtr) ctxt->context->doc);
+		return(ctxt->context->node->parent);
+            case XML_ATTRIBUTE_NODE: {
+		xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
+
+		return(att->parent);
+	    }
+            case XML_DOCUMENT_NODE:
+            case XML_DOCUMENT_TYPE_NODE:
+            case XML_DOCUMENT_FRAG_NODE:
+            case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_SGML_ENABLED
+	    case XML_SGML_DOCUMENT_NODE:
+#endif
+                return(NULL);
+	    case XML_NAMESPACE_DECL:
+		/*
+		 * TODO !!! may require extending struct _xmlNs with
+		 * parent field
+		 * C.f. Infoset case...
+		 */
+                return(NULL);
+	}
+    }
+    return(NULL);
+}
+
+/**
+ * xmlXPathNextAncestor:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "ancestor" direction
+ * the ancestor axis contains the ancestors of the context node; the ancestors
+ * of the context node consist of the parent of context node and the parent's
+ * parent and so on; the nodes are ordered in reverse document order; thus the
+ * parent is the first node on the axis, and the parent's parent is the second
+ * node on the axis
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    /*
+     * the parent of an attribute or namespace node is the element
+     * to which the attribute or namespace node is attached
+     * !!!!!!!!!!!!!
+     */
+    if (cur == NULL) {
+	if (ctxt->context->node == NULL) return(NULL);
+	switch (ctxt->context->node->type) {
+            case XML_ELEMENT_NODE:
+            case XML_TEXT_NODE:
+            case XML_CDATA_SECTION_NODE:
+            case XML_ENTITY_REF_NODE:
+            case XML_ENTITY_NODE:
+            case XML_PI_NODE:
+            case XML_COMMENT_NODE:
+	    case XML_DTD_NODE:
+	    case XML_ELEMENT_DECL:
+	    case XML_ATTRIBUTE_DECL:
+	    case XML_ENTITY_DECL:
+            case XML_NOTATION_NODE:
+	    case XML_XINCLUDE_START:
+	    case XML_XINCLUDE_END:
+		if (ctxt->context->node->parent == NULL)
+		    return((xmlNodePtr) ctxt->context->doc);
+		return(ctxt->context->node->parent);
+            case XML_ATTRIBUTE_NODE: {
+		xmlAttrPtr cur = (xmlAttrPtr) ctxt->context->node;
+
+		return(cur->parent);
+	    }
+            case XML_DOCUMENT_NODE:
+            case XML_DOCUMENT_TYPE_NODE:
+            case XML_DOCUMENT_FRAG_NODE:
+            case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_SGML_ENABLED
+	    case XML_SGML_DOCUMENT_NODE:
+#endif
+                return(NULL);
+	    case XML_NAMESPACE_DECL:
+		/*
+		 * TODO !!! may require extending struct _xmlNs with
+		 * parent field
+		 * C.f. Infoset case...
+		 */
+                return(NULL);
+	}
+	return(NULL);
+    }
+    if (cur == ctxt->context->doc->children)
+	return((xmlNodePtr) ctxt->context->doc);
+    if (cur == (xmlNodePtr) ctxt->context->doc)
+	return(NULL);
+    switch (cur->type) {
+	case XML_ELEMENT_NODE:
+	case XML_TEXT_NODE:
+	case XML_CDATA_SECTION_NODE:
+	case XML_ENTITY_REF_NODE:
+	case XML_ENTITY_NODE:
+	case XML_PI_NODE:
+	case XML_COMMENT_NODE:
+	case XML_NOTATION_NODE:
+	case XML_DTD_NODE:
+        case XML_ELEMENT_DECL:
+        case XML_ATTRIBUTE_DECL:
+        case XML_ENTITY_DECL:
+	case XML_XINCLUDE_START:
+	case XML_XINCLUDE_END:
+	    return(cur->parent);
+	case XML_ATTRIBUTE_NODE: {
+	    xmlAttrPtr att = (xmlAttrPtr) ctxt->context->node;
+
+	    return(att->parent);
+	}
+	case XML_DOCUMENT_NODE:
+	case XML_DOCUMENT_TYPE_NODE:
+	case XML_DOCUMENT_FRAG_NODE:
+	case XML_HTML_DOCUMENT_NODE:
+#ifdef LIBXML_SGML_ENABLED
+	case XML_SGML_DOCUMENT_NODE:
+#endif
+	    return(NULL);
+	case XML_NAMESPACE_DECL:
+	    /*
+	     * TODO !!! may require extending struct _xmlNs with
+	     * parent field
+	     * C.f. Infoset case...
+	     */
+	    return(NULL);
+    }
+    return(NULL);
+}
+
+/**
+ * xmlXPathNextAncestorOrSelf:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "ancestor-or-self" direction
+ * he ancestor-or-self axis contains the context node and ancestors of
+ * the context node in reverse document order; thus the context node is
+ * the first node on the axis, and the context node's parent the second;
+ * parent here is defined the same as with the parent axis.
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextAncestorOrSelf(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur == NULL)
+        return(ctxt->context->node);
+    return(xmlXPathNextAncestor(ctxt, cur));
+}
+
+/**
+ * xmlXPathNextFollowingSibling:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "following-sibling" direction
+ * The following-sibling axis contains the following siblings of the context
+ * node in document order.
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextFollowingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	(ctxt->context->node->type == XML_NAMESPACE_DECL))
+	return(NULL);
+    if (cur == (xmlNodePtr) ctxt->context->doc)
+        return(NULL);
+    if (cur == NULL)
+        return(ctxt->context->node->next);
+    return(cur->next);
+}
+
+/**
+ * xmlXPathNextPrecedingSibling:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "preceding-sibling" direction
+ * The preceding-sibling axis contains the preceding siblings of the context
+ * node in reverse document order; the first preceding sibling is first on the
+ * axis; the sibling preceding that node is the second on the axis and so on.
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if ((ctxt->context->node->type == XML_ATTRIBUTE_NODE) ||
+	(ctxt->context->node->type == XML_NAMESPACE_DECL))
+	return(NULL);
+    if (cur == (xmlNodePtr) ctxt->context->doc)
+        return(NULL);
+    if (cur == NULL)
+        return(ctxt->context->node->prev);
+    return(cur->prev);
+}
+
+/**
+ * xmlXPathNextFollowing:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "following" direction
+ * The following axis contains all nodes in the same document as the context
+ * node that are after the context node in document order, excluding any
+ * descendants and excluding attribute nodes and namespace nodes; the nodes
+ * are ordered in document order
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextFollowing(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur != NULL && cur->children != NULL)
+        return cur->children ;
+    if (cur == NULL) cur = ctxt->context->node;
+    if (cur == NULL) return(NULL) ; /* ERROR */
+    if (cur->next != NULL) return(cur->next) ;
+    do {
+        cur = cur->parent;
+        if (cur == NULL) return(NULL);
+        if (cur == (xmlNodePtr) ctxt->context->doc) return(NULL);
+        if (cur->next != NULL) return(cur->next);
+    } while (cur != NULL);
+    return(cur);
+}
+
+/*
+ * xmlXPathIsAncestor:
+ * @ancestor:  the ancestor node
+ * @node:  the current node
+ *
+ * Check that @ancestor is a @node's ancestor
+ *
+ * returns 1 if @ancestor is a @node's ancestor, 0 otherwise.
+ */
+static int
+xmlXPathIsAncestor(xmlNodePtr ancestor, xmlNodePtr node) {
+    if ((ancestor == NULL) || (node == NULL)) return(0);
+    /* nodes need to be in the same document */
+    if (ancestor->doc != node->doc) return(0);
+    /* avoid searching if ancestor or node is the root node */
+    if (ancestor == (xmlNodePtr) node->doc) return(1);
+    if (node == (xmlNodePtr) ancestor->doc) return(0);
+    while (node->parent != NULL) {
+        if (node->parent == ancestor)
+            return(1);
+	node = node->parent;
+    }
+    return(0);
+}
+
+/**
+ * xmlXPathNextPreceding:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current node in the traversal
+ *
+ * Traversal function for the "preceding" direction
+ * the preceding axis contains all nodes in the same document as the context
+ * node that are before the context node in document order, excluding any
+ * ancestors and excluding attribute nodes and namespace nodes; the nodes are
+ * ordered in reverse document order
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (cur == NULL)
+        cur = ctxt->context->node ;
+    do {
+        if (cur->prev != NULL) {
+            for (cur = cur->prev ; cur->last != NULL ; cur = cur->last)
+                ;
+            return(cur) ;
+        }
+
+        cur = cur->parent;
+        if (cur == NULL) return(NULL);
+        if (cur == ctxt->context->doc->children) return(NULL);
+    } while (xmlXPathIsAncestor(cur, ctxt->context->node));
+    return(cur);
+}
+
+/**
+ * xmlXPathNextNamespace:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current attribute in the traversal
+ *
+ * Traversal function for the "namespace" direction
+ * the namespace axis contains the namespace nodes of the context node;
+ * the order of nodes on this axis is implementation-defined; the axis will
+ * be empty unless the context node is an element
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextNamespace(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
+    if ((cur == NULL) || (ctxt->context->namespaces == NULL)) {
+        if (ctxt->context->namespaces != NULL)
+	    xmlFree(ctxt->context->namespaces);
+	ctxt->context->namespaces = 
+	    xmlGetNsList(ctxt->context->doc, ctxt->context->node);
+	if (ctxt->context->namespaces == NULL) return(NULL);
+	ctxt->context->nsNr = 0;
+    }
+    return((xmlNodePtr)ctxt->context->namespaces[ctxt->context->nsNr++]);
+}
+
+/**
+ * xmlXPathNextAttribute:
+ * @ctxt:  the XPath Parser context
+ * @cur:  the current attribute in the traversal
+ *
+ * Traversal function for the "attribute" direction
+ * TODO: support DTD inherited default attributes
+ *
+ * Returns the next element following that axis
+ */
+xmlNodePtr
+xmlXPathNextAttribute(xmlXPathParserContextPtr ctxt, xmlNodePtr cur) {
+    if (ctxt->context->node->type != XML_ELEMENT_NODE) return(NULL);
+    if (cur == NULL) {
+        if (ctxt->context->node == (xmlNodePtr) ctxt->context->doc)
+	    return(NULL);
+        return((xmlNodePtr)ctxt->context->node->properties);
+    }
+    return((xmlNodePtr)cur->next);
+}
+
+/************************************************************************
+ *									*
+ *		NodeTest Functions					*
+ *									*
+ ************************************************************************/
+
+typedef enum {
+    NODE_TEST_NONE = 0,
+    NODE_TEST_TYPE = 1,
+    NODE_TEST_PI = 2,
+    NODE_TEST_ALL = 3,
+    NODE_TEST_NS = 4,
+    NODE_TEST_NAME = 5
+} xmlXPathTestVal;
+
+typedef enum {
+    NODE_TYPE_NODE = 0,
+    NODE_TYPE_COMMENT = XML_COMMENT_NODE,
+    NODE_TYPE_TEXT = XML_TEXT_NODE,
+    NODE_TYPE_PI = XML_PI_NODE
+} xmlXPathTypeVal;
+
+#define IS_FUNCTION			200
+
+/**
+ * xmlXPathNodeCollectAndTest:
+ * @ctxt:  the XPath Parser context
+ * @axis:  the XPath axis
+ * @test:  the XPath test
+ * @type:  the XPath type
+ * @prefix:  the namesapce prefix if any
+ * @name:  the name used in the search if any
+ *
+ * This is the function implementing a step: based on the current list
+ * of nodes, it builds up a new list, looking at all nodes under that
+ * axis and selecting them.
+ *
+ * Returns the new NodeSet resulting from the search.
+ */
+void
+xmlXPathNodeCollectAndTest(xmlXPathParserContextPtr ctxt, xmlXPathAxisVal axis,
+                           xmlXPathTestVal test, xmlXPathTypeVal type,
+			   const xmlChar *prefix, const xmlChar *name) {
+#ifdef DEBUG_STEP
+    int n = 0, t = 0;
+#endif
+    int i;
+    xmlNodeSetPtr ret;
+    xmlXPathTraversalFunction next = NULL;
+    void (*addNode)(xmlNodeSetPtr, xmlNodePtr);
+    xmlNodePtr cur = NULL;
+    xmlXPathObjectPtr obj;
+    xmlNodeSetPtr nodelist;
+
+    CHECK_TYPE(XPATH_NODESET);
+    obj = valuePop(ctxt);
+    addNode = xmlXPathNodeSetAdd;
+
+#ifdef DEBUG_STEP
+    xmlGenericError(xmlGenericErrorContext,
+	    "new step : ");
+#endif
+    switch (axis) {
+        case AXIS_ANCESTOR:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'ancestors' ");
+#endif
+	    next = xmlXPathNextAncestor; break;
+        case AXIS_ANCESTOR_OR_SELF:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'ancestors-or-self' ");
+#endif
+	    next = xmlXPathNextAncestorOrSelf; break;
+        case AXIS_ATTRIBUTE:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'attributes' ");
+#endif
+	    next = xmlXPathNextAttribute; break;
+	    break;
+        case AXIS_CHILD:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'child' ");
+#endif
+	    next = xmlXPathNextChild; break;
+        case AXIS_DESCENDANT:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'descendant' ");
+#endif
+	    next = xmlXPathNextDescendant; break;
+        case AXIS_DESCENDANT_OR_SELF:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'descendant-or-self' ");
+#endif
+	    next = xmlXPathNextDescendantOrSelf; break;
+        case AXIS_FOLLOWING:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'following' ");
+#endif
+	    next = xmlXPathNextFollowing; break;
+        case AXIS_FOLLOWING_SIBLING:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'following-siblings' ");
+#endif
+	    next = xmlXPathNextFollowingSibling; break;
+        case AXIS_NAMESPACE:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'namespace' ");
+#endif
+	    next = (xmlXPathTraversalFunction) xmlXPathNextNamespace; break;
+	    break;
+        case AXIS_PARENT:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'parent' ");
+#endif
+	    next = xmlXPathNextParent; break;
+        case AXIS_PRECEDING:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'preceding' ");
+#endif
+	    next = xmlXPathNextPreceding; break;
+        case AXIS_PRECEDING_SIBLING:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'preceding-sibling' ");
+#endif
+	    next = xmlXPathNextPrecedingSibling; break;
+        case AXIS_SELF:
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "axis 'self' ");
+#endif
+	    next = xmlXPathNextSelf; break;
+    }
+    if (next == NULL)
+	return;
+
+    nodelist = obj->nodesetval;
+    if ((nodelist != NULL) &&
+	(nodelist->nodeNr <= 1))
+	addNode = xmlXPathNodeSetAddUnique;
+    else
+	addNode = xmlXPathNodeSetAdd;
+    ret = xmlXPathNodeSetCreate(NULL);
+#ifdef DEBUG_STEP
+    xmlGenericError(xmlGenericErrorContext,
+	    " context contains %d nodes\n",
+            nodelist->nodeNr);
+    switch (test) {
+	case NODE_TEST_NODE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching all nodes\n");
+	    break;
+	case NODE_TEST_NONE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching for none !!!\n");
+	    break;
+	case NODE_TEST_TYPE:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching for type %d\n", type);
+	    break;
+	case NODE_TEST_PI:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching for PI !!!\n");
+	    break;
+	case NODE_TEST_ALL:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching for *\n");
+	    break;
+	case NODE_TEST_NS:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching for namespace %s\n",
+	            prefix);
+	    break;
+	case NODE_TEST_NAME:
+	    xmlGenericError(xmlGenericErrorContext,
+		    "           searching for name %s\n", name);
+	    if (prefix != NULL)
+		xmlGenericError(xmlGenericErrorContext,
+			"           with namespace %s\n",
+		        prefix);
+	    break;
+    }
+    xmlGenericError(xmlGenericErrorContext, "Testing : ");
+#endif
+    /*
+     * 2.3 Node Tests
+     *  - For the attribute axis, the principal node type is attribute. 
+     *  - For the namespace axis, the principal node type is namespace. 
+     *  - For other axes, the principal node type is element. 
+     *
+     * A node test * is true for any node of the
+     * principal node type. For example, child::* willi
+     * select all element children of the context node
+     */
+    for (i = 0;i < nodelist->nodeNr; i++) {
+        ctxt->context->node = nodelist->nodeTab[i];
+
+	cur = NULL;
+	do {
+	    cur = next(ctxt, cur);
+	    if (cur == NULL) break;
+#ifdef DEBUG_STEP
+            t++;
+            xmlGenericError(xmlGenericErrorContext, " %s", cur->name);
+#endif
+	    switch (test) {
+                case NODE_TEST_NONE:
+		    STRANGE
+		    return;
+                case NODE_TEST_TYPE:
+		    if ((cur->type == type) ||
+		        ((type == NODE_TYPE_NODE) && 
+			 ((cur->type == XML_DOCUMENT_NODE) ||
+			  (cur->type == XML_HTML_DOCUMENT_NODE) ||
+			  (cur->type == XML_ELEMENT_NODE) ||
+			  (cur->type == XML_PI_NODE) ||
+			  (cur->type == XML_COMMENT_NODE) ||
+			  (cur->type == XML_CDATA_SECTION_NODE) ||
+			  (cur->type == XML_TEXT_NODE)))) {
+#ifdef DEBUG_STEP
+                        n++;
+#endif
+		        addNode(ret, cur);
+		    }
+		    break;
+                case NODE_TEST_PI:
+		    if (cur->type == XML_PI_NODE) {
+		        if ((name != NULL) &&
+			    (!xmlStrEqual(name, cur->name)))
+			    break;
+#ifdef DEBUG_STEP
+			n++;
+#endif
+			addNode(ret, cur);
+		    }
+		    break;
+                case NODE_TEST_ALL:
+		    if (axis == AXIS_ATTRIBUTE) {
+			if (cur->type == XML_ATTRIBUTE_NODE) {
+#ifdef DEBUG_STEP
+			    n++;
+#endif
+			    addNode(ret, cur);
+			}
+		    } else if (axis == AXIS_NAMESPACE) {
+			if (cur->type == XML_NAMESPACE_DECL) {
+#ifdef DEBUG_STEP
+			    n++;
+#endif
+			    addNode(ret, cur);
+			}
+		    } else {
+			if ((cur->type == XML_ELEMENT_NODE) ||
+			    (cur->type == XML_DOCUMENT_NODE) ||
+			    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+			    if (prefix == NULL) {
+#ifdef DEBUG_STEP
+				n++;
+#endif
+				addNode(ret, cur);
+			    } else if ((cur->ns != NULL) && 
+				(xmlStrEqual(prefix,
+					     cur->ns->href))) {
+#ifdef DEBUG_STEP
+				n++;
+#endif
+				addNode(ret, cur);
+			    }
+			}
+		    }
+		    break;
+                case NODE_TEST_NS: {
+		    TODO;
+		    break;
+		}
+                case NODE_TEST_NAME:
+		    switch (cur->type) {
+		        case XML_ELEMENT_NODE:
+			    if (xmlStrEqual(name, cur->name)) {
+				if (prefix == NULL) {
+				    if ((cur->ns == NULL) ||
+					(cur->ns->prefix == NULL)) {
+#ifdef DEBUG_STEP
+					n++;
+#endif
+					addNode(ret, cur);
+				    }
+				} else {
+				    if ((cur->ns != NULL) && 
+				        (xmlStrEqual(prefix,
+						     cur->ns->href))) {
+#ifdef DEBUG_STEP
+					n++;
+#endif
+					addNode(ret, cur);
+				    }
+				}
+			    }
+			    break;
+		        case XML_ATTRIBUTE_NODE: {
+			    xmlAttrPtr attr = (xmlAttrPtr) cur;
+			    if (xmlStrEqual(name, attr->name)) {
+				if (prefix == NULL) {
+				    if ((attr->ns == NULL) ||
+					(attr->ns->prefix == NULL)) {
+#ifdef DEBUG_STEP
+					n++;
+#endif
+					addNode(ret, (xmlNodePtr) attr);
+				    }
+				} else {
+				    if ((attr->ns != NULL) && 
+				        (xmlStrEqual(prefix,
+						     attr->ns->href))) {
+#ifdef DEBUG_STEP
+					n++;
+#endif
+					addNode(ret, (xmlNodePtr) attr);
+				    }
+				}
+			    }
+			    break;
+			}
+			case XML_NAMESPACE_DECL: {
+			    TODO;
+			    break;
+			}
+			default:
+			    break;
+		    }
+	            break;
+	    }
+	} while (cur != NULL);
+    }
+#ifdef DEBUG_STEP
+    xmlGenericError(xmlGenericErrorContext,
+            "\nExamined %d nodes, found %d nodes at that step\n", t, n);
+#endif
+    xmlXPathFreeObject(obj);
+    valuePush(ctxt, xmlXPathWrapNodeSet(ret));
+}
+
+
+/************************************************************************
+ *									*
+ *		Implicit tree core function library			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPathRoot:
+ * @ctxt:  the XPath Parser context
+ *
+ * Initialize the context to the root of the document
+ */
+void
+xmlXPathRoot(xmlXPathParserContextPtr ctxt) {
+    ctxt->context->node = (xmlNodePtr) ctxt->context->doc;
+    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+}
+
+/************************************************************************
+ *									*
+ *		The explicit core function library			*
+ *http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html#corelib	*
+ *									*
+ ************************************************************************/
+
+
+/**
+ * xmlXPathLastFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the last() XPath function
+ *    number last()
+ * The last function returns the number of nodes in the context node list.
+ */
+void
+xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(0);
+    if (ctxt->context->contextSize >= 0) {
+	valuePush(ctxt, xmlXPathNewFloat((double) ctxt->context->contextSize));
+#ifdef DEBUG_EXPR
+	xmlGenericError(xmlGenericErrorContext,
+		"last() : %d\n", ctxt->context->contextSize);
+#endif
+    } else {
+	XP_ERROR(XPATH_INVALID_CTXT_SIZE);
+    }
+}
+
+/**
+ * xmlXPathPositionFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the position() XPath function
+ *    number position()
+ * The position function returns the position of the context node in the
+ * context node list. The first position is 1, and so the last positionr
+ * will be equal to last().
+ */
+void
+xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(0);
+    if (ctxt->context->proximityPosition >= 0) {
+	valuePush(ctxt,
+	      xmlXPathNewFloat((double) ctxt->context->proximityPosition));
+#ifdef DEBUG_EXPR
+	xmlGenericError(xmlGenericErrorContext, "position() : %d\n",
+		ctxt->context->proximityPosition);
+#endif
+    } else {
+	XP_ERROR(XPATH_INVALID_CTXT_POSITION);
+    }
+}
+
+/**
+ * xmlXPathCountFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the count() XPath function
+ *    number count(node-set)
+ */
+void
+xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) || 
+	((ctxt->value->type != XPATH_NODESET) &&
+	 (ctxt->value->type != XPATH_XSLT_TREE)))
+	XP_ERROR(XPATH_INVALID_TYPE);
+    cur = valuePop(ctxt);
+
+    valuePush(ctxt, xmlXPathNewFloat((double) cur->nodesetval->nodeNr));
+    xmlXPathFreeObject(cur);
+}
+
+/**
+ * xmlXPathIdFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the id() XPath function
+ *    node-set id(object)
+ * The id function selects elements by their unique ID
+ * (see [5.2.1 Unique IDs]). When the argument to id is of type node-set,
+ * then the result is the union of the result of applying id to the
+ * string value of each of the nodes in the argument node-set. When the
+ * argument to id is of any other type, the argument is converted to a
+ * string as if by a call to the string function; the string is split
+ * into a whitespace-separated list of tokens (whitespace is any sequence
+ * of characters matching the production S); the result is a node-set
+ * containing the elements in the same document as the context node that
+ * have a unique ID equal to any of the tokens in the list.
+ */
+void
+xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    const xmlChar *tokens;
+    const xmlChar *cur;
+    xmlChar *ID;
+    xmlAttrPtr attr;
+    xmlNodePtr elem = NULL;
+    xmlXPathObjectPtr ret, obj;
+
+    CHECK_ARITY(1);
+    obj = valuePop(ctxt);
+    if (obj == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
+    if (obj->type == XPATH_NODESET) {
+	xmlXPathObjectPtr newobj;
+	int i;
+
+	ret = xmlXPathNewNodeSet(NULL);
+
+	for (i = 0; i < obj->nodesetval->nodeNr; i++) {
+	    valuePush(ctxt,
+		      xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
+	    xmlXPathStringFunction(ctxt, 1);
+	    xmlXPathIdFunction(ctxt, 1);
+	    newobj = valuePop(ctxt);
+	    ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
+						   newobj->nodesetval);
+	    xmlXPathFreeObject(newobj);
+	}
+
+	xmlXPathFreeObject(obj);
+	valuePush(ctxt, ret);
+	return;
+    }
+    if (obj->type != XPATH_STRING) {
+        valuePush(ctxt, obj);
+	xmlXPathStringFunction(ctxt, 1);
+	obj = valuePop(ctxt);
+	if (obj->type != XPATH_STRING) {
+	    xmlXPathFreeObject(obj);
+	    return;
+	}
+    }
+    tokens = obj->stringval;
+
+    ret = xmlXPathNewNodeSet(NULL);
+    valuePush(ctxt, ret);
+    if (tokens == NULL) {
+	xmlXPathFreeObject(obj);
+        return;
+    }
+
+    cur = tokens;
+    
+    while (IS_BLANK(*cur)) cur++;
+    while (*cur != 0) {
+	while ((IS_LETTER(*cur)) || (IS_DIGIT(*cur)) ||
+	       (*cur == '.') || (*cur == '-') ||
+	       (*cur == '_') || (*cur == ':') || 
+	       (IS_COMBINING(*cur)) ||
+	       (IS_EXTENDER(*cur)))
+	       cur++;
+
+	if ((!IS_BLANK(*cur)) && (*cur != 0)) break;
+
+        ID = xmlStrndup(tokens, cur - tokens);
+	attr = xmlGetID(ctxt->context->doc, ID);
+	if (attr != NULL) {
+	    elem = attr->parent;
+            xmlXPathNodeSetAdd(ret->nodesetval, elem);
+        }
+	if (ID != NULL)
+	    xmlFree(ID);
+
+	while (IS_BLANK(*cur)) cur++;
+	tokens = cur;
+    }
+    xmlXPathFreeObject(obj);
+    return;
+}
+
+/**
+ * xmlXPathLocalNameFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the local-name() XPath function
+ *    string local-name(node-set?)
+ * The local-name function returns a string containing the local part
+ * of the name of the node in the argument node-set that is first in
+ * document order. If the node-set is empty or the first node has no
+ * name, an empty string is returned. If the argument is omitted it
+ * defaults to the context node.
+ */
+void
+xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+
+    if (nargs == 0) {
+	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+	nargs = 1;
+    }
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) || 
+	((ctxt->value->type != XPATH_NODESET) &&
+	 (ctxt->value->type != XPATH_XSLT_TREE)))
+	XP_ERROR(XPATH_INVALID_TYPE);
+    cur = valuePop(ctxt);
+
+    if (cur->nodesetval->nodeNr == 0) {
+	valuePush(ctxt, xmlXPathNewCString(""));
+    } else {
+	int i = 0; /* Should be first in document order !!!!! */
+	switch (cur->nodesetval->nodeTab[i]->type) {
+	case XML_ELEMENT_NODE:
+	case XML_ATTRIBUTE_NODE:
+	case XML_PI_NODE:
+	    valuePush(ctxt,
+		      xmlXPathNewString(cur->nodesetval->nodeTab[i]->name));
+	    break;
+	case XML_NAMESPACE_DECL:
+	    valuePush(ctxt, xmlXPathNewString(
+			((xmlNsPtr)cur->nodesetval->nodeTab[i])->prefix));
+	    break;
+	default:
+	    valuePush(ctxt, xmlXPathNewCString(""));
+	}
+    }
+    xmlXPathFreeObject(cur);
+}
+
+/**
+ * xmlXPathNamespaceURIFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the namespace-uri() XPath function
+ *    string namespace-uri(node-set?)
+ * The namespace-uri function returns a string containing the
+ * namespace URI of the expanded name of the node in the argument
+ * node-set that is first in document order. If the node-set is empty,
+ * the first node has no name, or the expanded name has no namespace
+ * URI, an empty string is returned. If the argument is omitted it
+ * defaults to the context node.
+ */
+void
+xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+
+    if (nargs == 0) {
+        valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+	nargs = 1;
+    }
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) || 
+	((ctxt->value->type != XPATH_NODESET) &&
+	 (ctxt->value->type != XPATH_XSLT_TREE)))
+	XP_ERROR(XPATH_INVALID_TYPE);
+    cur = valuePop(ctxt);
+
+    if (cur->nodesetval->nodeNr == 0) {
+	valuePush(ctxt, xmlXPathNewCString(""));
+    } else {
+	int i = 0; /* Should be first in document order !!!!! */
+	switch (cur->nodesetval->nodeTab[i]->type) {
+	case XML_ELEMENT_NODE:
+	case XML_ATTRIBUTE_NODE:
+	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
+		valuePush(ctxt, xmlXPathNewCString(""));
+	    else
+		valuePush(ctxt, xmlXPathNewString(
+			  cur->nodesetval->nodeTab[i]->ns->href));
+	    break;
+	default:
+	    valuePush(ctxt, xmlXPathNewCString(""));
+	}
+    }
+    xmlXPathFreeObject(cur);
+}
+
+/**
+ * xmlXPathNameFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the name() XPath function
+ *    string name(node-set?)
+ * The name function returns a string containing a QName representing
+ * the name of the node in the argument node-set that is first in documenti
+ * order. The QName must represent the name with respect to the namespace
+ * declarations in effect on the node whose name is being represented.
+ * Typically, this will be the form in which the name occurred in the XML
+ * source. This need not be the case if there are namespace declarations
+ * in effect on the node that associate multiple prefixes with the same
+ * namespace. However, an implementation may include information about
+ * the original prefix in its representation of nodes; in this case, an
+ * implementation can ensure that the returned string is always the same
+ * as the QName used in the XML source. If the argument it omitted it
+ * defaults to the context node.
+ * Libxml keep the original prefix so the "real qualified name" used is
+ * returned.
+ */
+void
+xmlXPathNameFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+
+    if (nargs == 0) {
+	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+	nargs = 1;
+    }
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) || 
+	((ctxt->value->type != XPATH_NODESET) &&
+	 (ctxt->value->type != XPATH_XSLT_TREE)))
+	XP_ERROR(XPATH_INVALID_TYPE);
+    cur = valuePop(ctxt);
+
+    if (cur->nodesetval->nodeNr == 0) {
+	valuePush(ctxt, xmlXPathNewCString(""));
+    } else {
+	int i = 0; /* Should be first in document order !!!!! */
+
+	switch (cur->nodesetval->nodeTab[i]->type) {
+	case XML_ELEMENT_NODE:
+	case XML_ATTRIBUTE_NODE:
+	    if (cur->nodesetval->nodeTab[i]->ns == NULL)
+		valuePush(ctxt, xmlXPathNewString(
+			    cur->nodesetval->nodeTab[i]->name));
+	    
+	    else {
+		char name[2000];
+#ifdef HAVE_SNPRINTF
+		snprintf(name, sizeof(name), "%s:%s", 
+			 (char *) cur->nodesetval->nodeTab[i]->ns->prefix,
+			 (char *) cur->nodesetval->nodeTab[i]->name);
+#else
+		sprintf(name, "%s:%s", 
+			(char *) cur->nodesetval->nodeTab[i]->ns->prefix,
+			(char *) cur->nodesetval->nodeTab[i]->name);
+#endif
+		name[sizeof(name) - 1] = 0;
+		valuePush(ctxt, xmlXPathNewCString(name));
+	    }
+	    break;
+	default:
+	    valuePush(ctxt,
+		      xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
+	    xmlXPathLocalNameFunction(ctxt, 1);
+	}
+    }
+    xmlXPathFreeObject(cur);
+}
+
+/**
+ * xmlXPathStringFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the string() XPath function
+ *    string string(object?)
+ * he string function converts an object to a string as follows:
+ *    - A node-set is converted to a string by returning the value of
+ *      the node in the node-set that is first in document order.
+ *      If the node-set is empty, an empty string is returned.
+ *    - A number is converted to a string as follows
+ *      + NaN is converted to the string NaN 
+ *      + positive zero is converted to the string 0 
+ *      + negative zero is converted to the string 0 
+ *      + positive infinity is converted to the string Infinity 
+ *      + negative infinity is converted to the string -Infinity 
+ *      + if the number is an integer, the number is represented in
+ *        decimal form as a Number with no decimal point and no leading
+ *        zeros, preceded by a minus sign (-) if the number is negative
+ *      + otherwise, the number is represented in decimal form as a
+ *        Number including a decimal point with at least one digit
+ *        before the decimal point and at least one digit after the
+ *        decimal point, preceded by a minus sign (-) if the number
+ *        is negative; there must be no leading zeros before the decimal
+ *        point apart possibly from the one required digit immediatelyi
+ *        before the decimal point; beyond the one required digit
+ *        after the decimal point there must be as many, but only as
+ *        many, more digits as are needed to uniquely distinguish the
+ *        number from all other IEEE 754 numeric values.
+ *    - The boolean false value is converted to the string false.
+ *      The boolean true value is converted to the string true.
+ *
+ * If the argument is omitted, it defaults to a node-set with the
+ * context node as its only member.
+ */
+void
+xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+
+    if (nargs == 0) {
+	valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+	nargs = 1;
+    }
+
+    CHECK_ARITY(1);
+    cur = valuePop(ctxt);
+    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
+    switch (cur->type) {
+	case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+	    xmlGenericError(xmlGenericErrorContext, "String: undefined\n");
+#endif
+	    valuePush(ctxt, xmlXPathNewCString(""));
+	    break;
+        case XPATH_XSLT_TREE:
+        case XPATH_NODESET:
+	    if (cur->nodesetval == NULL)
+		valuePush(ctxt, xmlXPathNewCString(""));
+	    else if (cur->nodesetval->nodeNr == 0) {
+		valuePush(ctxt, xmlXPathNewCString(""));
+	    } else {
+		xmlChar *res;
+	        int i = 0; /* Should be first in document order !!!!! */
+		res = xmlNodeGetContent(cur->nodesetval->nodeTab[i]);
+		valuePush(ctxt, xmlXPathNewString(res));
+		if (res != NULL)
+		    xmlFree(res);
+	    }
+	    xmlXPathFreeObject(cur);
+	    return;
+	case XPATH_STRING:
+	    valuePush(ctxt, cur);
+	    return;
+        case XPATH_BOOLEAN:
+	    if (cur->boolval) valuePush(ctxt, xmlXPathNewCString("true"));
+	    else valuePush(ctxt, xmlXPathNewCString("false"));
+	    xmlXPathFreeObject(cur);
+	    return;
+	case XPATH_NUMBER: {
+	    char buf[100];
+
+	    if (isnan(cur->floatval))
+	        sprintf(buf, "NaN");
+	    else if (isinf(cur->floatval) > 0)
+	        sprintf(buf, "+Infinity");
+	    else if (isinf(cur->floatval) < 0)
+	        sprintf(buf, "-Infinity");
+	    else
+		sprintf(buf, "%0g", cur->floatval);
+	    valuePush(ctxt, xmlXPathNewCString(buf));
+	    xmlXPathFreeObject(cur);
+	    return;
+	}
+	case XPATH_USERS:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	case XPATH_LOCATIONSET:
+	    TODO
+	    valuePush(ctxt, xmlXPathNewCString(""));
+	    break;
+    }
+    STRANGE
+}
+
+/**
+ * xmlXPathStringLengthFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the string-length() XPath function
+ *    number string-length(string?)
+ * The string-length returns the number of characters in the string
+ * (see [3.6 Strings]). If the argument is omitted, it defaults to
+ * the context node converted to a string, in other words the value
+ * of the context node.
+ */
+void
+xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+
+    if (nargs == 0) {
+	if (ctxt->context->node == NULL) {
+	    valuePush(ctxt, xmlXPathNewFloat(0));
+	} else {
+	    xmlChar *content;
+
+	    content = xmlNodeGetContent(ctxt->context->node);
+	    valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(content)));
+	    xmlFree(content);
+	}
+	return;
+    }
+    CHECK_ARITY(1);
+    CAST_TO_STRING;
+    CHECK_TYPE(XPATH_STRING);
+    cur = valuePop(ctxt);
+    valuePush(ctxt, xmlXPathNewFloat(xmlStrlen(cur->stringval)));
+    xmlXPathFreeObject(cur);
+}
+
+/**
+ * xmlXPathConcatFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the concat() XPath function
+ *    string concat(string, string, string*)
+ * The concat function returns the concatenation of its arguments.
+ */
+void
+xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur, newobj;
+    xmlChar *tmp;
+
+    if (nargs < 2) {
+	CHECK_ARITY(2);
+    }
+
+    CAST_TO_STRING;
+    cur = valuePop(ctxt);
+    if ((cur == NULL) || (cur->type != XPATH_STRING)) {
+        xmlXPathFreeObject(cur);
+	return;
+    }
+    nargs--;
+
+    while (nargs > 0) {
+	CAST_TO_STRING;
+	newobj = valuePop(ctxt);
+	if ((newobj == NULL) || (newobj->type != XPATH_STRING)) {
+	    xmlXPathFreeObject(newobj);
+	    xmlXPathFreeObject(cur);
+	    XP_ERROR(XPATH_INVALID_TYPE);
+	}
+	tmp = xmlStrcat(newobj->stringval, cur->stringval);
+	newobj->stringval = cur->stringval;
+	cur->stringval = tmp;
+
+	xmlXPathFreeObject(newobj);
+	nargs--;
+    }
+    valuePush(ctxt, cur);
+}
+
+/**
+ * xmlXPathContainsFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the contains() XPath function
+ *    boolean contains(string, string)
+ * The contains function returns true if the first argument string
+ * contains the second argument string, and otherwise returns false.
+ */
+void
+xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr hay, needle;
+
+    CHECK_ARITY(2);
+    CAST_TO_STRING;
+    CHECK_TYPE(XPATH_STRING);
+    needle = valuePop(ctxt);
+    CAST_TO_STRING;
+    hay = valuePop(ctxt);
+    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
+        xmlXPathFreeObject(hay);
+        xmlXPathFreeObject(needle);
+	XP_ERROR(XPATH_INVALID_TYPE);
+    }
+    if (xmlStrstr(hay->stringval, needle->stringval))
+        valuePush(ctxt, xmlXPathNewBoolean(1));
+    else
+        valuePush(ctxt, xmlXPathNewBoolean(0));
+    xmlXPathFreeObject(hay);
+    xmlXPathFreeObject(needle);
+}
+
+/**
+ * xmlXPathStartsWithFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the starts-with() XPath function
+ *    boolean starts-with(string, string)
+ * The starts-with function returns true if the first argument string
+ * starts with the second argument string, and otherwise returns false.
+ */
+void
+xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr hay, needle;
+    int n;
+
+    CHECK_ARITY(2);
+    CAST_TO_STRING;
+    CHECK_TYPE(XPATH_STRING);
+    needle = valuePop(ctxt);
+    CAST_TO_STRING;
+    hay = valuePop(ctxt);
+    if ((hay == NULL) || (hay->type != XPATH_STRING)) {
+        xmlXPathFreeObject(hay);
+        xmlXPathFreeObject(needle);
+	XP_ERROR(XPATH_INVALID_TYPE);
+    }
+    n = xmlStrlen(needle->stringval);
+    if (xmlStrncmp(hay->stringval, needle->stringval, n))
+        valuePush(ctxt, xmlXPathNewBoolean(0));
+    else
+        valuePush(ctxt, xmlXPathNewBoolean(1));
+    xmlXPathFreeObject(hay);
+    xmlXPathFreeObject(needle);
+}
+
+/**
+ * xmlXPathSubstringFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the substring() XPath function
+ *    string substring(string, number, number?)
+ * The substring function returns the substring of the first argument
+ * starting at the position specified in the second argument with
+ * length specified in the third argument. For example,
+ * substring("12345",2,3) returns "234". If the third argument is not
+ * specified, it returns the substring starting at the position specified
+ * in the second argument and continuing to the end of the string. For
+ * example, substring("12345",2) returns "2345".  More precisely, each
+ * character in the string (see [3.6 Strings]) is considered to have a
+ * numeric position: the position of the first character is 1, the position
+ * of the second character is 2 and so on. The returned substring contains
+ * those characters for which the position of the character is greater than
+ * or equal to the second argument and, if the third argument is specified,
+ * less than the sum of the second and third arguments; the comparisons
+ * and addition used for the above follow the standard IEEE 754 rules. Thus:
+ *  - substring("12345", 1.5, 2.6) returns "234" 
+ *  - substring("12345", 0, 3) returns "12" 
+ *  - substring("12345", 0 div 0, 3) returns "" 
+ *  - substring("12345", 1, 0 div 0) returns "" 
+ *  - substring("12345", -42, 1 div 0) returns "12345" 
+ *  - substring("12345", -1 div 0, 1 div 0) returns "" 
+ */
+void
+xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr str, start, len;
+    double le, in;
+    int i, l;
+    xmlChar *ret;
+
+    /* 
+     * Conformance needs to be checked !!!!!
+     */
+    if (nargs < 2) {
+	CHECK_ARITY(2);
+    }
+    if (nargs > 3) {
+	CHECK_ARITY(3);
+    }
+    if (nargs == 3) {
+	CAST_TO_NUMBER;
+	CHECK_TYPE(XPATH_NUMBER);
+	len = valuePop(ctxt);
+	le = len->floatval;
+        xmlXPathFreeObject(len);
+    } else {
+	le = 2000000000;
+    }
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+    start = valuePop(ctxt);
+    in = start->floatval;
+    xmlXPathFreeObject(start);
+    CAST_TO_STRING;
+    CHECK_TYPE(XPATH_STRING);
+    str = valuePop(ctxt);
+    le += in;
+
+    /* integer index of the first char */
+    i = (int) in;
+    if (((double)i) != in) i++;
+    
+    /* integer index of the last char */
+    l = (int) le;
+    if (((double)l) != le) l++;
+
+    /* back to a zero based len */
+    i--;
+    l--;
+
+    /* check against the string len */
+    if (l > 1024) {
+        l = xmlStrlen(str->stringval);
+    }
+    if (i < 0) {
+        i = 0;
+    }
+
+    /* number of chars to copy */
+    l -= i;
+
+    ret = xmlStrsub(str->stringval, i, l);
+    if (ret == NULL)
+	valuePush(ctxt, xmlXPathNewCString(""));
+    else {
+	valuePush(ctxt, xmlXPathNewString(ret));
+	xmlFree(ret);
+    }
+    xmlXPathFreeObject(str);
+}
+
+/**
+ * xmlXPathSubstringBeforeFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the substring-before() XPath function
+ *    string substring-before(string, string)
+ * The substring-before function returns the substring of the first
+ * argument string that precedes the first occurrence of the second
+ * argument string in the first argument string, or the empty string
+ * if the first argument string does not contain the second argument
+ * string. For example, substring-before("1999/04/01","/") returns 1999.
+ */
+void
+xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+  xmlXPathObjectPtr str;
+  xmlXPathObjectPtr find;
+  xmlBufferPtr target;
+  const xmlChar *point;
+  int offset;
+  
+  CHECK_ARITY(2);
+  CAST_TO_STRING;
+  find = valuePop(ctxt);
+  CAST_TO_STRING;
+  str = valuePop(ctxt);
+  
+  target = xmlBufferCreate();
+  if (target) {
+    point = xmlStrstr(str->stringval, find->stringval);
+    if (point) {
+      offset = (int)(point - str->stringval);
+      xmlBufferAdd(target, str->stringval, offset);
+    }
+    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
+    xmlBufferFree(target);
+  }
+  
+  xmlXPathFreeObject(str);
+  xmlXPathFreeObject(find);
+}
+
+/**
+ * xmlXPathSubstringAfterFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the substring-after() XPath function
+ *    string substring-after(string, string)
+ * The substring-after function returns the substring of the first
+ * argument string that follows the first occurrence of the second
+ * argument string in the first argument string, or the empty stringi
+ * if the first argument string does not contain the second argument
+ * string. For example, substring-after("1999/04/01","/") returns 04/01,
+ * and substring-after("1999/04/01","19") returns 99/04/01.
+ */
+void
+xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+  xmlXPathObjectPtr str;
+  xmlXPathObjectPtr find;
+  xmlBufferPtr target;
+  const xmlChar *point;
+  int offset;
+  
+  CHECK_ARITY(2);
+  CAST_TO_STRING;
+  find = valuePop(ctxt);
+  CAST_TO_STRING;
+  str = valuePop(ctxt);
+  
+  target = xmlBufferCreate();
+  if (target) {
+    point = xmlStrstr(str->stringval, find->stringval);
+    if (point) {
+      offset = (int)(point - str->stringval) + xmlStrlen(find->stringval);
+      xmlBufferAdd(target, &str->stringval[offset],
+		   xmlStrlen(str->stringval) - offset);
+    }
+    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
+    xmlBufferFree(target);
+  }
+  
+  xmlXPathFreeObject(str);
+  xmlXPathFreeObject(find);
+}
+
+/**
+ * xmlXPathNormalizeFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the normalize-space() XPath function
+ *    string normalize-space(string?)
+ * The normalize-space function returns the argument string with white
+ * space normalized by stripping leading and trailing whitespace
+ * and replacing sequences of whitespace characters by a single
+ * space. Whitespace characters are the same allowed by the S production
+ * in XML. If the argument is omitted, it defaults to the context
+ * node converted to a string, in other words the value of the context node.
+ */
+void
+xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+  xmlXPathObjectPtr obj = NULL;
+  xmlChar *source = NULL;
+  xmlBufferPtr target;
+  xmlChar blank;
+  
+  if (nargs == 0) {
+    /* Use current context node */
+    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+    xmlXPathStringFunction(ctxt, 1);
+    nargs = 1;
+  }
+
+  CHECK_ARITY(1);
+  CAST_TO_STRING;
+  CHECK_TYPE(XPATH_STRING);
+  obj = valuePop(ctxt);
+  source = obj->stringval;
+
+  target = xmlBufferCreate();
+  if (target && source) {
+    
+    /* Skip leading whitespaces */
+    while (IS_BLANK(*source))
+      source++;
+  
+    /* Collapse intermediate whitespaces, and skip trailing whitespaces */
+    blank = 0;
+    while (*source) {
+      if (IS_BLANK(*source)) {
+	blank = *source;
+      } else {
+	if (blank) {
+	  xmlBufferAdd(target, &blank, 1);
+	  blank = 0;
+	}
+	xmlBufferAdd(target, source, 1);
+      }
+      source++;
+    }
+  
+    valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
+    xmlBufferFree(target);
+  }
+  xmlXPathFreeObject(obj);
+}
+
+/**
+ * xmlXPathTranslateFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the translate() XPath function
+ *    string translate(string, string, string)
+ * The translate function returns the first argument string with
+ * occurrences of characters in the second argument string replaced
+ * by the character at the corresponding position in the third argument
+ * string. For example, translate("bar","abc","ABC") returns the string
+ * BAr. If there is a character in the second argument string with no
+ * character at a corresponding position in the third argument string
+ * (because the second argument string is longer than the third argument
+ * string), then occurrences of that character in the first argument
+ * string are removed. For example, translate("--aaa--","abc-","ABC")
+ * returns "AAA". If a character occurs more than once in second
+ * argument string, then the first occurrence determines the replacement
+ * character. If the third argument string is longer than the second
+ * argument string, then excess characters are ignored.
+ */
+void
+xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+  xmlXPathObjectPtr str;
+  xmlXPathObjectPtr from;
+  xmlXPathObjectPtr to;
+  xmlBufferPtr target;
+  int i, offset, max;
+  xmlChar ch;
+  const xmlChar *point;
+
+  CHECK_ARITY(3);
+
+  CAST_TO_STRING;
+  to = valuePop(ctxt);
+  CAST_TO_STRING;
+  from = valuePop(ctxt);
+  CAST_TO_STRING;
+  str = valuePop(ctxt);
+
+  target = xmlBufferCreate();
+  if (target) {
+    max = xmlStrlen(to->stringval);
+    for (i = 0; (ch = str->stringval[i]); i++) {
+      point = xmlStrchr(from->stringval, ch);
+      if (point) {
+	/* Warning: This may not work with UTF-8 */
+	offset = (int)(point - from->stringval);
+	if (offset < max)
+	  xmlBufferAdd(target, &to->stringval[offset], 1);
+      } else
+	xmlBufferAdd(target, &ch, 1);
+    }
+  }
+  valuePush(ctxt, xmlXPathNewString(xmlBufferContent(target)));
+  xmlBufferFree(target);
+  xmlXPathFreeObject(str);
+  xmlXPathFreeObject(from);
+  xmlXPathFreeObject(to);
+}
+
+/**
+ * xmlXPathBooleanFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the boolean() XPath function
+ *    boolean boolean(object)
+ * he boolean function converts its argument to a boolean as follows:
+ *    - a number is true if and only if it is neither positive or
+ *      negative zero nor NaN
+ *    - a node-set is true if and only if it is non-empty
+ *    - a string is true if and only if its length is non-zero
+ */
+void
+xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+    int res = 0;
+
+    CHECK_ARITY(1);
+    cur = valuePop(ctxt);
+    if (cur == NULL) XP_ERROR(XPATH_INVALID_OPERAND);
+    switch (cur->type) {
+        case XPATH_NODESET:
+        case XPATH_XSLT_TREE:
+	    if ((cur->nodesetval == NULL) ||
+	        (cur->nodesetval->nodeNr == 0)) res = 0;
+	    else 
+	        res = 1;
+	    break;
+	case XPATH_STRING:
+	    if ((cur->stringval == NULL) ||
+	        (cur->stringval[0] == 0)) res = 0;
+	    else 
+	        res = 1;
+	    break;
+        case XPATH_BOOLEAN:
+	    valuePush(ctxt, cur);
+	    return;
+	case XPATH_NUMBER:
+	    if (cur->floatval) res = 1;
+	    break;
+	default:
+	    STRANGE
+    }
+    xmlXPathFreeObject(cur);
+    valuePush(ctxt, xmlXPathNewBoolean(res));
+}
+
+/**
+ * xmlXPathNotFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the not() XPath function
+ *    boolean not(boolean)
+ * The not function returns true if its argument is false,
+ * and false otherwise.
+ */
+void
+xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(1);
+    CAST_TO_BOOLEAN;
+    CHECK_TYPE(XPATH_BOOLEAN);
+    ctxt->value->boolval = ! ctxt->value->boolval;
+}
+
+/**
+ * xmlXPathTrueFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the true() XPath function
+ *    boolean true()
+ */
+void
+xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(0);
+    valuePush(ctxt, xmlXPathNewBoolean(1));
+}
+
+/**
+ * xmlXPathFalseFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the false() XPath function
+ *    boolean false()
+ */
+void
+xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(0);
+    valuePush(ctxt, xmlXPathNewBoolean(0));
+}
+
+/**
+ * xmlXPathLangFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the lang() XPath function
+ *    boolean lang(string)
+ * The lang function returns true or false depending on whether the
+ * language of the context node as specified by xml:lang attributes
+ * is the same as or is a sublanguage of the language specified by
+ * the argument string. The language of the context node is determined
+ * by the value of the xml:lang attribute on the context node, or, if
+ * the context node has no xml:lang attribute, by the value of the
+ * xml:lang attribute on the nearest ancestor of the context node that
+ * has an xml:lang attribute. If there is no such attribute, then lang
+ * returns false. If there is such an attribute, then lang returns
+ * true if the attribute value is equal to the argument ignoring case,
+ * or if there is some suffix starting with - such that the attribute
+ * value is equal to the argument ignoring that suffix of the attribute
+ * value and ignoring case.
+ */
+void
+xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr val;
+    const xmlChar *theLang;
+    const xmlChar *lang;
+    int ret = 0;
+    int i;
+
+    CHECK_ARITY(1);
+    CAST_TO_STRING;
+    CHECK_TYPE(XPATH_STRING);
+    val = valuePop(ctxt);
+    lang = val->stringval;
+    theLang = xmlNodeGetLang(ctxt->context->node);
+    if ((theLang != NULL) && (lang != NULL)) {
+        for (i = 0;lang[i] != 0;i++)
+	    if (toupper(lang[i]) != toupper(theLang[i]))
+	        goto not_equal;
+        ret = 1;
+    }
+not_equal:
+    xmlXPathFreeObject(val);
+    valuePush(ctxt, xmlXPathNewBoolean(ret));
+}
+
+/**
+ * xmlXPathNumberFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the number() XPath function
+ *    number number(object?)
+ */
+void
+xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+    double res;
+
+    if (nargs == 0) {
+	if (ctxt->context->node == NULL) {
+	    valuePush(ctxt, xmlXPathNewFloat(0.0));
+	} else {
+	    xmlChar* content = xmlNodeGetContent(ctxt->context->node);
+
+	    res = xmlXPathStringEvalNumber(content);
+	    valuePush(ctxt, xmlXPathNewFloat(res));
+	    xmlFree(content);
+	}
+	return;
+    }
+
+    CHECK_ARITY(1);
+    cur = valuePop(ctxt);
+    switch (cur->type) {
+	case XPATH_UNDEFINED:
+#ifdef DEBUG_EXPR
+	    xmlGenericError(xmlGenericErrorContext, "NUMBER: undefined\n");
+#endif
+	    valuePush(ctxt, xmlXPathNewFloat(0.0));
+	    break;
+        case XPATH_XSLT_TREE:
+        case XPATH_NODESET:
+	    valuePush(ctxt, cur);
+	    xmlXPathStringFunction(ctxt, 1);
+	    cur = valuePop(ctxt);
+	case XPATH_STRING:
+	    res = xmlXPathStringEvalNumber(cur->stringval);
+	    valuePush(ctxt, xmlXPathNewFloat(res));
+	    xmlXPathFreeObject(cur);
+	    return;
+        case XPATH_BOOLEAN:
+	    if (cur->boolval) valuePush(ctxt, xmlXPathNewFloat(1.0));
+	    else valuePush(ctxt, xmlXPathNewFloat(0.0));
+	    xmlXPathFreeObject(cur);
+	    return;
+	case XPATH_NUMBER:
+	    valuePush(ctxt, cur);
+	    return;
+	case XPATH_USERS:
+	case XPATH_POINT:
+	case XPATH_RANGE:
+	case XPATH_LOCATIONSET:
+	    TODO
+	    valuePush(ctxt, xmlXPathNewFloat(0.0));
+	    break;
+    }
+    STRANGE
+}
+
+/**
+ * xmlXPathSumFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the sum() XPath function
+ *    number sum(node-set)
+ * The sum function returns the sum of the values of the nodes in
+ * the argument node-set.
+ */
+void
+xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr cur;
+    int i;
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) || 
+	((ctxt->value->type != XPATH_NODESET) &&
+	 (ctxt->value->type != XPATH_XSLT_TREE)))
+	XP_ERROR(XPATH_INVALID_TYPE);
+    cur = valuePop(ctxt);
+
+    if (cur->nodesetval->nodeNr == 0) {
+	valuePush(ctxt, xmlXPathNewFloat(0.0));
+    } else {
+	valuePush(ctxt,
+		  xmlXPathNewNodeSet(cur->nodesetval->nodeTab[0]));
+	xmlXPathNumberFunction(ctxt, 1);
+	for (i = 1; i < cur->nodesetval->nodeNr; i++) {
+	    valuePush(ctxt,
+		      xmlXPathNewNodeSet(cur->nodesetval->nodeTab[i]));
+	    xmlXPathAddValues(ctxt);
+	}
+    }
+    xmlXPathFreeObject(cur);
+}
+
+/**
+ * xmlXPathFloorFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the floor() XPath function
+ *    number floor(number)
+ * The floor function returns the largest (closest to positive infinity)
+ * number that is not greater than the argument and that is an integer.
+ */
+void
+xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    CHECK_ARITY(1);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+#if 0
+    ctxt->value->floatval = floor(ctxt->value->floatval);
+#else
+    /* floor(0.999999999999) => 1.0 !!!!!!!!!!! */
+    ctxt->value->floatval = (double)((int) ctxt->value->floatval);
+#endif
+}
+
+/**
+ * xmlXPathCeilingFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the ceiling() XPath function
+ *    number ceiling(number)
+ * The ceiling function returns the smallest (closest to negative infinity)
+ * number that is not less than the argument and that is an integer.
+ */
+void
+xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    double f;
+
+    CHECK_ARITY(1);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+
+#if 0
+    ctxt->value->floatval = ceil(ctxt->value->floatval);
+#else
+    f = (double)((int) ctxt->value->floatval);
+    if (f != ctxt->value->floatval)
+	ctxt->value->floatval = f + 1;
+#endif
+}
+
+/**
+ * xmlXPathRoundFunction:
+ * @ctxt:  the XPath Parser context
+ * @nargs:  the number of arguments
+ *
+ * Implement the round() XPath function
+ *    number round(number)
+ * The round function returns the number that is closest to the
+ * argument and that is an integer. If there are two such numbers,
+ * then the one that is even is returned.
+ */
+void
+xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    double f;
+
+    CHECK_ARITY(1);
+    CAST_TO_NUMBER;
+    CHECK_TYPE(XPATH_NUMBER);
+
+    if ((ctxt->value->floatval == xmlXPathNAN) ||
+	(ctxt->value->floatval == xmlXPathPINF) ||
+	(ctxt->value->floatval == xmlXPathNINF) ||
+	(ctxt->value->floatval == 0.0))
+	return;
+
+#if 0
+    f = floor(ctxt->value->floatval);
+#else
+    f = (double)((int) ctxt->value->floatval);
+#endif
+    if (ctxt->value->floatval < f + 0.5)
+        ctxt->value->floatval = f;
+    else 
+        ctxt->value->floatval = f + 1;
+}
+
+/************************************************************************
+ *									*
+ *			The Parser					*
+ *									*
+ ************************************************************************/
+
+/*
+ * a couple of forward declarations since we use a recursive call based
+ * implementation.
+ */
+void xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt);
+void xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt);
+void xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt);
+#ifdef VMS
+void xmlXPathEvalRelLocationPath(xmlXPathParserContextPtr ctxt);
+#define xmlXPathEvalRelativeLocationPath xmlXPathEvalRelLocationPath 
+#else 
+void xmlXPathEvalRelativeLocationPath(xmlXPathParserContextPtr ctxt);
+#endif
+
+/**
+ * xmlXPathParseNCName:
+ * @ctxt:  the XPath Parser context
+ *
+ * parse an XML namespace non qualified name.
+ *
+ * [NS 3] NCName ::= (Letter | '_') (NCNameChar)*
+ *
+ * [NS 4] NCNameChar ::= Letter | Digit | '.' | '-' | '_' |
+ *                       CombiningChar | Extender
+ *
+ * Returns the namespace name or NULL
+ */
+
+xmlChar *
+xmlXPathParseNCName(xmlXPathParserContextPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+
+    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
+    q = NEXT;
+
+    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+           (CUR == '.') || (CUR == '-') ||
+	   (CUR == '_') ||
+	   (IS_COMBINING(CUR)) ||
+	   (IS_EXTENDER(CUR)))
+	NEXT;
+    
+    ret = xmlStrndup(q, CUR_PTR - q);
+
+    return(ret);
+}
+
+/**
+ * xmlXPathParseQName:
+ * @ctxt:  the XPath Parser context
+ * @prefix:  a xmlChar ** 
+ *
+ * parse an XML qualified name
+ *
+ * [NS 5] QName ::= (Prefix ':')? LocalPart
+ *
+ * [NS 6] Prefix ::= NCName
+ *
+ * [NS 7] LocalPart ::= NCName
+ *
+ * Returns the function returns the local part, and prefix is updated
+ *   to get the Prefix if any.
+ */
+
+xmlChar *
+xmlXPathParseQName(xmlXPathParserContextPtr ctxt, xmlChar **prefix) {
+    xmlChar *ret = NULL;
+
+    *prefix = NULL;
+    ret = xmlXPathParseNCName(ctxt);
+    if (CUR == ':') {
+        *prefix = ret;
+	NEXT;
+	ret = xmlXPathParseNCName(ctxt);
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathParseName:
+ * @ctxt:  the XPath Parser context
+ *
+ * parse an XML name
+ *
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ *                  CombiningChar | Extender
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * Returns the namespace name or NULL
+ */
+
+xmlChar *
+xmlXPathParseName(xmlXPathParserContextPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+
+    if (!IS_LETTER(CUR) && (CUR != '_')) return(NULL);
+    q = NEXT;
+
+    /* TODO Make this UTF8 compliant !!! */
+    while ((IS_LETTER(CUR)) || (IS_DIGIT(CUR)) ||
+           (CUR == '.') || (CUR == '-') ||
+	   (CUR == '_') || (CUR == ':') ||
+	   (IS_COMBINING(CUR)) ||
+	   (IS_EXTENDER(CUR)))
+	NEXT;
+    
+    ret = xmlStrndup(q, CUR_PTR - q);
+
+    return(ret);
+}
+
+/**
+ * xmlXPathStringEvalNumber:
+ * @str:  A string to scan
+ *
+ *  [30]   Number ::=   Digits ('.' Digits?)?
+ *                    | '.' Digits 
+ *  [31]   Digits ::=   [0-9]+
+ *
+ * Parse and evaluate a Number in the string
+ * In complement of the Number expression, this function also handles
+ * negative values : '-' Number.
+ *
+ * Returns the double value.
+ */
+double
+xmlXPathStringEvalNumber(const xmlChar *str) {
+    const xmlChar *cur = str;
+    double ret = 0.0;
+    double mult = 1;
+    int ok = 0;
+    int isneg = 0;
+
+    while (IS_BLANK(*cur)) cur++;
+    if ((*cur != '.') && ((*cur < '0') || (*cur > '9')) && (*cur != '-')) {
+        return(xmlXPathNAN);
+    }
+    if (*cur == '-') {
+	isneg = 1;
+	cur++;
+    }
+    while ((*cur >= '0') && (*cur <= '9')) {
+        ret = ret * 10 + (*cur - '0');
+	ok = 1;
+	cur++;
+    }
+    if (*cur == '.') {
+        cur++;
+	if (((*cur < '0') || (*cur > '9')) && (!ok)) {
+	    return(xmlXPathNAN);
+	}
+	while ((*cur >= '0') && (*cur <= '9')) {
+	    mult /= 10;
+	    ret = ret  + (*cur - '0') * mult;
+	    cur++;
+	}
+    }
+    while (IS_BLANK(*cur)) cur++;
+    if (*cur != 0) return(xmlXPathNAN);
+    if (isneg) ret = -ret;
+    return(ret);
+}
+
+/**
+ * xmlXPathEvalNumber:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [30]   Number ::=   Digits ('.' Digits?)?
+ *                    | '.' Digits 
+ *  [31]   Digits ::=   [0-9]+
+ *
+ * Parse and evaluate a Number, then push it on the stack
+ *
+ */
+void
+xmlXPathEvalNumber(xmlXPathParserContextPtr ctxt) {
+    double ret = 0.0;
+    double mult = 1;
+    int ok = 0;
+
+    CHECK_ERROR;
+    if ((CUR != '.') && ((CUR < '0') || (CUR > '9'))) {
+        XP_ERROR(XPATH_NUMBER_ERROR);
+    }
+    while ((CUR >= '0') && (CUR <= '9')) {
+        ret = ret * 10 + (CUR - '0');
+	ok = 1;
+	NEXT;
+    }
+    if (CUR == '.') {
+        NEXT;
+	if (((CUR < '0') || (CUR > '9')) && (!ok)) {
+	     XP_ERROR(XPATH_NUMBER_ERROR);
+	}
+	while ((CUR >= '0') && (CUR <= '9')) {
+	    mult /= 10;
+	    ret = ret  + (CUR - '0') * mult;
+	    NEXT;
+	}
+    }
+    valuePush(ctxt, xmlXPathNewFloat(ret));
+}
+
+/**
+ * xmlXPathEvalLiteral:
+ * @ctxt:  the XPath Parser context
+ *
+ * Parse a Literal and push it on the stack.
+ *
+ *  [29]   Literal ::=   '"' [^"]* '"'
+ *                    | "'" [^']* "'"
+ *
+ * TODO: xmlXPathEvalLiteral memory allocation could be improved.
+ */
+void
+xmlXPathEvalLiteral(xmlXPathParserContextPtr ctxt) {
+    const xmlChar *q;
+    xmlChar *ret = NULL;
+
+    if (CUR == '"') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_CHAR(CUR)) && (CUR != '"'))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+        }
+    } else if (CUR == '\'') {
+        NEXT;
+	q = CUR_PTR;
+	while ((IS_CHAR(CUR)) && (CUR != '\''))
+	    NEXT;
+	if (!IS_CHAR(CUR)) {
+	    XP_ERROR(XPATH_UNFINISHED_LITERAL_ERROR);
+	} else {
+	    ret = xmlStrndup(q, CUR_PTR - q);
+	    NEXT;
+        }
+    } else {
+	XP_ERROR(XPATH_START_LITERAL_ERROR);
+    }
+    if (ret == NULL) return;
+    valuePush(ctxt, xmlXPathNewString(ret));
+    xmlFree(ret);
+}
+
+/**
+ * xmlXPathEvalVariableReference:
+ * @ctxt:  the XPath Parser context
+ *
+ * Parse a VariableReference, evaluate it and push it on the stack.
+ *
+ * The variable bindings consist of a mapping from variable names
+ * to variable values. The value of a variable is an object, which
+ * of any of the types that are possible for the value of an expression,
+ * and may also be of additional types not specified here.
+ *
+ * Early evaluation is possible since:
+ * The variable bindings [...] used to evaluate a subexpression are
+ * always the same as those used to evaluate the containing expression. 
+ *
+ *  [36]   VariableReference ::=   '$' QName 
+ */
+void
+xmlXPathEvalVariableReference(xmlXPathParserContextPtr ctxt) {
+    xmlChar *name;
+    xmlChar *prefix;
+    xmlXPathObjectPtr value;
+
+    SKIP_BLANKS;
+    if (CUR != '$') {
+	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
+    }
+    NEXT;
+    name = xmlXPathParseQName(ctxt, &prefix);
+    if (name == NULL) {
+	XP_ERROR(XPATH_VARIABLE_REF_ERROR);
+    }
+    if (prefix == NULL) {
+	value = xmlXPathVariableLookup(ctxt->context, name);
+    } else {
+	TODO;
+	value = NULL;
+    }
+    xmlFree(name);
+    if (prefix != NULL) xmlFree(prefix);
+    if (value == NULL) {
+	XP_ERROR(XPATH_UNDEF_VARIABLE_ERROR);
+    }
+    valuePush(ctxt, value);
+    SKIP_BLANKS;
+}
+
+/**
+ * xmlXPathIsNodeType:
+ * @ctxt:  the XPath Parser context
+ * @name:  a name string
+ *
+ * Is the name given a NodeType one.
+ *
+ *  [38]   NodeType ::=   'comment'
+ *                    | 'text'
+ *                    | 'processing-instruction'
+ *                    | 'node'
+ *
+ * Returns 1 if true 0 otherwise
+ */
+int
+xmlXPathIsNodeType(const xmlChar *name) {
+    if (name == NULL)
+	return(0);
+
+    if (xmlStrEqual(name, BAD_CAST "comment"))
+	return(1);
+    if (xmlStrEqual(name, BAD_CAST "text"))
+	return(1);
+    if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
+	return(1);
+    if (xmlStrEqual(name, BAD_CAST "node"))
+	return(1);
+    return(0);
+}
+
+/**
+ * xmlXPathEvalFunctionCall:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [16]   FunctionCall ::=   FunctionName '(' ( Argument ( ',' Argument)*)? ')'
+ *  [17]   Argument ::=   Expr 
+ *
+ * Parse and evaluate a function call, the evaluation of all arguments are
+ * pushed on the stack
+ */
+void
+xmlXPathEvalFunctionCall(xmlXPathParserContextPtr ctxt) {
+    xmlChar *name;
+    xmlChar *prefix;
+    xmlXPathFunction func;
+    int nbargs = 0;
+
+    name = xmlXPathParseQName(ctxt, &prefix);
+    if (name == NULL) {
+	XP_ERROR(XPATH_EXPR_ERROR);
+    }
+    SKIP_BLANKS;
+    if (prefix == NULL) {
+	func = xmlXPathFunctionLookup(ctxt->context, name);
+    } else {
+	TODO;
+	func = NULL;
+    }
+    if (func == NULL) {
+        xmlFree(name);
+	if (prefix != NULL) xmlFree(prefix);
+	XP_ERROR(XPATH_UNKNOWN_FUNC_ERROR);
+    }
+#ifdef DEBUG_EXPR
+    if (prefix == NULL)
+	xmlGenericError(xmlGenericErrorContext, "Calling function %s\n",
+			name);
+    else
+	xmlGenericError(xmlGenericErrorContext, "Calling function %s:%s\n",
+			prefix, name);
+#endif
+
+    xmlFree(name);
+    if (prefix != NULL) xmlFree(prefix);
+
+    if (CUR != '(') {
+	XP_ERROR(XPATH_EXPR_ERROR);
+    }
+    NEXT;
+    SKIP_BLANKS;
+
+    while (CUR != ')') {
+        xmlXPathEvalExpr(ctxt);
+	nbargs++;
+	if (CUR == ')') break;
+	if (CUR != ',') {
+	    XP_ERROR(XPATH_EXPR_ERROR);
+	}
+	NEXT;
+	SKIP_BLANKS;
+    }
+    NEXT;
+    SKIP_BLANKS;
+    func(ctxt, nbargs);
+}
+
+/**
+ * xmlXPathEvalPrimaryExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [15]   PrimaryExpr ::=   VariableReference 
+ *                | '(' Expr ')'
+ *                | Literal 
+ *                | Number 
+ *                | FunctionCall 
+ *
+ * Parse and evaluate a primary expression, then push the result on the stack
+ */
+void
+xmlXPathEvalPrimaryExpr(xmlXPathParserContextPtr ctxt) {
+    SKIP_BLANKS;
+    if (CUR == '$') xmlXPathEvalVariableReference(ctxt);
+    else if (CUR == '(') {
+	NEXT;
+	SKIP_BLANKS;
+	xmlXPathEvalExpr(ctxt);
+	if (CUR != ')') {
+	    XP_ERROR(XPATH_EXPR_ERROR);
+	}
+	NEXT;
+	SKIP_BLANKS;
+    } else if (IS_DIGIT(CUR)) {
+	xmlXPathEvalNumber(ctxt);
+    } else if ((CUR == '\'') || (CUR == '"')) {
+	xmlXPathEvalLiteral(ctxt);
+    } else {
+	xmlXPathEvalFunctionCall(ctxt);
+    }
+    SKIP_BLANKS;
+}
+
+/**
+ * xmlXPathEvalFilterExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [20]   FilterExpr ::=   PrimaryExpr 
+ *               | FilterExpr Predicate 
+ *
+ * Parse and evaluate a filter expression, then push the result on the stack
+ * Square brackets are used to filter expressions in the same way that
+ * they are used in location paths. It is an error if the expression to
+ * be filtered does not evaluate to a node-set. The context node list
+ * used for evaluating the expression in square brackets is the node-set
+ * to be filtered listed in document order.
+ */
+
+void
+xmlXPathEvalFilterExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalPrimaryExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    
+    while (CUR == '[') {
+	if ((ctxt->value == NULL) || 
+	    ((ctxt->value->type != XPATH_NODESET) &&
+	     (ctxt->value->type != XPATH_LOCATIONSET)))
+	    XP_ERROR(XPATH_INVALID_TYPE)
+
+	if (ctxt->value->type == XPATH_NODESET)
+	    xmlXPathEvalPredicate(ctxt);
+        else
+	    xmlXPtrEvalRangePredicate(ctxt);
+	SKIP_BLANKS;
+    }
+
+    
+}
+
+/**
+ * xmlXPathScanName:
+ * @ctxt:  the XPath Parser context
+ *
+ * Trickery: parse an XML name but without consuming the input flow
+ * Needed to avoid insanity in the parser state.
+ *
+ * [4] NameChar ::= Letter | Digit | '.' | '-' | '_' | ':' |
+ *                  CombiningChar | Extender
+ *
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ *
+ * [6] Names ::= Name (S Name)*
+ *
+ * Returns the Name parsed or NULL
+ */
+
+xmlChar *
+xmlXPathScanName(xmlXPathParserContextPtr ctxt) {
+    xmlChar buf[XML_MAX_NAMELEN];
+    int len = 0;
+
+    SKIP_BLANKS;
+    if (!IS_LETTER(CUR) && (CUR != '_') &&
+        (CUR != ':')) {
+	return(NULL);
+    }
+
+    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
+           (NXT(len) == '.') || (NXT(len) == '-') ||
+	   (NXT(len) == '_') || (NXT(len) == ':') || 
+	   (IS_COMBINING(NXT(len))) ||
+	   (IS_EXTENDER(NXT(len)))) {
+	buf[len] = NXT(len);
+	len++;
+	if (len >= XML_MAX_NAMELEN) {
+	    xmlGenericError(xmlGenericErrorContext, 
+	       "xmlScanName: reached XML_MAX_NAMELEN limit\n");
+	    while ((IS_LETTER(NXT(len))) || (IS_DIGIT(NXT(len))) ||
+		   (NXT(len) == '.') || (NXT(len) == '-') ||
+		   (NXT(len) == '_') || (NXT(len) == ':') || 
+		   (IS_COMBINING(NXT(len))) ||
+		   (IS_EXTENDER(NXT(len))))
+		 len++;
+	    break;
+	}
+    }
+    return(xmlStrndup(buf, len));
+}
+
+/**
+ * xmlXPathEvalPathExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [19]   PathExpr ::=   LocationPath 
+ *               | FilterExpr 
+ *               | FilterExpr '/' RelativeLocationPath 
+ *               | FilterExpr '//' RelativeLocationPath 
+ *
+ * Parse and evaluate a path expression, then push the result on the stack
+ * The / operator and // operators combine an arbitrary expression
+ * and a relative location path. It is an error if the expression
+ * does not evaluate to a node-set.
+ * The / operator does composition in the same way as when / is
+ * used in a location path. As in location paths, // is short for
+ * /descendant-or-self::node()/.
+ */
+
+void
+xmlXPathEvalPathExpr(xmlXPathParserContextPtr ctxt) {
+    int lc = 1;           /* Should we branch to LocationPath ?         */
+    xmlChar *name = NULL; /* we may have to preparse a name to find out */
+
+    SKIP_BLANKS;
+    if ((CUR == '$') || (CUR == '(') || (IS_DIGIT(CUR)) ||
+        (CUR == '\'') || (CUR == '"')) {
+	lc = 0;
+    } else if (CUR == '*') {
+	/* relative or absolute location path */
+	lc = 1;
+    } else if (CUR == '/') {
+	/* relative or absolute location path */
+	lc = 1;
+    } else if (CUR == '@') {
+	/* relative abbreviated attribute location path */
+	lc = 1;
+    } else if (CUR == '.') {
+	/* relative abbreviated attribute location path */
+	lc = 1;
+    } else {
+	/*
+	 * Problem is finding if we have a name here whether it's:
+	 *   - a nodetype
+	 *   - a function call in which case it's followed by '('
+	 *   - an axis in which case it's followed by ':'
+	 *   - a element name
+	 * We do an a priori analysis here rather than having to
+	 * maintain parsed token content through the recursive function
+	 * calls. This looks uglier but makes the code quite easier to
+	 * read/write/debug.
+	 */
+	SKIP_BLANKS;
+	name = xmlXPathScanName(ctxt);
+	if ((name != NULL) && (xmlStrstr(name, (xmlChar *) "::") != NULL)) {
+#ifdef DEBUG_STEP
+	    xmlGenericError(xmlGenericErrorContext,
+		    "PathExpr: Axis\n");
+#endif
+	    lc = 1;
+	    xmlFree(name);
+	} else if (name != NULL) {
+	    int len =xmlStrlen(name);
+	    int blank = 0;
+
+	    
+	    while (NXT(len) != 0) {
+		if (NXT(len) == '/') {
+		    /* element name */
+#ifdef DEBUG_STEP
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PathExpr: AbbrRelLocation\n");
+#endif
+		    lc = 1;
+		    break;
+		} else if (IS_BLANK(NXT(len))) {
+		    /* skip to next */
+		    blank = 1;
+		} else if (NXT(len) == ':') {
+#ifdef DEBUG_STEP
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PathExpr: AbbrRelLocation\n");
+#endif
+		    lc = 1;
+		    break;
+		} else if ((NXT(len) == '(')) {
+		    /* Note Type or Function */
+		    if (xmlXPathIsNodeType(name)) {
+#ifdef DEBUG_STEP
+		        xmlGenericError(xmlGenericErrorContext,
+				"PathExpr: Type search\n");
+#endif
+			lc = 1;
+		    } else {
+#ifdef DEBUG_STEP
+		        xmlGenericError(xmlGenericErrorContext,
+				"PathExpr: function call\n");
+#endif
+			lc = 0;
+		    }
+                    break;
+		} else if ((NXT(len) == '[')) {
+		    /* element name */
+#ifdef DEBUG_STEP
+		    xmlGenericError(xmlGenericErrorContext,
+			    "PathExpr: AbbrRelLocation\n");
+#endif
+		    lc = 1;
+		    break;
+		} else if ((NXT(len) == '<') || (NXT(len) == '>') ||
+			   (NXT(len) == '=')) {
+		    lc = 1;
+		    break;
+		} else {
+		    lc = 1;
+		    break;
+		}
+		len++;
+	    }
+	    if (NXT(len) == 0) {
+#ifdef DEBUG_STEP
+		xmlGenericError(xmlGenericErrorContext,
+			"PathExpr: AbbrRelLocation\n");
+#endif
+		/* element name */
+		lc = 1;
+	    }
+	    xmlFree(name);
+	} else {
+	    /* make sure all cases are covered explicitely */
+	    XP_ERROR(XPATH_EXPR_ERROR);
+	}
+    } 
+
+    if (lc) {
+	if (CUR == '/')
+	    xmlXPathRoot(ctxt);
+	else {
+	    /* TAG:9999 */
+	    valuePush(ctxt, xmlXPathNewNodeSet(ctxt->context->node));
+	}
+	xmlXPathEvalLocationPath(ctxt);
+    } else {
+	xmlXPathEvalFilterExpr(ctxt);
+	CHECK_ERROR;
+	if ((CUR == '/') && (NXT(1) == '/')) {
+	    SKIP(2);
+	    SKIP_BLANKS;
+	    xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
+			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
+	    ctxt->context->node = NULL;
+	    xmlXPathEvalRelativeLocationPath(ctxt);
+	} else if (CUR == '/') {
+	    xmlXPathEvalRelativeLocationPath(ctxt);
+	}
+    }
+    SKIP_BLANKS;
+}
+
+/**
+ * xmlXPathEvalUnionExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [18]   UnionExpr ::=   PathExpr 
+ *               | UnionExpr '|' PathExpr 
+ *
+ * Parse and evaluate an union expression, then push the result on the stack
+ */
+
+void
+xmlXPathEvalUnionExpr(xmlXPathParserContextPtr ctxt) {
+    int sort = 0;
+    xmlXPathEvalPathExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while (CUR == '|') {
+	xmlXPathObjectPtr obj1,obj2, tmp;
+
+	sort = 1;
+	CHECK_TYPE(XPATH_NODESET);
+	obj1 = valuePop(ctxt);
+	tmp = xmlXPathNewNodeSet(ctxt->context->node);
+	valuePush(ctxt, tmp);
+
+	NEXT;
+	SKIP_BLANKS;
+	xmlXPathEvalPathExpr(ctxt);
+
+	CHECK_TYPE(XPATH_NODESET);
+	obj2 = valuePop(ctxt);
+	obj1->nodesetval = xmlXPathNodeSetMerge(obj1->nodesetval,
+		                                obj2->nodesetval);
+	if (ctxt->value == tmp) {
+	    tmp = valuePop(ctxt);
+	    xmlXPathFreeObject(tmp);
+	}
+	valuePush(ctxt, obj1);
+	xmlXPathFreeObject(obj2);
+	SKIP_BLANKS;
+    }
+    if (sort) {
+    }
+}
+
+/**
+ * xmlXPathEvalUnaryExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [27]   UnaryExpr ::=   UnionExpr 
+ *                   | '-' UnaryExpr 
+ *
+ * Parse and evaluate an unary expression, then push the result on the stack
+ */
+
+void
+xmlXPathEvalUnaryExpr(xmlXPathParserContextPtr ctxt) {
+    int minus = 0;
+
+    SKIP_BLANKS;
+    if (CUR == '-') {
+        minus = 1;
+	NEXT;
+	SKIP_BLANKS;
+    }
+    xmlXPathEvalUnionExpr(ctxt);
+    CHECK_ERROR;
+    if (minus) {
+        xmlXPathValueFlipSign(ctxt);
+    }
+}
+
+/**
+ * xmlXPathEvalMultiplicativeExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [26]   MultiplicativeExpr ::=   UnaryExpr 
+ *                   | MultiplicativeExpr MultiplyOperator UnaryExpr 
+ *                   | MultiplicativeExpr 'div' UnaryExpr 
+ *                   | MultiplicativeExpr 'mod' UnaryExpr 
+ *  [34]   MultiplyOperator ::=   '*'
+ *
+ * Parse and evaluate an Additive expression, then push the result on the stack
+ */
+
+void
+xmlXPathEvalMultiplicativeExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalUnaryExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while ((CUR == '*') || 
+           ((CUR == 'd') && (NXT(1) == 'i') && (NXT(2) == 'v')) ||
+           ((CUR == 'm') && (NXT(1) == 'o') && (NXT(2) == 'd'))) {
+	int op = -1;
+
+        if (CUR == '*') {
+	    op = 0;
+	    NEXT;
+	} else if (CUR == 'd') {
+	    op = 1;
+	    SKIP(3);
+	} else if (CUR == 'm') {
+	    op = 2;
+	    SKIP(3);
+	}
+	SKIP_BLANKS;
+        xmlXPathEvalUnaryExpr(ctxt);
+	CHECK_ERROR;
+	switch (op) {
+	    case 0:
+	        xmlXPathMultValues(ctxt);
+		break;
+	    case 1:
+	        xmlXPathDivValues(ctxt);
+		break;
+	    case 2:
+	        xmlXPathModValues(ctxt);
+		break;
+	}
+	SKIP_BLANKS;
+    }
+}
+
+/**
+ * xmlXPathEvalAdditiveExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [25]   AdditiveExpr ::=   MultiplicativeExpr 
+ *                   | AdditiveExpr '+' MultiplicativeExpr 
+ *                   | AdditiveExpr '-' MultiplicativeExpr 
+ *
+ * Parse and evaluate an Additive expression, then push the result on the stack
+ */
+
+void
+xmlXPathEvalAdditiveExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalMultiplicativeExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while ((CUR == '+') || (CUR == '-')) {
+	int plus;
+
+        if (CUR == '+') plus = 1;
+	else plus = 0;
+	NEXT;
+	SKIP_BLANKS;
+        xmlXPathEvalMultiplicativeExpr(ctxt);
+	CHECK_ERROR;
+	if (plus) xmlXPathAddValues(ctxt);
+	else xmlXPathSubValues(ctxt);
+	SKIP_BLANKS;
+    }
+}
+
+/**
+ * xmlXPathEvalRelationalExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [24]   RelationalExpr ::=   AdditiveExpr 
+ *                 | RelationalExpr '<' AdditiveExpr 
+ *                 | RelationalExpr '>' AdditiveExpr 
+ *                 | RelationalExpr '<=' AdditiveExpr 
+ *                 | RelationalExpr '>=' AdditiveExpr 
+ *
+ *  A <= B > C is allowed ? Answer from James, yes with
+ *  (AdditiveExpr <= AdditiveExpr) > AdditiveExpr
+ *  which is basically what got implemented.
+ *
+ * Parse and evaluate a Relational expression, then push the result
+ * on the stack
+ */
+
+void
+xmlXPathEvalRelationalExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalAdditiveExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while ((CUR == '<') ||
+           (CUR == '>') ||
+           ((CUR == '<') && (NXT(1) == '=')) ||
+           ((CUR == '>') && (NXT(1) == '='))) {
+	int inf, strict, ret;
+
+        if (CUR == '<') inf = 1;
+	else inf = 0;
+	if (NXT(1) == '=') strict = 0;
+	else strict = 1;
+	NEXT;
+	if (!strict) NEXT;
+	SKIP_BLANKS;
+        xmlXPathEvalAdditiveExpr(ctxt);
+	CHECK_ERROR;
+	ret = xmlXPathCompareValues(ctxt, inf, strict);
+	valuePush(ctxt, xmlXPathNewBoolean(ret));
+	SKIP_BLANKS;
+    }
+}
+
+/**
+ * xmlXPathEvalEqualityExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [23]   EqualityExpr ::=   RelationalExpr 
+ *                 | EqualityExpr '=' RelationalExpr 
+ *                 | EqualityExpr '!=' RelationalExpr 
+ *
+ *  A != B != C is allowed ? Answer from James, yes with
+ *  (RelationalExpr = RelationalExpr) = RelationalExpr
+ *  (RelationalExpr != RelationalExpr) != RelationalExpr
+ *  which is basically what got implemented.
+ *
+ * Parse and evaluate an Equality expression, then push the result on the stack
+ *
+ */
+void
+xmlXPathEvalEqualityExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalRelationalExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while ((CUR == '=') || ((CUR == '!') && (NXT(1) == '='))) {
+	xmlXPathObjectPtr res;
+	int eq, equal;
+
+        if (CUR == '=') eq = 1;
+	else eq = 0;
+	NEXT;
+	if (!eq) NEXT;
+	SKIP_BLANKS;
+        xmlXPathEvalRelationalExpr(ctxt);
+	CHECK_ERROR;
+	equal = xmlXPathEqualValues(ctxt);
+	if (eq) res = xmlXPathNewBoolean(equal);
+	else res = xmlXPathNewBoolean(!equal);
+	valuePush(ctxt, res);
+	SKIP_BLANKS;
+    }
+}
+
+/**
+ * xmlXPathEvalAndExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [22]   AndExpr ::=   EqualityExpr 
+ *                 | AndExpr 'and' EqualityExpr 
+ *
+ * Parse and evaluate an AND expression, then push the result on the stack
+ *
+ */
+void
+xmlXPathEvalAndExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalEqualityExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while ((CUR == 'a') && (NXT(1) == 'n') && (NXT(2) == 'd')) {
+	xmlXPathObjectPtr arg1, arg2;
+
+        SKIP(3);
+	SKIP_BLANKS;
+        xmlXPathEvalEqualityExpr(ctxt);
+	CHECK_ERROR;
+	xmlXPathBooleanFunction(ctxt, 1);
+	arg2 = valuePop(ctxt);
+	xmlXPathBooleanFunction(ctxt, 1);
+	arg1 = valuePop(ctxt);
+	arg1->boolval &= arg2->boolval;
+	valuePush(ctxt, arg1);
+	xmlXPathFreeObject(arg2);
+	SKIP_BLANKS;
+    }
+}
+
+/**
+ * xmlXPathEvalExpr:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [14]   Expr ::=   OrExpr 
+ *  [21]   OrExpr ::=   AndExpr 
+ *                 | OrExpr 'or' AndExpr 
+ *
+ * Parse and evaluate an expression, then push the result on the stack
+ *
+ */
+void
+xmlXPathEvalExpr(xmlXPathParserContextPtr ctxt) {
+    xmlXPathEvalAndExpr(ctxt);
+    CHECK_ERROR;
+    SKIP_BLANKS;
+    while ((CUR == 'o') && (NXT(1) == 'r')) {
+	xmlXPathObjectPtr arg1, arg2;
+
+        SKIP(2);
+	SKIP_BLANKS;
+        xmlXPathEvalAndExpr(ctxt);
+	CHECK_ERROR;
+	xmlXPathBooleanFunction(ctxt, 1);
+	arg2 = valuePop(ctxt);
+	xmlXPathBooleanFunction(ctxt, 1);
+	arg1 = valuePop(ctxt);
+	arg1->boolval |= arg2->boolval;
+	valuePush(ctxt, arg1);
+	xmlXPathFreeObject(arg2);
+	SKIP_BLANKS;
+    }
+    if ((ctxt->value != NULL) && (ctxt->value->type == XPATH_NODESET) &&
+	(ctxt->value->nodesetval != NULL))
+	xmlXPathNodeSetSort(ctxt->value->nodesetval);
+}
+
+/**
+ * xmlXPathEvaluatePredicateResult:
+ * @ctxt:  the XPath Parser context
+ * @res:  the Predicate Expression evaluation result
+ *
+ * Evaluate a predicate result for the current node.
+ * A PredicateExpr is evaluated by evaluating the Expr and converting
+ * the result to a boolean. If the result is a number, the result will
+ * be converted to true if the number is equal to the position of the
+ * context node in the context node list (as returned by the position
+ * function) and will be converted to false otherwise; if the result
+ * is not a number, then the result will be converted as if by a call
+ * to the boolean function. 
+ *
+ * Return 1 if predicate is true, 0 otherwise
+ */
+int
+xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
+                                xmlXPathObjectPtr res) {
+    if (res == NULL) return(0);
+    switch (res->type) {
+        case XPATH_BOOLEAN:
+	    return(res->boolval);
+        case XPATH_NUMBER:
+	    return(res->floatval == ctxt->context->proximityPosition);
+        case XPATH_NODESET:
+        case XPATH_XSLT_TREE:
+	    return(res->nodesetval->nodeNr != 0);
+        case XPATH_STRING:
+	    return((res->stringval != NULL) &&
+	           (xmlStrlen(res->stringval) != 0));
+        default:
+	    STRANGE
+    }
+    return(0);
+}
+
+/**
+ * xmlXPathEvalPredicate:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [8]   Predicate ::=   '[' PredicateExpr ']'
+ *  [9]   PredicateExpr ::=   Expr 
+ *
+ * ---------------------
+ * For each node in the node-set to be filtered, the PredicateExpr is
+ * evaluated with that node as the context node, with the number of nodes
+ * in the node-set as the context size, and with the proximity position
+ * of the node in the node-set with respect to the axis as the context
+ * position; if PredicateExpr evaluates to true for that node, the node
+ * is included in the new node-set; otherwise, it is not included.
+ * ---------------------
+ *
+ * Parse and evaluate a predicate for all the elements of the
+ * current node list. Then refine the list by removing all
+ * nodes where the predicate is false.
+ */
+void
+xmlXPathEvalPredicate(xmlXPathParserContextPtr ctxt) {
+    const xmlChar *cur;
+    xmlXPathObjectPtr res;
+    xmlXPathObjectPtr obj, tmp;
+    xmlNodeSetPtr newset = NULL;
+    xmlNodeSetPtr oldset;
+    xmlNodePtr oldnode;
+    int i;
+
+    SKIP_BLANKS;
+    if (CUR != '[') {
+	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
+    }
+    NEXT;
+    SKIP_BLANKS;
+
+    /*
+     * Extract the old set, and then evaluate the result of the
+     * expression for all the element in the set. use it to grow
+     * up a new set.
+     */
+    CHECK_TYPE(XPATH_NODESET);
+    obj = valuePop(ctxt);
+    oldset = obj->nodesetval;
+    oldnode = ctxt->context->node;
+    ctxt->context->node = NULL;
+
+    if ((oldset == NULL) || (oldset->nodeNr == 0)) {
+	ctxt->context->contextSize = 0;
+	ctxt->context->proximityPosition = 0;
+	xmlXPathEvalExpr(ctxt);
+	res = valuePop(ctxt);
+	if (res != NULL)
+	    xmlXPathFreeObject(res);
+	valuePush(ctxt, obj);
+	CHECK_ERROR;
+    } else {
+	/*
+	 * Save the expression pointer since we will have to evaluate
+	 * it multiple times. Initialize the new set.
+	 */
+        cur = ctxt->cur;
+	newset = xmlXPathNodeSetCreate(NULL);
+	
+        for (i = 0; i < oldset->nodeNr; i++) {
+	    ctxt->cur = cur;
+
+	    /*
+	     * Run the evaluation with a node list made of a single item
+	     * in the nodeset.
+	     */
+	    ctxt->context->node = oldset->nodeTab[i];
+	    tmp = xmlXPathNewNodeSet(ctxt->context->node);
+	    valuePush(ctxt, tmp);
+	    ctxt->context->contextSize = oldset->nodeNr;
+	    ctxt->context->proximityPosition = i + 1;
+
+	    xmlXPathEvalExpr(ctxt);
+	    CHECK_ERROR;
+
+	    /*
+	     * The result of the evaluation need to be tested to
+	     * decided whether the filter succeeded or not
+	     */
+	    res = valuePop(ctxt);
+	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
+	        xmlXPathNodeSetAdd(newset, oldset->nodeTab[i]);
+	    }
+
+	    /*
+	     * Cleanup
+	     */
+	    if (res != NULL)
+		xmlXPathFreeObject(res);
+	    if (ctxt->value == tmp) {
+		res = valuePop(ctxt);
+		xmlXPathFreeObject(res);
+	    }
+	    
+	    ctxt->context->node = NULL;
+	}
+
+	/*
+	 * The result is used as the new evaluation set.
+	 */
+	xmlXPathFreeObject(obj);
+	ctxt->context->node = NULL;
+	ctxt->context->contextSize = -1;
+	ctxt->context->proximityPosition = -1;
+	valuePush(ctxt, xmlXPathWrapNodeSet(newset));
+    }
+    if (CUR != ']') {
+	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
+    }
+
+    NEXT;
+    SKIP_BLANKS;
+#ifdef DEBUG_STEP
+    xmlGenericError(xmlGenericErrorContext, "After predicate : ");
+    xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
+	    ctxt->value->nodesetval);
+#endif
+    ctxt->context->node = oldnode;
+}
+
+/**
+ * xmlXPathEvalNodeTest:
+ * @ctxt:  the XPath Parser context
+ * @test:  pointer to a xmlXPathTestVal
+ * @type:  pointer to a xmlXPathTypeVal
+ * @prefix:  placeholder for a possible name prefix
+ *
+ * [7] NodeTest ::=   NameTest
+ *		    | NodeType '(' ')'
+ *		    | 'processing-instruction' '(' Literal ')'
+ *
+ * [37] NameTest ::=  '*'
+ *		    | NCName ':' '*'
+ *		    | QName
+ * [38] NodeType ::= 'comment'
+ *		   | 'text'
+ *		   | 'processing-instruction'
+ *		   | 'node'
+ *
+ * Returns the name found and update @test, @type and @prefix appropriately
+ */
+xmlChar *
+xmlXPathEvalNodeTest(xmlXPathParserContextPtr ctxt, xmlXPathTestVal *test,
+	             xmlXPathTypeVal *type, const xmlChar **prefix, xmlChar *name) {
+    int blanks;
+
+    if ((test == NULL) || (type == NULL) || (prefix == NULL)) {
+	STRANGE;
+	return(NULL);
+    }
+    *type = 0;
+    *test = 0;
+    *prefix = NULL;
+    SKIP_BLANKS;
+
+    if ((name == NULL) && (CUR == '*')) {
+	/*
+	 * All elements
+	 */
+	NEXT;
+	*test = NODE_TEST_ALL;
+	return(NULL);
+    }
+
+    if (name == NULL)
+	name = xmlXPathParseNCName(ctxt);
+    if (name == NULL) {
+	XP_ERROR0(XPATH_EXPR_ERROR);
+    }
+
+    blanks = IS_BLANK(CUR);
+    SKIP_BLANKS;
+    if (CUR == '(') {
+	NEXT;
+	/*
+	 * NodeType or PI search
+	 */
+	if (xmlStrEqual(name, BAD_CAST "comment"))
+	    *type = NODE_TYPE_COMMENT;
+	else if (xmlStrEqual(name, BAD_CAST "node"))
+	    *type = NODE_TYPE_NODE;
+	else if (xmlStrEqual(name, BAD_CAST "processing-instruction"))
+	    *type = NODE_TYPE_PI;
+	else if (xmlStrEqual(name, BAD_CAST "text"))
+	    *type = NODE_TYPE_TEXT;
+	else {
+	    if (name != NULL)
+		xmlFree(name);
+	    XP_ERROR0(XPATH_EXPR_ERROR);
+	}
+
+	*test = NODE_TEST_TYPE;
+	
+	SKIP_BLANKS;
+	if (*type == NODE_TYPE_PI) {
+	    /*
+	     * Specific case: search a PI by name.
+	     */
+	    xmlXPathObjectPtr cur;
+
+	    if (name != NULL)
+		xmlFree(name);
+
+	    xmlXPathEvalLiteral(ctxt);
+	    CHECK_ERROR 0;
+	    xmlXPathStringFunction(ctxt, 1);
+	    CHECK_ERROR0;
+	    cur = valuePop(ctxt);
+	    name = xmlStrdup(cur->stringval);
+	    xmlXPathFreeObject(cur);
+	    SKIP_BLANKS;
+	}
+	if (CUR != ')') {
+	    if (name != NULL)
+		xmlFree(name);
+	    XP_ERROR0(XPATH_UNCLOSED_ERROR);
+	}
+	NEXT;
+	return(name);
+    }
+    *test = NODE_TEST_NAME;
+    if ((!blanks) && (CUR == ':')) {
+	NEXT;
+
+	/*
+	 * get the namespace name for this prefix
+	 */
+	*prefix = xmlXPathNsLookup(ctxt->context, name);
+	if (name != NULL)
+	    xmlFree(name);
+	if (*prefix == NULL) {
+	    XP_ERROR0(XPATH_UNDEF_PREFIX_ERROR);
+	}
+
+	if (CUR == '*') {
+	    /*
+	     * All elements
+	     */
+	    NEXT;
+	    *test = NODE_TEST_ALL;
+	    return(NULL);
+	}
+
+	name = xmlXPathParseNCName(ctxt);
+	if (name == NULL) {
+	    XP_ERROR0(XPATH_EXPR_ERROR);
+	}
+    }
+    return(name);
+}
+
+/**
+ * xmlXPathIsAxisName:
+ * @name:  a preparsed name token
+ *
+ * [6] AxisName ::=   'ancestor'
+ *                  | 'ancestor-or-self'
+ *                  | 'attribute'
+ *                  | 'child'
+ *                  | 'descendant'
+ *                  | 'descendant-or-self'
+ *                  | 'following'
+ *                  | 'following-sibling'
+ *                  | 'namespace'
+ *                  | 'parent'
+ *                  | 'preceding'
+ *                  | 'preceding-sibling'
+ *                  | 'self'
+ *
+ * Returns the axis or 0
+ */
+xmlXPathAxisVal
+xmlXPathIsAxisName(const xmlChar *name) {
+    xmlXPathAxisVal ret = 0;
+    switch (name[0]) {
+	case 'a':
+	    if (xmlStrEqual(name, BAD_CAST "ancestor"))
+		ret = AXIS_ANCESTOR;
+	    if (xmlStrEqual(name, BAD_CAST "ancestor-or-self"))
+		ret = AXIS_ANCESTOR_OR_SELF;
+	    if (xmlStrEqual(name, BAD_CAST "attribute"))
+		ret = AXIS_ATTRIBUTE;
+	    break;
+	case 'c':
+	    if (xmlStrEqual(name, BAD_CAST "child"))
+		ret = AXIS_CHILD;
+	    break;
+	case 'd':
+	    if (xmlStrEqual(name, BAD_CAST "descendant"))
+		ret = AXIS_DESCENDANT;
+	    if (xmlStrEqual(name, BAD_CAST "descendant-or-self"))
+		ret = AXIS_DESCENDANT_OR_SELF;
+	    break;
+	case 'f':
+	    if (xmlStrEqual(name, BAD_CAST "following"))
+		ret = AXIS_FOLLOWING;
+	    if (xmlStrEqual(name, BAD_CAST "following-sibling"))
+		ret = AXIS_FOLLOWING_SIBLING;
+	    break;
+	case 'n':
+	    if (xmlStrEqual(name, BAD_CAST "namespace"))
+		ret = AXIS_NAMESPACE;
+	    break;
+	case 'p':
+	    if (xmlStrEqual(name, BAD_CAST "parent"))
+		ret = AXIS_PARENT;
+	    if (xmlStrEqual(name, BAD_CAST "preceding"))
+		ret = AXIS_PRECEDING;
+	    if (xmlStrEqual(name, BAD_CAST "preceding-sibling"))
+		ret = AXIS_PRECEDING_SIBLING;
+	    break;
+	case 's':
+	    if (xmlStrEqual(name, BAD_CAST "self"))
+		ret = AXIS_SELF;
+	    break;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathEvalAxisSpecifier:
+ * @ctxt:  the XPath Parser context
+ *
+ *
+ * Returns the axis found
+ */
+xmlXPathAxisVal
+xmlXPathEvalAxisSpecifier(xmlXPathParserContextPtr ctxt) {
+    xmlXPathAxisVal ret = AXIS_CHILD;
+    int blank = 0;
+    xmlChar *name;
+
+    if (CUR == '@') {
+	NEXT;
+	return(AXIS_ATTRIBUTE);
+    } else {
+	name = xmlXPathParseNCName(ctxt);
+	if (name == NULL) {
+	    XP_ERROR0(XPATH_EXPR_ERROR);
+	}
+	if (IS_BLANK(CUR))
+	    blank = 1;
+	SKIP_BLANKS;
+	if ((CUR == ':') && (NXT(1) == ':')) {
+	    ret = xmlXPathIsAxisName(name);
+	} else if ((blank) && (CUR == ':'))
+	    XP_ERROR0(XPATH_EXPR_ERROR);
+
+	xmlFree(name);
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPathEvalStep:
+ * @ctxt:  the XPath Parser context
+ *
+ * [4] Step ::=   AxisSpecifier NodeTest Predicate*
+ *                  | AbbreviatedStep 
+ *
+ * [12] AbbreviatedStep ::=   '.' | '..'
+ *
+ * [5] AxisSpecifier ::= AxisName '::'
+ *                  | AbbreviatedAxisSpecifier
+ *
+ * [13] AbbreviatedAxisSpecifier ::= '@'?
+ *
+ * Modified for XPtr range support as:
+ *
+ *  [4xptr] Step ::= AxisSpecifier NodeTest Predicate*
+ *                     | AbbreviatedStep
+ *                     | 'range-to' '(' Expr ')' Predicate*
+ *
+ * Evaluate one step in a Location Path
+ * A location step of . is short for self::node(). This is
+ * particularly useful in conjunction with //. For example, the
+ * location path .//para is short for
+ * self::node()/descendant-or-self::node()/child::para
+ * and so will select all para descendant elements of the context
+ * node.
+ * Similarly, a location step of .. is short for parent::node().
+ * For example, ../title is short for parent::node()/child::title
+ * and so will select the title children of the parent of the context
+ * node.
+ */
+void
+xmlXPathEvalStep(xmlXPathParserContextPtr ctxt) {
+    SKIP_BLANKS;
+    if ((CUR == '.') && (NXT(1) == '.')) {
+	SKIP(2);
+	SKIP_BLANKS;
+	xmlXPathNodeCollectAndTest(ctxt, AXIS_PARENT,
+			 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
+    } else if (CUR == '.') {
+	NEXT;
+	SKIP_BLANKS;
+    } else {
+	xmlChar *name = NULL;
+	const xmlChar *prefix = NULL;
+	xmlXPathTestVal test;
+	xmlXPathAxisVal axis;
+	xmlXPathTypeVal type;
+
+	/*
+	 * The modification needed for XPointer change to the production
+	 */
+#ifdef LIBXML_XPTR_ENABLED
+	if (ctxt->context->xptr) {
+	    name = xmlXPathParseNCName(ctxt);
+	    if ((name != NULL) && (xmlStrEqual(name, BAD_CAST "range-to"))) {
+		xmlFree(name);
+		SKIP_BLANKS;
+		if (CUR != '(') {
+		    XP_ERROR(XPATH_EXPR_ERROR);
+		}
+		NEXT;
+		SKIP_BLANKS;
+
+		xmlXPtrRangeToFunction(ctxt, 1);
+		CHECK_ERROR;
+
+		SKIP_BLANKS;
+		if (CUR != ')') {
+		    XP_ERROR(XPATH_EXPR_ERROR);
+		}
+		NEXT;
+		goto eval_predicates;
+	    }
+	}
+#endif
+	if (name == NULL)
+	    name = xmlXPathParseNCName(ctxt);
+	if (name != NULL) {
+	    axis = xmlXPathIsAxisName(name);
+	    if (axis != 0) {
+		SKIP_BLANKS;
+		if ((CUR == ':') && (NXT(1) == ':')) {
+		    SKIP(2);
+		    xmlFree(name);
+		    name = NULL;
+		} else {
+		    /* an element name can conflict with an axis one :-\ */
+		    axis = AXIS_CHILD;
+		}
+	    } else {
+	        axis = AXIS_CHILD;
+	    }
+	} else if (CUR == '@') {
+	    NEXT;
+	    axis = AXIS_ATTRIBUTE;
+	} else {
+	    axis = AXIS_CHILD;
+	}
+
+	CHECK_ERROR;
+
+	name = xmlXPathEvalNodeTest(ctxt, &test, &type, &prefix, name);
+	if (test == 0)
+	    return;
+
+#ifdef DEBUG_STEP
+	xmlGenericError(xmlGenericErrorContext,
+		"Basis : computing new set\n");
+#endif
+	xmlXPathNodeCollectAndTest(ctxt, axis, test, type, prefix, name);
+#ifdef DEBUG_STEP
+	xmlGenericError(xmlGenericErrorContext, "Basis : ");
+	xmlGenericErrorContextNodeSet(stdout, ctxt->value->nodesetval);
+#endif
+	if (name != NULL)
+	    xmlFree(name);
+
+eval_predicates:
+	SKIP_BLANKS;
+	while (CUR == '[') {
+	    xmlXPathEvalPredicate(ctxt);
+	}
+    }
+#ifdef DEBUG_STEP
+    xmlGenericError(xmlGenericErrorContext, "Step : ");
+    xmlGenericErrorContextNodeSet(xmlGenericErrorContext,
+	    ctxt->value->nodesetval);
+#endif
+}
+
+/**
+ * xmlXPathEvalRelativeLocationPath:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [3]   RelativeLocationPath ::=   Step 
+ *                     | RelativeLocationPath '/' Step 
+ *                     | AbbreviatedRelativeLocationPath 
+ *  [11]  AbbreviatedRelativeLocationPath ::=   RelativeLocationPath '//' Step 
+ *
+ */
+void
+#ifdef VMS
+xmlXPathEvalRelLocationPath
+#else
+xmlXPathEvalRelativeLocationPath
+#endif
+(xmlXPathParserContextPtr ctxt) {
+    SKIP_BLANKS;
+    if ((CUR == '/') && (NXT(1) == '/')) {
+	SKIP(2);
+	SKIP_BLANKS;
+	xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
+			 NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
+    } else if (CUR == '/') {
+	    NEXT;
+	SKIP_BLANKS;
+    }
+    xmlXPathEvalStep(ctxt);
+    SKIP_BLANKS;
+    while (CUR == '/') {
+	if ((CUR == '/') && (NXT(1) == '/')) {
+	    SKIP(2);
+	    SKIP_BLANKS;
+	    xmlXPathNodeCollectAndTest(ctxt, AXIS_DESCENDANT_OR_SELF,
+			     NODE_TEST_TYPE, NODE_TYPE_NODE, NULL, NULL);
+	    xmlXPathEvalStep(ctxt);
+	} else if (CUR == '/') {
+	    NEXT;
+	    SKIP_BLANKS;
+	    xmlXPathEvalStep(ctxt);
+	}
+	SKIP_BLANKS;
+    }
+}
+
+/**
+ * xmlXPathEvalLocationPath:
+ * @ctxt:  the XPath Parser context
+ *
+ *  [1]   LocationPath ::=   RelativeLocationPath 
+ *                     | AbsoluteLocationPath 
+ *  [2]   AbsoluteLocationPath ::=   '/' RelativeLocationPath?
+ *                     | AbbreviatedAbsoluteLocationPath 
+ *  [10]   AbbreviatedAbsoluteLocationPath ::=   
+ *                           '//' RelativeLocationPath 
+ *
+ * // is short for /descendant-or-self::node()/. For example,
+ * //para is short for /descendant-or-self::node()/child::para and
+ * so will select any para element in the document (even a para element
+ * that is a document element will be selected by //para since the
+ * document element node is a child of the root node); div//para is
+ * short for div/descendant-or-self::node()/child::para and so will
+ * select all para descendants of div children.
+ */
+void
+xmlXPathEvalLocationPath(xmlXPathParserContextPtr ctxt) {
+    SKIP_BLANKS;
+    if (CUR != '/') {
+        xmlXPathEvalRelativeLocationPath(ctxt);
+    } else {
+	while (CUR == '/') {
+	    if ((CUR == '/') && (NXT(1) == '/')) {
+		SKIP(2);
+		SKIP_BLANKS;
+		xmlXPathNodeCollectAndTest(ctxt,
+		                 AXIS_DESCENDANT_OR_SELF, NODE_TEST_TYPE,
+				 NODE_TYPE_NODE, NULL, NULL);
+		xmlXPathEvalRelativeLocationPath(ctxt);
+	    } else if (CUR == '/') {
+		NEXT;
+		SKIP_BLANKS;
+		if (CUR != 0)
+		    xmlXPathEvalRelativeLocationPath(ctxt);
+	    }
+	}
+    }
+}
+
+/**
+ * xmlXPathEval:
+ * @str:  the XPath expression
+ * @ctx:  the XPath context
+ *
+ * Evaluate the XPath Location Path in the given context.
+ *
+ * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
+ *         the caller has to free the object.
+ */
+xmlXPathObjectPtr
+xmlXPathEval(const xmlChar *str, xmlXPathContextPtr ctx) {
+    xmlXPathParserContextPtr ctxt;
+    xmlXPathObjectPtr res, tmp, init = NULL;
+    int stack = 0;
+
+    xmlXPathInit();
+
+    CHECK_CONTEXT(ctx)
+
+    ctxt = xmlXPathNewParserContext(str, ctx);
+    /**** TAG:9999
+    if (ctx->node != NULL) {
+	init = xmlXPathNewNodeSet(ctx->node);
+	valuePush(ctxt, init);
+    }
+     ****/
+    xmlXPathEvalExpr(ctxt);
+
+    if (ctxt->value == NULL) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathEval: evaluation failed\n");
+	res = NULL;
+    } else if (*ctxt->cur != 0) {
+	xmlXPatherror(ctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
+	res = NULL;
+    } else {
+	res = valuePop(ctxt);
+    }
+
+    do {
+        tmp = valuePop(ctxt);
+	if (tmp != NULL) {
+	    if (tmp != init)
+		stack++;    
+	    xmlXPathFreeObject(tmp);
+        }
+    } while (tmp != NULL);
+    if ((stack != 0) && (res != NULL)) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathEval: %d object left on the stack\n",
+	        stack);
+    }
+    if (ctxt->error != XPATH_EXPRESSION_OK) {
+	xmlXPathFreeObject(res);
+	res = NULL;
+    }
+        
+    xmlXPathFreeParserContext(ctxt);
+    return(res);
+}
+
+/**
+ * xmlXPathEvalExpression:
+ * @str:  the XPath expression
+ * @ctxt:  the XPath context
+ *
+ * Evaluate the XPath expression in the given context.
+ *
+ * Returns the xmlXPathObjectPtr resulting from the evaluation or NULL.
+ *         the caller has to free the object.
+ */
+xmlXPathObjectPtr
+xmlXPathEvalExpression(const xmlChar *str, xmlXPathContextPtr ctxt) {
+    xmlXPathParserContextPtr pctxt;
+    xmlXPathObjectPtr res, tmp;
+    int stack = 0;
+
+    xmlXPathInit();
+
+    CHECK_CONTEXT(ctxt)
+
+    pctxt = xmlXPathNewParserContext(str, ctxt);
+    xmlXPathEvalExpr(pctxt);
+
+    if (*pctxt->cur != 0) {
+	xmlXPatherror(pctxt, __FILE__, __LINE__, XPATH_EXPR_ERROR);
+	res = NULL;
+    } else {
+	res = valuePop(pctxt);
+    }
+    do {
+        tmp = valuePop(pctxt);
+	if (tmp != NULL) {
+	    xmlXPathFreeObject(tmp);
+	    stack++;
+	}
+    } while (tmp != NULL);
+    if ((stack != 0) && (res != NULL)) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlXPathEvalExpression: %d object left on the stack\n",
+	        stack);
+    }
+    xmlXPathFreeParserContext(pctxt);
+    return(res);
+}
+
+/**
+ * xmlXPathRegisterAllFunctions:
+ * @ctxt:  the XPath context
+ *
+ * Registers all default XPath functions in this context
+ */
+void
+xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt)
+{
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"boolean",
+                         xmlXPathBooleanFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"ceiling",
+                         xmlXPathCeilingFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"count",
+                         xmlXPathCountFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"concat",
+                         xmlXPathConcatFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"contains",
+                         xmlXPathContainsFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"id",
+                         xmlXPathIdFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"false",
+                         xmlXPathFalseFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"floor",
+                         xmlXPathFloorFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"last",
+                         xmlXPathLastFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"lang",
+                         xmlXPathLangFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"local-name",
+                         xmlXPathLocalNameFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"not",
+                         xmlXPathNotFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"name",
+                         xmlXPathNameFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"namespace-uri",
+                         xmlXPathNamespaceURIFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"normalize-space",
+                         xmlXPathNormalizeFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"number",
+                         xmlXPathNumberFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"position",
+                         xmlXPathPositionFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"round",
+                         xmlXPathRoundFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string",
+                         xmlXPathStringFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"string-length",
+                         xmlXPathStringLengthFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"starts-with",
+                         xmlXPathStartsWithFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring",
+                         xmlXPathSubstringFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-before",
+                         xmlXPathSubstringBeforeFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"substring-after",
+                         xmlXPathSubstringAfterFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"sum",
+                         xmlXPathSumFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"true",
+                         xmlXPathTrueFunction);
+    xmlXPathRegisterFunc(ctxt, (const xmlChar *)"translate",
+                         xmlXPathTranslateFunction);
+}
+
+#endif /* LIBXML_XPATH_ENABLED */
diff --git a/xpath.h b/xpath.h
new file mode 100644
index 0000000..f8fd861
--- /dev/null
+++ b/xpath.h
@@ -0,0 +1,278 @@
+/*
+ * xpath.c: interface for XML Path Language implementation
+ *
+ * Reference: W3C Working Draft 5 July 1999
+ *            http://www.w3.org/Style/XSL/Group/1999/07/xpath-19990705.html
+ *
+ * See COPYRIGHT for the status of this software
+ *
+ * Author: Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XPATH_H__
+#define __XML_XPATH_H__
+
+#include <libxml/tree.h>
+#include <libxml/hash.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _xmlXPathContext xmlXPathContext;
+typedef xmlXPathContext *xmlXPathContextPtr;
+typedef struct _xmlXPathParserContext xmlXPathParserContext;
+typedef xmlXPathParserContext *xmlXPathParserContextPtr;
+
+/**
+ * The set of XPath error codes
+ */
+
+typedef enum {
+    XPATH_EXPRESSION_OK = 0,
+    XPATH_NUMBER_ERROR,
+    XPATH_UNFINISHED_LITERAL_ERROR,
+    XPATH_START_LITERAL_ERROR,
+    XPATH_VARIABLE_REF_ERROR,
+    XPATH_UNDEF_VARIABLE_ERROR,
+    XPATH_INVALID_PREDICATE_ERROR,
+    XPATH_EXPR_ERROR,
+    XPATH_UNCLOSED_ERROR,
+    XPATH_UNKNOWN_FUNC_ERROR,
+    XPATH_INVALID_OPERAND,
+    XPATH_INVALID_TYPE,
+    XPATH_INVALID_ARITY,
+    XPATH_INVALID_CTXT_SIZE,
+    XPATH_INVALID_CTXT_POSITION,
+    XPATH_MEMORY_ERROR,
+    XPTR_SYNTAX_ERROR,
+    XPTR_RESOURCE_ERROR,
+    XPTR_SUB_RESOURCE_ERROR,
+    XPATH_UNDEF_PREFIX_ERROR
+} xmlXPathError;
+
+/*
+ * A node-set (an unordered collection of nodes without duplicates) 
+ */
+typedef struct _xmlNodeSet xmlNodeSet;
+typedef xmlNodeSet *xmlNodeSetPtr;
+struct _xmlNodeSet {
+    int nodeNr;			/* number of nodes in the set */
+    int nodeMax;		/* size of the array as allocated */
+    xmlNodePtr *nodeTab;	/* array of nodes in no particular order */
+};
+
+/*
+ * An expression is evaluated to yield an object, which
+ * has one of the following four basic types:
+ *   - node-set
+ *   - boolean
+ *   - number
+ *   - string
+ *
+ * @@ XPointer will add more types !
+ */
+
+typedef enum {
+    XPATH_UNDEFINED = 0,
+    XPATH_NODESET = 1,
+    XPATH_BOOLEAN = 2,
+    XPATH_NUMBER = 3,
+    XPATH_STRING = 4,
+    XPATH_POINT = 5,
+    XPATH_RANGE = 6,
+    XPATH_LOCATIONSET = 7,
+    XPATH_USERS = 8,
+    XPATH_XSLT_TREE = 9  /* An XSLT value tree, non modifiable */
+} xmlXPathObjectType;
+
+typedef struct _xmlXPathObject xmlXPathObject;
+typedef xmlXPathObject *xmlXPathObjectPtr;
+struct _xmlXPathObject {
+    xmlXPathObjectType type;
+    xmlNodeSetPtr nodesetval;
+    int boolval;
+    double floatval;
+    xmlChar *stringval;
+    void *user;
+    int index;
+    void *user2;
+    int index2;
+};
+
+/*
+ * A conversion function is associated to a type and used to cast
+ * the new type to primitive values.
+ */
+typedef int (*xmlXPathConvertFunc) (xmlXPathObjectPtr obj, int type);
+
+/*
+ * Extra type: a name and a conversion function.
+ */
+
+typedef struct _xmlXPathType xmlXPathType;
+typedef xmlXPathType *xmlXPathTypePtr;
+struct _xmlXPathType {
+    const xmlChar         *name;		/* the type name */
+    xmlXPathConvertFunc func;		/* the conversion function */
+};
+
+/*
+ * Extra variable: a name and a value.
+ */
+
+typedef struct _xmlXPathVariable xmlXPathVariable;
+typedef xmlXPathVariable *xmlXPathVariablePtr;
+struct _xmlXPathVariable {
+    const xmlChar       *name;		/* the variable name */
+    xmlXPathObjectPtr value;		/* the value */
+};
+
+/*
+ * an evaluation function, the parameters are on the context stack
+ */
+
+typedef void (*xmlXPathEvalFunc)(xmlXPathParserContextPtr ctxt, int nargs);
+
+/*
+ * Extra function: a name and a evaluation function.
+ */
+
+typedef struct _xmlXPathFunct xmlXPathFunct;
+typedef xmlXPathFunct *xmlXPathFuncPtr;
+struct _xmlXPathFunct {
+    const xmlChar      *name;		/* the function name */
+    xmlXPathEvalFunc func;		/* the evaluation function */
+};
+
+/*
+ * An axis traversal function. To traverse an axis, the engine calls
+ * the first time with cur == NULL and repeat until the function returns
+ * NULL indicating the end of the axis traversal.
+ */
+
+typedef xmlXPathObjectPtr (*xmlXPathAxisFunc)	(xmlXPathParserContextPtr ctxt,
+						 xmlXPathObjectPtr cur);
+
+/*
+ * Extra axis: a name and an axis function.
+ */
+
+typedef struct _xmlXPathAxis xmlXPathAxis;
+typedef xmlXPathAxis *xmlXPathAxisPtr;
+struct _xmlXPathAxis {
+    const xmlChar      *name;		/* the axis name */
+    xmlXPathAxisFunc func;		/* the search function */
+};
+
+/* 
+ * Expression evaluation occurs with respect to a context.
+ * he context consists of:
+ *    - a node (the context node) 
+ *    - a node list (the context node list) 
+ *    - a set of variable bindings 
+ *    - a function library 
+ *    - the set of namespace declarations in scope for the expression 
+ * Following the switch to hash tables, this need to be trimmed up at
+ * the next binary incompatible release.
+ */
+
+struct _xmlXPathContext {
+    xmlDocPtr doc;			/* The current document */
+    xmlNodePtr node;			/* The current node */
+
+    int nb_variables_unused;		/* unused (hash table) */
+    int max_variables_unused;		/* unused (hash table) */
+    xmlHashTablePtr varHash;		/* Hash table of defined variables */
+
+    int nb_types;			/* number of defined types */
+    int max_types;			/* max number of types */
+    xmlXPathTypePtr types;		/* Array of defined types */
+
+    int nb_funcs_unused;		/* unused (hash table) */
+    int max_funcs_unused;		/* unused (hash table) */
+    xmlHashTablePtr funcHash;		/* Hash table of defined funcs */
+
+    int nb_axis;			/* number of defined axis */
+    int max_axis;			/* max number of axis */
+    xmlXPathAxisPtr axis;		/* Array of defined axis */
+
+    /* the namespace nodes of the context node */
+    xmlNsPtr *namespaces;		/* Array of namespaces */
+    int nsNr;				/* number of namespace in scope */
+    void *user;				/* function to free */
+
+    /* extra variables */
+    int contextSize;			/* the context size */
+    int proximityPosition;		/* the proximity position */
+
+    /* extra stuff for XPointer */
+    int xptr;				/* it this an XPointer context */
+    xmlNodePtr here;			/* for here() */
+    xmlNodePtr origin;			/* for origin() */
+
+    /* the set of namespace declarations in scope for the expression */
+    xmlHashTablePtr nsHash;		/* The namespaces hash table */
+    void *varLookupFunc;		/* variable lookup func */
+    void *varLookupData;		/* variable lookup data */
+
+    /* Possibility to link in an extra item */
+    void *extra;                        /* needed for XSLT */
+};
+
+/*
+ * An XPath parser context, it contains pure parsing informations,
+ * an xmlXPathContext, and the stack of objects.
+ */
+struct _xmlXPathParserContext {
+    const xmlChar *cur;			/* the current char being parsed */
+    const xmlChar *base;			/* the full expression */
+
+    int error;				/* error code */
+
+    xmlXPathContextPtr  context;	/* the evaluation context */
+    xmlXPathObjectPtr     value;	/* the current value */
+    int                 valueNr;	/* number of values stacked */
+    int                valueMax;	/* max number of values stacked */
+    xmlXPathObjectPtr *valueTab;	/* stack of values */
+};
+
+/*
+ * An XPath function
+ * The arguments (if any) are popped out of the context stack
+ * and the result is pushed on the stack.
+ */
+
+typedef void (*xmlXPathFunction) (xmlXPathParserContextPtr ctxt, int nargs);
+
+/************************************************************************
+ *									*
+ *			Public API					*
+ *									*
+ ************************************************************************/
+
+/**
+ * Evaluation functions.
+ */
+void		   xmlXPathInit			(void);
+xmlXPathContextPtr xmlXPathNewContext		(xmlDocPtr doc);
+void		   xmlXPathFreeContext		(xmlXPathContextPtr ctxt);
+xmlXPathObjectPtr  xmlXPathEval			(const xmlChar *str,
+						 xmlXPathContextPtr ctxt);
+xmlXPathObjectPtr  xmlXPathEvalXPtrExpr		(const xmlChar *str,
+						 xmlXPathContextPtr ctxt);
+void		   xmlXPathFreeObject		(xmlXPathObjectPtr obj);
+xmlXPathObjectPtr  xmlXPathEvalExpression	(const xmlChar *str,
+						 xmlXPathContextPtr ctxt);
+xmlNodeSetPtr	   xmlXPathNodeSetCreate	(xmlNodePtr val);
+void		   xmlXPathFreeNodeSetList	(xmlXPathObjectPtr obj);
+void		   xmlXPathFreeNodeSet		(xmlNodeSetPtr obj);
+xmlXPathObjectPtr  xmlXPathObjectCopy		(xmlXPathObjectPtr val);
+int		   xmlXPathCmpNodes		(xmlNodePtr node1,
+						 xmlNodePtr node2);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* ! __XML_XPATH_H__ */
diff --git a/xpathInternals.h b/xpathInternals.h
new file mode 100644
index 0000000..51f6ad5
--- /dev/null
+++ b/xpathInternals.h
@@ -0,0 +1,236 @@
+/*
+ * xpath.c: internal interfaces for XML Path Language implementation
+ *          used to build new modules on top of XPath
+ *
+ * See COPYRIGHT for the status of this software
+ *
+ * Author: Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XPATH_INTERNALS_H__
+#define __XML_XPATH_INTERNALS_H__
+
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/************************************************************************
+ *									*
+ *			Helpers						*
+ *									*
+ ************************************************************************/
+
+#define CHECK_ERROR							\
+    if (ctxt->error != XPATH_EXPRESSION_OK) return
+
+#define CHECK_ERROR0							\
+    if (ctxt->error != XPATH_EXPRESSION_OK) return(0)
+
+#define XP_ERROR(X)							\
+    { xmlXPatherror(ctxt, __FILE__, __LINE__, X);			\
+      ctxt->error = (X); return; }
+
+#define XP_ERROR0(X)							\
+    { xmlXPatherror(ctxt, __FILE__, __LINE__, X);			\
+      ctxt->error = (X); return(0); }
+
+#define CHECK_TYPE(typeval)						\
+    if ((ctxt->value == NULL) || (ctxt->value->type != typeval))	\
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+#define CHECK_ARITY(x)							\
+    if (nargs != (x))							\
+        XP_ERROR(XPATH_INVALID_ARITY);
+
+#define CAST_TO_STRING							\
+    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_STRING))	\
+        xmlXPathStringFunction(ctxt, 1);
+
+#define CAST_TO_NUMBER							\
+    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_NUMBER))	\
+        xmlXPathNumberFunction(ctxt, 1);
+
+#define CAST_TO_BOOLEAN							\
+    if ((ctxt->value != NULL) && (ctxt->value->type != XPATH_BOOLEAN))	\
+        xmlXPathBooleanFunction(ctxt, 1);
+
+/*
+ * Varibale Lookup forwarding
+ */
+typedef xmlXPathObjectPtr
+	(*xmlXPathVariableLookupFunc)	(void *ctxt,
+					 const xmlChar *name,
+					 const xmlChar *ns_uri);
+
+void	xmlXPathRegisterVariableLookup	(xmlXPathContextPtr ctxt,
+					 xmlXPathVariableLookupFunc f,
+					 void *varCtxt);
+
+/*
+ * Error reporting
+ */
+void		xmlXPatherror	(xmlXPathParserContextPtr ctxt,
+				 const char *file,
+				 int line,
+				 int no);
+
+void		xmlXPathDebugDumpObject	(FILE *output,
+					 xmlXPathObjectPtr cur,
+					 int depth);
+
+/**
+ * Extending a context
+ */
+
+int		   xmlXPathRegisterNs		(xmlXPathContextPtr ctxt,
+						 const xmlChar *prefix,
+						 const xmlChar *ns_uri);
+const xmlChar *	   xmlXPathNsLookup		(xmlXPathContextPtr ctxt,
+						 const xmlChar *ns_uri);
+void		   xmlXPathRegisteredNsCleanup	(xmlXPathContextPtr ctxt);
+
+int		   xmlXPathRegisterFunc		(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 xmlXPathFunction f);
+int		   xmlXPathRegisterFuncNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri,
+						 xmlXPathFunction f);
+int		   xmlXPathRegisterVariable	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 xmlXPathObjectPtr value);
+int		   xmlXPathRegisterVariableNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri,
+						 xmlXPathObjectPtr value);
+xmlXPathFunction   xmlXPathFunctionLookup	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name);
+xmlXPathFunction   xmlXPathFunctionLookupNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
+void		   xmlXPathRegisteredFuncsCleanup(xmlXPathContextPtr ctxt);
+xmlXPathObjectPtr  xmlXPathVariableLookup	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name);
+xmlXPathObjectPtr  xmlXPathVariableLookupNS	(xmlXPathContextPtr ctxt,
+						 const xmlChar *name,
+						 const xmlChar *ns_uri);
+void		   xmlXPathRegisteredVariablesCleanup(xmlXPathContextPtr ctxt);
+
+/**
+ * Utilities to extend XPath
+ */
+xmlXPathParserContextPtr
+		  xmlXPathNewParserContext	(const xmlChar *str,
+			  			 xmlXPathContextPtr ctxt);
+void		  xmlXPathFreeParserContext	(xmlXPathParserContextPtr ctxt);
+
+/* TODO: remap to xmlXPathValuePop and Push */
+xmlXPathObjectPtr valuePop			(xmlXPathParserContextPtr ctxt);
+int		  valuePush			(xmlXPathParserContextPtr ctxt,
+					 	xmlXPathObjectPtr value);
+
+xmlXPathObjectPtr xmlXPathNewString		(const xmlChar *val);
+xmlXPathObjectPtr xmlXPathNewCString		(const char *val);
+xmlXPathObjectPtr xmlXPathNewFloat		(double val);
+xmlXPathObjectPtr xmlXPathNewBoolean		(int val);
+xmlXPathObjectPtr xmlXPathNewNodeSet		(xmlNodePtr val);
+xmlXPathObjectPtr xmlXPathNewValueTree		(xmlNodePtr val);
+void		  xmlXPathNodeSetAdd		(xmlNodeSetPtr cur,
+						 xmlNodePtr val);
+
+
+void		  xmlXPathIdFunction		(xmlXPathParserContextPtr ctxt,
+					 	int nargs);
+void		  xmlXPathRoot			(xmlXPathParserContextPtr ctxt);
+void		  xmlXPathEvalExpr		(xmlXPathParserContextPtr ctxt);
+xmlChar *	  xmlXPathParseName		(xmlXPathParserContextPtr ctxt);
+xmlChar *	  xmlXPathParseNCName		(xmlXPathParserContextPtr ctxt);
+
+/*
+ * Debug
+ */
+#ifdef LIBXML_DEBUG_ENABLED
+double xmlXPathStringEvalNumber(const xmlChar *str);
+void xmlXPathDebugDumpObject(FILE *output, xmlXPathObjectPtr cur, int depth);
+#endif
+/*
+ * Existing functions
+ */
+
+int xmlXPathEvaluatePredicateResult(xmlXPathParserContextPtr ctxt, 
+                                    xmlXPathObjectPtr res);
+void xmlXPathInit(void);
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathRegisterAllFunctions(xmlXPathContextPtr ctxt);
+xmlNodeSetPtr xmlXPathNodeSetCreate(xmlNodePtr val);
+void xmlXPathNodeSetAdd(xmlNodeSetPtr cur, xmlNodePtr val);
+xmlNodeSetPtr xmlXPathNodeSetMerge(xmlNodeSetPtr val1, xmlNodeSetPtr val2);
+void xmlXPathNodeSetDel(xmlNodeSetPtr cur, xmlNodePtr val);
+void xmlXPathNodeSetRemove(xmlNodeSetPtr cur, int val);
+void xmlXPathFreeNodeSet(xmlNodeSetPtr obj);
+xmlXPathObjectPtr xmlXPathNewNodeSet(xmlNodePtr val);
+xmlXPathObjectPtr xmlXPathNewNodeSetList(xmlNodeSetPtr val);
+xmlXPathObjectPtr xmlXPathWrapNodeSet(xmlNodeSetPtr val);
+void xmlXPathFreeNodeSetList(xmlXPathObjectPtr obj);
+
+
+xmlXPathObjectPtr xmlXPathNewFloat(double val);
+xmlXPathObjectPtr xmlXPathNewBoolean(int val);
+xmlXPathObjectPtr xmlXPathNewString(const xmlChar *val);
+xmlXPathObjectPtr xmlXPathNewCString(const char *val);
+void xmlXPathFreeObject(xmlXPathObjectPtr obj);
+xmlXPathContextPtr xmlXPathNewContext(xmlDocPtr doc);
+void xmlXPathFreeContext(xmlXPathContextPtr ctxt);
+
+int xmlXPathEqualValues(xmlXPathParserContextPtr ctxt);
+int xmlXPathCompareValues(xmlXPathParserContextPtr ctxt, int inf, int strict);
+void xmlXPathValueFlipSign(xmlXPathParserContextPtr ctxt);
+void xmlXPathAddValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathSubValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathMultValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathDivValues(xmlXPathParserContextPtr ctxt);
+void xmlXPathModValues(xmlXPathParserContextPtr ctxt);
+
+
+/*
+ * Some of the axis navigation routines
+ */
+xmlNodePtr xmlXPathNextPreceding(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+xmlNodePtr xmlXPathNextAncestor(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+xmlNodePtr xmlXPathNextPrecedingSibling(xmlXPathParserContextPtr ctxt, xmlNodePtr cur);
+/*
+ * The official core of XPath functions
+ */
+void xmlXPathRoot(xmlXPathParserContextPtr ctxt);
+void xmlXPathLastFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathPositionFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathCountFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathIdFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathLocalNameFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNamespaceURIFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathStringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathStringLengthFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathConcatFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathContainsFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathStartsWithFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSubstringFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSubstringBeforeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSubstringAfterFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNormalizeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathTranslateFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNotFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathTrueFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathFalseFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathLangFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathNumberFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathSumFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathFloorFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathCeilingFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathRoundFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPathBooleanFunction(xmlXPathParserContextPtr ctxt, int nargs);
+#ifdef __cplusplus
+}
+#endif
+#endif /* ! __XML_XPATH_INTERNALS_H__ */
diff --git a/xpointer.c b/xpointer.c
new file mode 100644
index 0000000..7d2da1b
--- /dev/null
+++ b/xpointer.c
@@ -0,0 +1,2903 @@
+/*
+ * xpointer.c : Code to handle XML Pointer
+ *
+ * World Wide Web Consortium Working Draft 03-March-1998 
+ * http://www.w3.org/TR/2000/CR-xptr-20000607
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifdef WIN32
+#include "win32config.h"
+#else
+#include "config.h"
+#endif
+
+/**
+ * TODO: better handling of error cases, the full expression should
+ *       be parsed beforehand instead of a progressive evaluation
+ * TODO: Access into entities references are not supported now ...
+ *       need a start to be able to pop out of entities refs since
+ *       parent is the endity declaration, not the ref.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <libxml/xpointer.h>
+#include <libxml/xmlmemory.h>
+#include <libxml/parserInternals.h>
+#include <libxml/uri.h>
+#include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
+#ifdef LIBXML_DEBUG_ENABLED
+#include <libxml/debugXML.h>
+#endif
+#include <libxml/xmlerror.h>
+
+#ifdef LIBXML_XPTR_ENABLED
+
+/* Add support of the xmlns() xpointer scheme to initialize the namespaces */
+#define XPTR_XMLNS_SCHEME
+
+/* #define DEBUG_RANGES */
+
+#define TODO 								\
+    xmlGenericError(xmlGenericErrorContext,				\
+	    "Unimplemented block at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+#define STRANGE 							\
+    xmlGenericError(xmlGenericErrorContext,				\
+	    "Internal error at %s:%d\n",				\
+            __FILE__, __LINE__);
+
+/************************************************************************
+ *									*
+ *		A few helper functions for child sequences		*
+ *									*
+ ************************************************************************/
+
+xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
+/**
+ * xmlXPtrGetArity:
+ * @cur:  the node
+ *
+ * Returns the number of child for an element, -1 in case of error
+ */
+int
+xmlXPtrGetArity(xmlNodePtr cur) {
+    int i;
+    if (cur == NULL) 
+	return(-1);
+    cur = cur->children;
+    for (i = 0;cur != NULL;cur = cur->next) {
+	if ((cur->type == XML_ELEMENT_NODE) ||
+	    (cur->type == XML_DOCUMENT_NODE) ||
+	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	    i++;
+	}
+    }
+    return(i);
+}
+
+/**
+ * xmlXPtrGetIndex:
+ * @cur:  the node
+ *
+ * Returns the index of the node in its parent children list, -1
+ *         in case of error
+ */
+int
+xmlXPtrGetIndex(xmlNodePtr cur) {
+    int i;
+    if (cur == NULL) 
+	return(-1);
+    for (i = 1;cur != NULL;cur = cur->prev) {
+	if ((cur->type == XML_ELEMENT_NODE) ||
+	    (cur->type == XML_DOCUMENT_NODE) ||
+	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	    i++;
+	}
+    }
+    return(i);
+}
+
+/**
+ * xmlXPtrGetNthChild:
+ * @cur:  the node
+ * @no:  the child number
+ *
+ * Returns the @no'th element child of @cur or NULL
+ */
+xmlNodePtr
+xmlXPtrGetNthChild(xmlNodePtr cur, int no) {
+    int i;
+    if (cur == NULL) 
+	return(cur);
+    cur = cur->children;
+    for (i = 0;i <= no;cur = cur->next) {
+	if (cur == NULL) 
+	    return(cur);
+	if ((cur->type == XML_ELEMENT_NODE) ||
+	    (cur->type == XML_DOCUMENT_NODE) ||
+	    (cur->type == XML_HTML_DOCUMENT_NODE)) {
+	    i++;
+	    if (i == no)
+		break;
+	}
+    }
+    return(cur);
+}
+
+/************************************************************************
+ *									*
+ *		Handling of XPointer specific types			*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPtrCmpPoints:
+ * @node1:  the first node
+ * @index1:  the first index
+ * @node2:  the second node
+ * @index2:  the second index
+ *
+ * Compare two points w.r.t document order
+ *
+ * Returns -2 in case of error 1 if first point < second point, 0 if
+ *         that's the same point, -1 otherwise
+ */
+int
+xmlXPtrCmpPoints(xmlNodePtr node1, int index1, xmlNodePtr node2, int index2) {
+    if ((node1 == NULL) || (node2 == NULL))
+	return(-2);
+    /*
+     * a couple of optimizations which will avoid computations in most cases
+     */
+    if (node1 == node2) {
+	if (index1 < index2)
+	    return(1);
+	if (index1 > index2)
+	    return(-1);
+	return(0);
+    }
+    return(xmlXPathCmpNodes(node1, node2));
+}
+
+/**
+ * xmlXPtrNewPoint:
+ * @node:  the xmlNodePtr
+ * @index:  the index within the node
+ *
+ * Create a new xmlXPathObjectPtr of type point
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewPoint(xmlNodePtr node, int index) {
+    xmlXPathObjectPtr ret;
+
+    if (node == NULL)
+	return(NULL);
+    if (index < 0)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewPoint: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_POINT;
+    ret->user = (void *) node;
+    ret->index = index;
+    return(ret);
+}
+
+/**
+ * xmlXPtrRangeCheckOrder:
+ * @range:  an object range
+ *
+ * Make sure the points in the range are in the right order
+ */
+void
+xmlXPtrRangeCheckOrder(xmlXPathObjectPtr range) {
+    int tmp;
+    xmlNodePtr tmp2;
+    if (range == NULL)
+	return;
+    if (range->type != XPATH_RANGE)
+	return;
+    if (range->user2 == NULL)
+	return;
+    tmp = xmlXPtrCmpPoints(range->user, range->index,
+	                     range->user2, range->index2);
+    if (tmp == -1) {
+	tmp2 = range->user;
+	range->user = range->user2;
+	range->user2 = tmp2;
+	tmp = range->index;
+	range->index = range->index2;
+	range->index2 = tmp;
+    }
+}
+
+/**
+ * xmlXPtrRangesEqual:
+ * @range1:  the first range
+ * @range2:  the second range
+ *
+ * Compare two ranges
+ *
+ * Return 1 if equal, 0 otherwise
+ */
+int
+xmlXPtrRangesEqual(xmlXPathObjectPtr range1, xmlXPathObjectPtr range2) {
+    if (range1 == range2)
+	return(1);
+    if ((range1 == NULL) || (range2 == NULL))
+	return(0);
+    if (range1->type != range2->type)
+	return(0);
+    if (range1->type != XPATH_RANGE)
+	return(0);
+    if (range1->user != range2->user)
+	return(0);
+    if (range1->index != range2->index)
+	return(0);
+    if (range1->user2 != range2->user2)
+	return(0);
+    if (range1->index2 != range2->index2)
+	return(0);
+    return(1);
+}
+
+/**
+ * xmlXPtrNewRange:
+ * @start:  the starting node
+ * @startindex:  the start index
+ * @end:  the ending point
+ * @endindex:  the ending index
+ *
+ * Create a new xmlXPathObjectPtr of type range
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRange(xmlNodePtr start, int startindex,
+	        xmlNodePtr end, int endindex) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+    if (startindex < 0)
+	return(NULL);
+    if (endindex < 0)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangePoints: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start;
+    ret->index = startindex;
+    ret->user2 = end;
+    ret->index2 = endindex;
+    xmlXPtrRangeCheckOrder(ret);
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewRangePoints:
+ * @start:  the starting point
+ * @end:  the ending point
+ *
+ * Create a new xmlXPathObjectPtr of type range using 2 Points
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRangePoints(xmlXPathObjectPtr start, xmlXPathObjectPtr end) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+    if (start->type != XPATH_POINT)
+	return(NULL);
+    if (end->type != XPATH_POINT)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangePoints: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start->user;
+    ret->index = start->index;
+    ret->user2 = end->user;
+    ret->index2 = end->index;
+    xmlXPtrRangeCheckOrder(ret);
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewRangePointNode:
+ * @start:  the starting point
+ * @end:  the ending node
+ *
+ * Create a new xmlXPathObjectPtr of type range from a point to a node
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRangePointNode(xmlXPathObjectPtr start, xmlNodePtr end) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+    if (start->type != XPATH_POINT)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangePointNode: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start->user;
+    ret->index = start->index;
+    ret->user2 = end;
+    ret->index2 = -1;
+    xmlXPtrRangeCheckOrder(ret);
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewRangeNodePoint:
+ * @start:  the starting node
+ * @end:  the ending point
+ *
+ * Create a new xmlXPathObjectPtr of type range from a node to a point
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRangeNodePoint(xmlNodePtr start, xmlXPathObjectPtr end) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+    if (start->type != XPATH_POINT)
+	return(NULL);
+    if (end->type != XPATH_POINT)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangeNodePoint: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start;
+    ret->index = -1;
+    ret->user2 = end->user;
+    ret->index2 = end->index;
+    xmlXPtrRangeCheckOrder(ret);
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewRangeNodes:
+ * @start:  the starting node
+ * @end:  the ending node
+ *
+ * Create a new xmlXPathObjectPtr of type range using 2 nodes
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRangeNodes(xmlNodePtr start, xmlNodePtr end) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangeNodes: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start;
+    ret->index = -1;
+    ret->user2 = end;
+    ret->index2 = -1;
+    xmlXPtrRangeCheckOrder(ret);
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewCollapsedRange:
+ * @start:  the starting and ending node
+ *
+ * Create a new xmlXPathObjectPtr of type range using a single nodes
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewCollapsedRange(xmlNodePtr start) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangeNodes: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start;
+    ret->index = -1;
+    ret->user2 = NULL;
+    ret->index2 = -1;
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewRangeNodeObject:
+ * @start:  the starting node
+ * @end:  the ending object
+ *
+ * Create a new xmlXPathObjectPtr of type range from a not to an object
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewRangeNodeObject(xmlNodePtr start, xmlXPathObjectPtr end) {
+    xmlXPathObjectPtr ret;
+
+    if (start == NULL)
+	return(NULL);
+    if (end == NULL)
+	return(NULL);
+    switch (end->type) {
+	case XPATH_POINT:
+	    break;
+	case XPATH_NODESET:
+	    /*
+	     * Empty set ... 
+	     */
+	    if (end->nodesetval->nodeNr <= 0)
+		return(NULL);
+	    break;
+	default:
+	    TODO
+	    return(NULL);
+    }
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewRangeNodeObject: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_RANGE;
+    ret->user = start;
+    ret->index = -1;
+    switch (end->type) {
+	case XPATH_POINT:
+	    ret->user2 = end->user;
+	    ret->index2 = end->index;
+	case XPATH_NODESET: {
+	    ret->user2 = end->nodesetval->nodeTab[end->nodesetval->nodeNr - 1];
+	    ret->index2 = -1;
+	    break;
+	}
+	default:
+	    STRANGE
+	    return(NULL);
+    }
+    xmlXPtrRangeCheckOrder(ret);
+    return(ret);
+}
+
+#define XML_RANGESET_DEFAULT	10
+
+/**
+ * xmlXPtrLocationSetCreate:
+ * @val:  an initial xmlXPathObjectPtr, or NULL
+ *
+ * Create a new xmlLocationSetPtr of type double and of value @val
+ *
+ * Returns the newly created object.
+ */
+xmlLocationSetPtr
+xmlXPtrLocationSetCreate(xmlXPathObjectPtr val) {
+    xmlLocationSetPtr ret;
+
+    ret = (xmlLocationSetPtr) xmlMalloc(sizeof(xmlLocationSet));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrLocationSetCreate: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlLocationSet));
+    if (val != NULL) {
+        ret->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
+					     sizeof(xmlXPathObjectPtr));
+	if (ret->locTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPtrLocationSetCreate: out of memory\n");
+	    return(NULL);
+	}
+	memset(ret->locTab, 0 ,
+	       XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
+        ret->locMax = XML_RANGESET_DEFAULT;
+	ret->locTab[ret->locNr++] = val;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPtrLocationSetAdd:
+ * @cur:  the initial range set
+ * @val:  a new xmlXPathObjectPtr
+ *
+ * add a new xmlXPathObjectPtr ot an existing LocationSet
+ * If the location already exist in the set @val is freed.
+ */
+void
+xmlXPtrLocationSetAdd(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
+    int i;
+
+    if (val == NULL) return;
+
+    /*
+     * check against doublons
+     */
+    for (i = 0;i < cur->locNr;i++) {
+	if (xmlXPtrRangesEqual(cur->locTab[i], val)) {
+	    xmlXPathFreeObject(val);
+	    return;
+	}
+    }
+
+    /*
+     * grow the locTab if needed
+     */
+    if (cur->locMax == 0) {
+        cur->locTab = (xmlXPathObjectPtr *) xmlMalloc(XML_RANGESET_DEFAULT *
+					     sizeof(xmlXPathObjectPtr));
+	if (cur->locTab == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPtrLocationSetAdd: out of memory\n");
+	    return;
+	}
+	memset(cur->locTab, 0 ,
+	       XML_RANGESET_DEFAULT * (size_t) sizeof(xmlXPathObjectPtr));
+        cur->locMax = XML_RANGESET_DEFAULT;
+    } else if (cur->locNr == cur->locMax) {
+        xmlXPathObjectPtr *temp;
+
+        cur->locMax *= 2;
+	temp = (xmlXPathObjectPtr *) xmlRealloc(cur->locTab, cur->locMax *
+				      sizeof(xmlXPathObjectPtr));
+	if (temp == NULL) {
+	    xmlGenericError(xmlGenericErrorContext,
+		    "xmlXPtrLocationSetAdd: out of memory\n");
+	    return;
+	}
+	cur->locTab = temp;
+    }
+    cur->locTab[cur->locNr++] = val;
+}
+
+/**
+ * xmlXPtrLocationSetMerge:
+ * @val1:  the first LocationSet
+ * @val2:  the second LocationSet
+ *
+ * Merges two rangesets, all ranges from @val2 are added to @val1
+ *
+ * Returns val1 once extended or NULL in case of error.
+ */
+xmlLocationSetPtr
+xmlXPtrLocationSetMerge(xmlLocationSetPtr val1, xmlLocationSetPtr val2) {
+    int i;
+
+    if (val1 == NULL) return(NULL);
+    if (val2 == NULL) return(val1);
+
+    /*
+     * !!!!! this can be optimized a lot, knowing that both
+     *       val1 and val2 already have unicity of their values.
+     */
+
+    for (i = 0;i < val2->locNr;i++)
+        xmlXPtrLocationSetAdd(val1, val2->locTab[i]);
+
+    return(val1);
+}
+
+/**
+ * xmlXPtrLocationSetDel:
+ * @cur:  the initial range set
+ * @val:  an xmlXPathObjectPtr
+ *
+ * Removes an xmlXPathObjectPtr from an existing LocationSet
+ */
+void
+xmlXPtrLocationSetDel(xmlLocationSetPtr cur, xmlXPathObjectPtr val) {
+    int i;
+
+    if (cur == NULL) return;
+    if (val == NULL) return;
+
+    /*
+     * check against doublons
+     */
+    for (i = 0;i < cur->locNr;i++)
+        if (cur->locTab[i] == val) break;
+
+    if (i >= cur->locNr) {
+#ifdef DEBUG
+        xmlGenericError(xmlGenericErrorContext, 
+	        "xmlXPtrLocationSetDel: Range %s wasn't found in RangeList\n",
+		val->name);
+#endif
+        return;
+    }
+    cur->locNr--;
+    for (;i < cur->locNr;i++)
+        cur->locTab[i] = cur->locTab[i + 1];
+    cur->locTab[cur->locNr] = NULL;
+}
+
+/**
+ * xmlXPtrLocationSetRemove:
+ * @cur:  the initial range set
+ * @val:  the index to remove
+ *
+ * Removes an entry from an existing LocationSet list.
+ */
+void
+xmlXPtrLocationSetRemove(xmlLocationSetPtr cur, int val) {
+    if (cur == NULL) return;
+    if (val >= cur->locNr) return;
+    cur->locNr--;
+    for (;val < cur->locNr;val++)
+        cur->locTab[val] = cur->locTab[val + 1];
+    cur->locTab[cur->locNr] = NULL;
+}
+
+/**
+ * xmlXPtrFreeLocationSet:
+ * @obj:  the xmlLocationSetPtr to free
+ *
+ * Free the LocationSet compound (not the actual ranges !).
+ */
+void
+xmlXPtrFreeLocationSet(xmlLocationSetPtr obj) {
+    int i;
+
+    if (obj == NULL) return;
+    if (obj->locTab != NULL) {
+	for (i = 0;i < obj->locNr; i++) {
+            xmlXPathFreeObject(obj->locTab[i]);
+	}
+#ifdef DEBUG
+	memset(obj->locTab, 0xB ,
+	       (size_t) sizeof(xmlXPathObjectPtr) * obj->locMax);
+#endif
+	xmlFree(obj->locTab);
+    }
+#ifdef DEBUG
+    memset(obj, 0xB , (size_t) sizeof(xmlLocationSet));
+#endif
+    xmlFree(obj);
+}
+
+/**
+ * xmlXPtrNewLocationSetNodes:
+ * @start:  the start NodePtr value
+ * @end:  the end NodePtr value or NULL
+ *
+ * Create a new xmlXPathObjectPtr of type LocationSet and initialize
+ * it with the single range made of the two nodes @start and @end
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewLocationSetNodes(xmlNodePtr start, xmlNodePtr end) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewLocationSetNodes: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_LOCATIONSET;
+    if (end == NULL)
+	ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewCollapsedRange(start));
+    else
+	ret->user = xmlXPtrLocationSetCreate(xmlXPtrNewRangeNodes(start,end));
+    return(ret);
+}
+
+/**
+ * xmlXPtrNewLocationSetNodeSet:
+ * @set:  a node set
+ *
+ * Create a new xmlXPathObjectPtr of type LocationSet and initialize
+ * it with all the nodes from @set
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrNewLocationSetNodeSet(xmlNodeSetPtr set) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrNewLocationSetNodes: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_LOCATIONSET;
+    if (set != NULL) {
+	int i;
+	xmlLocationSetPtr newset;
+
+	newset = xmlXPtrLocationSetCreate(NULL);
+	if (newset == NULL)
+	    return(ret);
+
+	for (i = 0;i < set->nodeNr;i++)
+	    xmlXPtrLocationSetAdd(newset,
+		        xmlXPtrNewCollapsedRange(set->nodeTab[i]));
+
+	ret->user = (void *) newset;
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPtrWrapLocationSet:
+ * @val:  the LocationSet value
+ *
+ * Wrap the LocationSet @val in a new xmlXPathObjectPtr
+ *
+ * Returns the newly created object.
+ */
+xmlXPathObjectPtr
+xmlXPtrWrapLocationSet(xmlLocationSetPtr val) {
+    xmlXPathObjectPtr ret;
+
+    ret = (xmlXPathObjectPtr) xmlMalloc(sizeof(xmlXPathObject));
+    if (ret == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrWrapLocationSet: out of memory\n");
+	return(NULL);
+    }
+    memset(ret, 0 , (size_t) sizeof(xmlXPathObject));
+    ret->type = XPATH_LOCATIONSET;
+    ret->user = (void *) val;
+    return(ret);
+}
+
+/************************************************************************
+ *									*
+ *			The parser					*
+ *									*
+ ************************************************************************/
+
+/*
+ * Macros for accessing the content. Those should be used only by the parser,
+ * and not exported.
+ *
+ * Dirty macros, i.e. one need to make assumption on the context to use them
+ *
+ *   CUR_PTR return the current pointer to the xmlChar to be parsed.
+ *   CUR     returns the current xmlChar value, i.e. a 8 bit value
+ *           in ISO-Latin or UTF-8.
+ *           This should be used internally by the parser
+ *           only to compare to ASCII values otherwise it would break when
+ *           running with UTF-8 encoding.
+ *   NXT(n)  returns the n'th next xmlChar. Same as CUR is should be used only
+ *           to compare on ASCII based substring.
+ *   SKIP(n) Skip n xmlChar, and must also be used only to skip ASCII defined
+ *           strings within the parser.
+ *   CURRENT Returns the current char value, with the full decoding of
+ *           UTF-8 if we are using this mode. It returns an int.
+ *   NEXT    Skip to the next character, this does the proper decoding
+ *           in UTF-8 mode. It also pop-up unfinished entities on the fly.
+ *           It returns the pointer to the current xmlChar.
+ */
+
+#define CUR (*ctxt->cur)
+#define SKIP(val) ctxt->cur += (val)
+#define NXT(val) ctxt->cur[(val)]
+#define CUR_PTR ctxt->cur
+
+#define SKIP_BLANKS 							\
+    while (IS_BLANK(*(ctxt->cur))) NEXT
+
+#define CURRENT (*ctxt->cur)
+#define NEXT ((*ctxt->cur) ?  ctxt->cur++: ctxt->cur)
+
+/*
+ * xmlXPtrGetChildNo:
+ * @ctxt:  the XPointer Parser context
+ * @index:  the child number
+ *
+ * Move the current node of the nodeset on the stack to the
+ * given child if found
+ */
+void
+xmlXPtrGetChildNo(xmlXPathParserContextPtr ctxt, int index) {
+    xmlNodePtr cur = NULL;
+    xmlXPathObjectPtr obj;
+    xmlNodeSetPtr oldset;
+
+    CHECK_TYPE(XPATH_NODESET);
+    obj = valuePop(ctxt);
+    oldset = obj->nodesetval;
+    if ((index <= 0) || (oldset == NULL) || (oldset->nodeNr != 1)) {
+	xmlXPathFreeObject(obj);
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+	return;
+    }
+    cur = xmlXPtrGetNthChild(oldset->nodeTab[0], index);
+    if (cur == NULL) {
+	xmlXPathFreeObject(obj);
+	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
+	return;
+    }
+    oldset->nodeTab[0] = cur;
+    valuePush(ctxt, obj);
+}
+
+/**
+ * xmlXPtrEvalXPtrPart:
+ * @ctxt:  the XPointer Parser context
+ * @name:  the preparsed Scheme for the XPtrPart
+ * 
+ * XPtrPart ::= 'xpointer' '(' XPtrExpr ')'
+ *            | Scheme '(' SchemeSpecificExpr ')'
+ *
+ * Scheme   ::=  NCName - 'xpointer' [VC: Non-XPointer schemes]
+ *
+ * SchemeSpecificExpr ::= StringWithBalancedParens
+ *
+ * StringWithBalancedParens ::=  
+ *              [^()]* ('(' StringWithBalancedParens ')' [^()]*)*
+ *              [VC: Parenthesis escaping]
+ *
+ * XPtrExpr ::= Expr [VC: Parenthesis escaping]
+ *
+ * VC: Parenthesis escaping:
+ *   The end of an XPointer part is signaled by the right parenthesis ")"
+ *   character that is balanced with the left parenthesis "(" character
+ *   that began the part. Any unbalanced parenthesis character inside the
+ *   expression, even within literals, must be escaped with a circumflex (^)
+ *   character preceding it. If the expression contains any literal
+ *   occurrences of the circumflex, each must be escaped with an additional
+ *   circumflex (that is, ^^). If the unescaped parentheses in the expression
+ *   are not balanced, a syntax error results.
+ *
+ * Parse and evaluate an XPtrPart. Basically it generates the unescaped
+ * string and if the scheme is 'xpointer' it will call the XPath interprter.
+ * 
+ * TODO: there is no new scheme registration mechanism
+ */
+
+void
+xmlXPtrEvalXPtrPart(xmlXPathParserContextPtr ctxt, xmlChar *name) {
+    xmlChar *buffer, *cur;
+    int len;
+    int level;
+
+    if (name == NULL)
+    name = xmlXPathParseName(ctxt);
+    if (name == NULL)
+	XP_ERROR(XPATH_EXPR_ERROR);
+
+    if (CUR != '(')
+	XP_ERROR(XPATH_EXPR_ERROR);
+    NEXT;
+    level = 1;
+
+    len = xmlStrlen(ctxt->cur);
+    len++;
+    buffer = (xmlChar *) xmlMalloc(len * sizeof (xmlChar));
+    if (buffer == NULL) {
+        xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrEvalXPtrPart: out of memory\n");
+	return;
+    }
+
+    cur = buffer;
+    while (CUR != 0) {
+	if (CUR == ')') {
+	    level--;
+	    if (level == 0) {
+		NEXT;
+		break;
+	    }
+	    *cur++ = CUR;
+	} else if (CUR == '(') {
+	    level++;
+	    *cur++ = CUR;
+	} else if (CUR == '^') {
+	    NEXT;
+	    if ((CUR == ')') || (CUR == '(') || (CUR == '^')) {
+		*cur++ = CUR;
+	    } else {
+		*cur++ = '^';
+		*cur++ = CUR;
+	    }
+	} else {
+	    *cur++ = CUR;
+	}
+	NEXT;
+    }
+    *cur = 0;
+
+    if ((level != 0) && (CUR == 0)) {
+	xmlFree(buffer);
+	XP_ERROR(XPTR_SYNTAX_ERROR);
+    }
+
+    if (xmlStrEqual(name, (xmlChar *) "xpointer")) {
+	const xmlChar *left = CUR_PTR;
+
+	CUR_PTR = buffer;
+	xmlXPathRoot(ctxt);
+	xmlXPathEvalExpr(ctxt);
+	CUR_PTR=left;
+#ifdef XPTR_XMLNS_SCHEME
+    } else if (xmlStrEqual(name, (xmlChar *) "xmlns")) {
+	const xmlChar *left = CUR_PTR;
+	xmlChar *prefix;
+	xmlChar *URI;
+	xmlURIPtr value;
+
+	CUR_PTR = buffer;
+        prefix = xmlXPathParseNCName(ctxt);
+	if (prefix == NULL) {
+	    xmlFree(buffer);
+	    xmlFree(name);
+	    XP_ERROR(XPTR_SYNTAX_ERROR);
+	}
+	SKIP_BLANKS;
+	if (CUR != '=') {
+	    xmlFree(prefix);
+	    xmlFree(buffer);
+	    xmlFree(name);
+	    XP_ERROR(XPTR_SYNTAX_ERROR);
+	}
+	NEXT;
+	SKIP_BLANKS;
+	/* @@ check escaping in the XPointer WD */
+
+	value = xmlParseURI((const char *)ctxt->cur);
+	if (value == NULL) {
+	    xmlFree(prefix);
+	    xmlFree(buffer);
+	    xmlFree(name);
+	    XP_ERROR(XPTR_SYNTAX_ERROR);
+	}
+	URI = xmlSaveUri(value);
+	xmlFreeURI(value);
+	if (URI == NULL) {
+	    xmlFree(prefix);
+	    xmlFree(buffer);
+	    xmlFree(name);
+	    XP_ERROR(XPATH_MEMORY_ERROR);
+	}
+	
+	xmlXPathRegisterNs(ctxt->context, prefix, URI);
+	CUR_PTR = left;
+#endif /* XPTR_XMLNS_SCHEME */
+    } else {
+        xmlGenericError(xmlGenericErrorContext,
+		"unsupported scheme '%s'\n", name);
+    }
+    xmlFree(buffer);
+    xmlFree(name);
+}
+
+/**
+ * xmlXPtrEvalFullXPtr:
+ * @ctxt:  the XPointer Parser context
+ * @name:  the preparsed Scheme for the first XPtrPart
+ *
+ * FullXPtr ::= XPtrPart (S? XPtrPart)*
+ *
+ * As the specs says:
+ * -----------
+ * When multiple XPtrParts are provided, they must be evaluated in
+ * left-to-right order. If evaluation of one part fails, the nexti
+ * is evaluated. The following conditions cause XPointer part failure:
+ *
+ * - An unknown scheme
+ * - A scheme that does not locate any sub-resource present in the resource
+ * - A scheme that is not applicable to the media type of the resource
+ *
+ * The XPointer application must consume a failed XPointer part and
+ * attempt to evaluate the next one, if any. The result of the first
+ * XPointer part whose evaluation succeeds is taken to be the fragment
+ * located by the XPointer as a whole. If all the parts fail, the result
+ * for the XPointer as a whole is a sub-resource error.
+ * -----------
+ *
+ * Parse and evaluate a Full XPtr i.e. possibly a cascade of XPath based
+ * expressions or other shemes.
+ */
+void
+xmlXPtrEvalFullXPtr(xmlXPathParserContextPtr ctxt, xmlChar *name) {
+    if (name == NULL)
+    name = xmlXPathParseName(ctxt);
+    if (name == NULL)
+	XP_ERROR(XPATH_EXPR_ERROR);
+    while (name != NULL) {
+	xmlXPtrEvalXPtrPart(ctxt, name);
+
+	/* in case of syntax error, break here */
+	if (ctxt->error != XPATH_EXPRESSION_OK)
+	    return;
+
+	/*
+	 * If the returned value is a non-empty nodeset
+	 * or location set, return here.
+	 */
+	if (ctxt->value != NULL) {
+	    xmlXPathObjectPtr obj = ctxt->value;
+
+	    switch (obj->type) {
+		case XPATH_LOCATIONSET: {
+		    xmlLocationSetPtr loc = ctxt->value->user;
+		    if ((loc != NULL) && (loc->locNr > 0))
+			return;
+		    break;
+		}
+		case XPATH_NODESET: {
+		    xmlNodeSetPtr loc = ctxt->value->nodesetval;
+		    if ((loc != NULL) && (loc->nodeNr > 0))
+			return;
+		    break;
+		}
+		default:
+		    break;
+	    }
+
+	    /*
+	     * Evaluating to improper values is equivalent to
+	     * a sub-resource error, clean-up the stack
+	     */
+	    do {
+		obj = valuePop(ctxt);
+		if (obj != NULL) {
+		    xmlXPathFreeObject(obj);
+		}
+	    } while (obj != NULL);
+	}
+
+	/*
+	 * Is there another XPoointer part.
+	 */
+	SKIP_BLANKS;
+	name = xmlXPathParseName(ctxt);
+    }
+}
+
+/**
+ * xmlXPtrEvalChildSeq:
+ * @ctxt:  the XPointer Parser context
+ * @name:  a possible ID name of the child sequence
+ *
+ *  ChildSeq ::= '/1' ('/' [0-9]*)*
+ *             | Name ('/' [0-9]*)+
+ *
+ * Parse and evaluate a Child Sequence. This routine also handle the
+ * case of a Bare Name used to get a document ID.
+ */
+void
+xmlXPtrEvalChildSeq(xmlXPathParserContextPtr ctxt, xmlChar *name) {
+    /*
+     * XPointer don't allow by syntax to adress in mutirooted trees
+     * this might prove useful in some cases, warn about it.
+     */
+    if ((name == NULL) && (CUR == '/') && (NXT(1) != '1')) {
+	xmlGenericError(xmlGenericErrorContext,
+		"warning: ChildSeq not starting by /1\n");
+    }
+
+    if (name != NULL) {
+	valuePush(ctxt, xmlXPathNewString(name));
+	xmlFree(name);
+	xmlXPathIdFunction(ctxt, 1);
+	CHECK_ERROR;
+    }
+
+    while (CUR == '/') {
+	int child = 0;
+	NEXT;
+        
+	while ((CUR >= '0') && (CUR <= '9')) {
+	    child = child * 10 + (CUR - '0');
+	    NEXT;
+	}
+	xmlXPtrGetChildNo(ctxt, child);
+    }
+}
+
+
+/**
+ * xmlXPtrEvalXPointer:
+ * @ctxt:  the XPointer Parser context
+ *
+ *  XPointer ::= Name
+ *             | ChildSeq
+ *             | FullXPtr
+ *
+ * Parse and evaluate an XPointer
+ */
+void
+xmlXPtrEvalXPointer(xmlXPathParserContextPtr ctxt) {
+    SKIP_BLANKS;
+    if (CUR == '/') {
+	xmlXPathRoot(ctxt);
+        xmlXPtrEvalChildSeq(ctxt, NULL);
+    } else {
+	xmlChar *name;
+
+	name = xmlXPathParseName(ctxt);
+	if (name == NULL)
+	    XP_ERROR(XPATH_EXPR_ERROR);
+	if (CUR == '(') {
+	    xmlXPtrEvalFullXPtr(ctxt, name);
+	    /* Short evaluation */
+	    return;
+	} else {
+	    /* this handle both Bare Names and Child Sequences */
+	    xmlXPtrEvalChildSeq(ctxt, name);
+	}
+    }
+    SKIP_BLANKS;
+    if (CUR != 0)
+	XP_ERROR(XPATH_EXPR_ERROR);
+}
+
+
+/************************************************************************
+ *									*
+ *			General routines				*
+ *									*
+ ************************************************************************/
+
+void xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs);
+void xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs);
+
+/**
+ * xmlXPtrNewContext:
+ * @doc:  the XML document
+ * @here:  the node that directly contains the XPointer being evaluated or NULL
+ * @origin:  the element from which a user or program initiated traversal of
+ *           the link, or NULL.
+ *
+ * Create a new XPointer context
+ *
+ * Returns the xmlXPathContext just allocated.
+ */
+xmlXPathContextPtr
+xmlXPtrNewContext(xmlDocPtr doc, xmlNodePtr here, xmlNodePtr origin) {
+    xmlXPathContextPtr ret;
+
+    ret = xmlXPathNewContext(doc);
+    if (ret == NULL)
+	return(ret);
+    ret->xptr = 1;
+    ret->here = here;
+    ret->origin = origin;
+
+    xmlXPathRegisterFunc(ret, (xmlChar *)"range-to",
+	                 xmlXPtrRangeToFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"range",
+	                 xmlXPtrRangeFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"range-inside",
+	                 xmlXPtrRangeInsideFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"string-range",
+	                 xmlXPtrStringRangeFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"start-point",
+	                 xmlXPtrStartPointFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"end-point",
+	                 xmlXPtrEndPointFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)"here",
+	                 xmlXPtrHereFunction);
+    xmlXPathRegisterFunc(ret, (xmlChar *)" origin",
+	                 xmlXPtrOriginFunction);
+
+    return(ret);
+}
+
+/**
+ * xmlXPtrEval:
+ * @str:  the XPointer expression
+ * @ctx:  the XPointer context
+ *
+ * Evaluate the XPath Location Path in the given context.
+ *
+ * Returns the xmlXPathObjectPtr resulting from the eveluation or NULL.
+ *         the caller has to free the object.
+ */
+xmlXPathObjectPtr
+xmlXPtrEval(const xmlChar *str, xmlXPathContextPtr ctx) {
+    xmlXPathParserContextPtr ctxt;
+    xmlXPathObjectPtr res = NULL, tmp;
+    xmlXPathObjectPtr init = NULL;
+    int stack = 0;
+
+    xmlXPathInit();
+
+    if ((ctx == NULL) || (str == NULL))
+	return(NULL);
+
+    ctxt = xmlXPathNewParserContext(str, ctx);
+    /* TAG:9999
+    if (ctx->node != NULL) {
+	init = xmlXPathNewNodeSet(ctx->node);
+	valuePush(ctxt, init);
+    }
+     */
+    xmlXPtrEvalXPointer(ctxt);
+
+    if ((ctxt->value != NULL) &&
+	(ctxt->value->type != XPATH_NODESET) &&
+	(ctxt->value->type != XPATH_LOCATIONSET)) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrEval: evaluation failed to return a node set\n");
+    } else {
+	res = valuePop(ctxt);
+    }
+
+    do {
+        tmp = valuePop(ctxt);
+	if (tmp != NULL) {
+	    if (tmp != init) {
+		if (tmp->type == XPATH_NODESET) {
+		    /*
+		     * Evaluation may push a root nodeset which is unused
+		     */
+		    xmlNodeSetPtr set; 
+		    set = tmp->nodesetval;
+		    if ((set->nodeNr != 1) ||
+			(set->nodeTab[0] != (xmlNodePtr) ctx->doc))
+			stack++;
+		} else
+		    stack++;    
+	    }
+	    xmlXPathFreeObject(tmp);
+        }
+    } while (tmp != NULL);
+    if (stack != 0) {
+	xmlGenericError(xmlGenericErrorContext,
+		"xmlXPtrEval: %d object left on the stack\n",
+	        stack);
+    }
+    if (ctxt->error != XPATH_EXPRESSION_OK) {
+	xmlXPathFreeObject(res);
+	res = NULL;
+    }
+        
+    xmlXPathFreeParserContext(ctxt);
+    return(res);
+}
+
+/**
+ * xmlXPtrBuildRangeNodeList:
+ * @range:  a range object
+ *
+ * Build a node list tree copy of the range
+ *
+ * Returns an xmlNodePtr list or NULL.
+ *         the caller has to free the node tree.
+ */
+xmlNodePtr
+xmlXPtrBuildRangeNodeList(xmlXPathObjectPtr range) {
+    /* pointers to generated nodes */
+    xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
+    /* pointers to traversal nodes */
+    xmlNodePtr start, cur, end;
+    int index, index2;
+
+    if (range == NULL)
+	return(NULL);
+    if (range->type != XPATH_RANGE)
+	return(NULL);
+    start = (xmlNodePtr) range->user;
+
+    if (start == NULL)
+	return(NULL);
+    end = range->user2;
+    if (end == NULL)
+	return(xmlCopyNode(start, 1));
+
+    cur = start;
+    index = range->index;
+    index2 = range->index2;
+    while (cur != NULL) {
+	if (cur == end) {
+	    if (cur->type == XML_TEXT_NODE) {
+		const xmlChar *content = cur->content;
+		int len;
+
+		if (content == NULL) {
+		    tmp = xmlNewTextLen(NULL, 0);
+		} else {
+		    len = index2;
+		    if ((cur == start) && (index > 1)) {
+			content += (index - 1);
+			len -= (index - 1);
+			index = 0;
+		    } else {
+			len = index2;
+		    }
+		    tmp = xmlNewTextLen(content, len);
+		}
+		/* single sub text node selection */
+		if (list == NULL)
+		    return(tmp);
+		/* prune and return full set */
+		if (last != NULL)
+		    xmlAddNextSibling(last, tmp);
+		else 
+		    xmlAddChild(parent, tmp);
+		return(list);
+	    } else {
+		tmp = xmlCopyNode(cur, 0);
+		if (list == NULL)
+		    list = tmp;
+		else {
+		    if (last != NULL)
+			xmlAddNextSibling(last, tmp);
+		    else
+			xmlAddChild(parent, tmp);
+		}
+		last = NULL;
+		parent = tmp;
+
+		if (index2 > 1) {
+		    end = xmlXPtrGetNthChild(cur, index2 - 1);
+		    index2 = 0;
+		}
+		if ((cur == start) && (index > 1)) {
+		    cur = xmlXPtrGetNthChild(cur, index - 1);
+		    index = 0;
+		} else {
+		    cur = cur->children;
+		}
+		/*
+		 * Now gather the remaining nodes from cur to end
+		 */
+		continue; /* while */
+	    }
+	} else if ((cur == start) &&
+		   (list == NULL) /* looks superfluous but ... */ ) {
+	    if (cur->type == XML_TEXT_NODE) {
+		const xmlChar *content = cur->content;
+
+		if (content == NULL) {
+		    tmp = xmlNewTextLen(NULL, 0);
+		} else {
+		    if (index > 1) {
+			content += (index - 1);
+		    }
+		    tmp = xmlNewText(content);
+		}
+		last = list = tmp;
+	    } else {
+		if ((cur == start) && (index > 1)) {
+		    tmp = xmlCopyNode(cur, 0);
+		    list = tmp;
+		    parent = tmp;
+		    last = NULL;
+		    cur = xmlXPtrGetNthChild(cur, index - 1);
+		    index = 0;
+		    /*
+		     * Now gather the remaining nodes from cur to end
+		     */
+		    continue; /* while */
+		}
+		tmp = xmlCopyNode(cur, 1);
+		list = tmp;
+		parent = NULL;
+		last = tmp;
+	    }
+	} else {
+	    tmp = NULL;
+	    switch (cur->type) {
+		case XML_DTD_NODE:
+		case XML_ELEMENT_DECL:
+		case XML_ATTRIBUTE_DECL:
+		case XML_ENTITY_NODE:
+		    /* Do not copy DTD informations */
+		    break;
+		case XML_ENTITY_DECL:
+		    TODO /* handle csossing entities -> stack needed */
+		    break;
+		case XML_XINCLUDE_START:
+		case XML_XINCLUDE_END:
+		    /* don't consider it part of the tree content */
+		    break;
+		case XML_ATTRIBUTE_NODE:
+		    /* Humm, should not happen ! */
+		    STRANGE
+		    break;
+		default:
+		    tmp = xmlCopyNode(cur, 1);
+		    break;
+	    }
+	    if (tmp != NULL) {
+		if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
+		    STRANGE
+		    return(NULL);
+		}
+		if (last != NULL)
+		    xmlAddNextSibling(last, tmp);
+		else {
+		    xmlAddChild(parent, tmp);
+		    last = tmp;
+		}
+	    }
+	}
+	/*
+	 * Skip to next node in document order
+	 */
+	if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
+	    STRANGE
+	    return(NULL);
+	}
+	cur = xmlXPtrAdvanceNode(cur);
+    }
+    return(list);
+}
+
+/**
+ * xmlXPtrBuildNodeList:
+ * @obj:  the XPointer result from the evaluation.
+ *
+ * Build a node list tree copy of the XPointer result.
+ *
+ * Returns an xmlNodePtr list or NULL.
+ *         the caller has to free the node tree.
+ */
+xmlNodePtr
+xmlXPtrBuildNodeList(xmlXPathObjectPtr obj) {
+    xmlNodePtr list = NULL, last = NULL;
+    int i;
+
+    if (obj == NULL)
+	return(NULL);
+    switch (obj->type) {
+        case XPATH_NODESET: {
+	    xmlNodeSetPtr set = obj->nodesetval;
+	    if (set == NULL)
+		return(NULL);
+	    for (i = 0;i < set->nodeNr;i++) {
+		if (last == NULL)
+		    list = last = xmlCopyNode(set->nodeTab[i], 1);
+		else {
+		    xmlAddNextSibling(last, xmlCopyNode(set->nodeTab[i], 1));
+		    if (last->next != NULL)
+			last = last->next;
+		}
+	    }
+	    break;
+	}
+	case XPATH_LOCATIONSET: {
+	    xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
+	    if (set == NULL)
+		return(NULL);
+	    for (i = 0;i < set->locNr;i++) {
+		if (last == NULL)
+		    list = last = xmlXPtrBuildNodeList(set->locTab[i]);
+		else
+		    xmlAddNextSibling(last,
+			    xmlXPtrBuildNodeList(set->locTab[i]));
+		if (last != NULL) {
+		    while (last->next != NULL)
+			last = last->next;
+		}
+	    }
+	    break;
+	}
+	case XPATH_RANGE:
+	    return(xmlXPtrBuildRangeNodeList(obj));
+	case XPATH_POINT:
+	    return(xmlCopyNode(obj->user, 0));
+	default:
+	    break;
+    }
+    return(list);
+}
+
+/************************************************************************
+ *									*
+ *			XPointer functions				*
+ *									*
+ ************************************************************************/
+
+/**
+ * xmlXPtrNbLocChildren:
+ * @node:  an xmlNodePtr
+ *
+ * Count the number of location children of @node or the lenght of the
+ * string value in case of text/PI/Comments nodes
+ *
+ * Returns the number of location children
+ */
+int
+xmlXPtrNbLocChildren(xmlNodePtr node) {
+    int ret = 0;
+    if (node == NULL)
+	return(-1);
+    switch (node->type) {
+        case XML_HTML_DOCUMENT_NODE:
+        case XML_DOCUMENT_NODE:
+        case XML_ELEMENT_NODE:
+	    node = node->children;
+	    while (node != NULL) {
+		if (node->type == XML_ELEMENT_NODE)
+		    ret++;
+		node = node->next;
+	    }
+	    break;
+        case XML_ATTRIBUTE_NODE:
+	    return(-1);
+
+        case XML_PI_NODE:
+        case XML_COMMENT_NODE:
+        case XML_TEXT_NODE:
+        case XML_CDATA_SECTION_NODE:
+        case XML_ENTITY_REF_NODE:
+#ifndef XML_USE_BUFFER_CONTENT
+	    ret = xmlStrlen(node->content);
+#else
+	    ret = xmlBufferLength(node->content);
+#endif
+	    break;
+	default:
+	    return(-1);
+    }
+    return(ret);
+}
+
+/**
+ * xmlXPtrHereFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing here() operation 
+ * as described in 5.4.3
+ */
+void
+xmlXPtrHereFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    if (ctxt->context->here == NULL)
+	XP_ERROR(XPTR_SYNTAX_ERROR);
+    
+    valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->here, NULL));
+}
+
+/**
+ * xmlXPtrOriginFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing origin() operation 
+ * as described in 5.4.3
+ */
+void
+xmlXPtrOriginFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    if (ctxt->context->origin == NULL)
+	XP_ERROR(XPTR_SYNTAX_ERROR);
+    
+    valuePush(ctxt, xmlXPtrNewLocationSetNodes(ctxt->context->origin, NULL));
+}
+
+/**
+ * xmlXPtrStartPointFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing start-point() operation 
+ * as described in 5.4.3
+ * ----------------
+ * location-set start-point(location-set)
+ *
+ * For each location x in the argument location-set, start-point adds a
+ * location of type point to the result location-set. That point represents
+ * the start point of location x and is determined by the following rules:
+ *
+ * - If x is of type point, the start point is x.
+ * - If x is of type range, the start point is the start point of x.
+ * - If x is of type root, element, text, comment, or processing instruction,
+ * - the container node of the start point is x and the index is 0.
+ * - If x is of type attribute or namespace, the function must signal a
+ *   syntax error.
+ * ----------------
+ *
+ */
+void
+xmlXPtrStartPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr tmp, obj, point;
+    xmlLocationSetPtr newset = NULL;
+    xmlLocationSetPtr oldset = NULL;
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_LOCATIONSET) &&
+	 (ctxt->value->type != XPATH_NODESET)))
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+    obj = valuePop(ctxt);
+    if (obj->type == XPATH_NODESET) {
+	/*
+	 * First convert to a location set
+	 */
+	tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
+	xmlXPathFreeObject(obj);
+	obj = tmp;
+    }
+
+    newset = xmlXPtrLocationSetCreate(NULL);
+    if (newset == NULL) {
+	xmlXPathFreeObject(obj);
+        XP_ERROR(XPATH_MEMORY_ERROR);
+    }
+    oldset = (xmlLocationSetPtr) obj->user;
+    if (oldset != NULL) {
+	int i;
+
+	for (i = 0; i < oldset->locNr; i++) {
+	    tmp = oldset->locTab[i];
+	    if (tmp == NULL)
+		continue;
+	    point = NULL;
+	    switch (tmp->type) {
+		case XPATH_POINT:
+		    point = xmlXPtrNewPoint(tmp->user, tmp->index);
+		    break;
+		case XPATH_RANGE: {
+		    xmlNodePtr node = tmp->user;
+		    if (node != NULL) {
+			if (node->type == XML_ATTRIBUTE_NODE) {
+			    /* TODO: Namespace Nodes ??? */
+			    xmlXPathFreeObject(obj);
+			    xmlXPtrFreeLocationSet(newset);
+			    XP_ERROR(XPTR_SYNTAX_ERROR);
+			}
+			point = xmlXPtrNewPoint(node, tmp->index);
+		    }
+		    break;
+	        }
+		default:
+		    /*** Should we raise an error ?
+		    xmlXPathFreeObject(obj);
+		    xmlXPathFreeObject(newset);
+		    XP_ERROR(XPATH_INVALID_TYPE)
+		    ***/
+		    break;
+	    }
+            if (point != NULL)
+		xmlXPtrLocationSetAdd(newset, point);
+	}
+    }
+    xmlXPathFreeObject(obj);
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+}
+
+/**
+ * xmlXPtrEndPointFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing end-point() operation 
+ * as described in 5.4.3
+ * ----------------------------
+ * location-set end-point(location-set)
+ *
+ * For each location x in the argument location-set, end-point adds a
+ * location of type point to the result location-set. That point representsi
+ * the end point of location x and is determined by the following rules:
+ *
+ * - If x is of type point, the resulting point is x.
+ * - If x is of type range, the resulting point is the end point of x.
+ * - If x is of type root or element, the container node of the resulting
+ *   point is x and the index is the number of location children of x.
+ * - If x is of type text, comment, or processing instruction, the container
+ *   node of the resulting point is x and the index is the length of thei
+ *   string-value of x.
+ * - If x is of type attribute or namespace, the function must signal a
+ *   syntax error.
+ * ----------------------------
+ */
+void
+xmlXPtrEndPointFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr tmp, obj, point;
+    xmlLocationSetPtr newset = NULL;
+    xmlLocationSetPtr oldset = NULL;
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_LOCATIONSET) &&
+	 (ctxt->value->type != XPATH_NODESET)))
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+    obj = valuePop(ctxt);
+    if (obj->type == XPATH_NODESET) {
+	/*
+	 * First convert to a location set
+	 */
+	tmp = xmlXPtrNewLocationSetNodeSet(obj->nodesetval);
+	xmlXPathFreeObject(obj);
+	obj = tmp;
+    }
+
+    newset = xmlXPtrLocationSetCreate(NULL);
+    oldset = (xmlLocationSetPtr) obj->user;
+    if (oldset != NULL) {
+	int i;
+
+	for (i = 0; i < oldset->locNr; i++) {
+	    tmp = oldset->locTab[i];
+	    if (tmp == NULL)
+		continue;
+	    point = NULL;
+	    switch (tmp->type) {
+		case XPATH_POINT:
+		    point = xmlXPtrNewPoint(tmp->user, tmp->index);
+		    break;
+		case XPATH_RANGE: {
+		    xmlNodePtr node = tmp->user2;
+		    if (node != NULL) {
+			if (node->type == XML_ATTRIBUTE_NODE) {
+			    /* TODO: Namespace Nodes ??? */
+			    xmlXPathFreeObject(obj);
+			    xmlXPtrFreeLocationSet(newset);
+			    XP_ERROR(XPTR_SYNTAX_ERROR);
+			}
+			point = xmlXPtrNewPoint(node, tmp->index2);
+		    } else if (tmp->user == NULL) {
+			point = xmlXPtrNewPoint(node,
+				       xmlXPtrNbLocChildren(node));
+		    }
+		    break;
+	        }
+		default:
+		    /*** Should we raise an error ?
+		    xmlXPathFreeObject(obj);
+		    xmlXPathFreeObject(newset);
+		    XP_ERROR(XPATH_INVALID_TYPE)
+		    ***/
+		    break;
+	    }
+            if (point != NULL)
+		xmlXPtrLocationSetAdd(newset, point);
+	}
+    }
+    xmlXPathFreeObject(obj);
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+}
+
+
+/**
+ * xmlXPtrCoveringRange:
+ * @ctxt:  the XPointer Parser context
+ * @loc:  the location for which the covering range must be computed
+ *
+ * A covering range is a range that wholly encompasses a location
+ * Section 5.3.3. Covering Ranges for All Location Types
+ *        http://www.w3.org/TR/xptr#N2267
+ *
+ * Returns a new location or NULL in case of error
+ */
+xmlXPathObjectPtr
+xmlXPtrCoveringRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
+    if (loc == NULL)
+	return(NULL);
+    if ((ctxt == NULL) || (ctxt->context == NULL) ||
+	(ctxt->context->doc == NULL))
+	return(NULL);
+    switch (loc->type) {
+        case XPATH_POINT:
+	    return(xmlXPtrNewRange(loc->user, loc->index,
+			           loc->user, loc->index));
+        case XPATH_RANGE:
+	    if (loc->user2 != NULL) {
+		return(xmlXPtrNewRange(loc->user, loc->index,
+			              loc->user2, loc->index2));
+	    } else {
+		xmlNodePtr node = (xmlNodePtr) loc->user;
+		if (node == (xmlNodePtr) ctxt->context->doc) {
+		    return(xmlXPtrNewRange(node, 0, node,
+					   xmlXPtrGetArity(node)));
+		} else {
+		    switch (node->type) {
+			case XML_ATTRIBUTE_NODE:
+			/* !!! our model is slightly different than XPath */
+			    return(xmlXPtrNewRange(node, 0, node,
+					           xmlXPtrGetArity(node)));
+			case XML_ELEMENT_NODE:
+			case XML_TEXT_NODE:
+			case XML_CDATA_SECTION_NODE:
+			case XML_ENTITY_REF_NODE:
+			case XML_PI_NODE:
+			case XML_COMMENT_NODE:
+			case XML_DOCUMENT_NODE:
+			case XML_NOTATION_NODE:
+			case XML_HTML_DOCUMENT_NODE: {
+			    int index = xmlXPtrGetIndex(node);
+			     
+			    node = node->parent;
+			    return(xmlXPtrNewRange(node, index - 1,
+					           node, index + 1));
+			}
+			default:
+			    return(NULL);
+		    }
+		}
+	    }
+	default:
+	    TODO /* missed one case ??? */
+    }
+    return(NULL);
+}
+
+/**
+ * xmlXPtrRangeFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing the range() function 5.4.3
+ *  location-set range(location-set )
+ *
+ *  The range function returns ranges covering the locations in
+ *  the argument location-set. For each location x in the argument
+ *  location-set, a range location representing the covering range of
+ *  x is added to the result location-set.
+ */
+void
+xmlXPtrRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    int i;
+    xmlXPathObjectPtr set;
+    xmlLocationSetPtr oldset;
+    xmlLocationSetPtr newset;
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_LOCATIONSET) &&
+	 (ctxt->value->type != XPATH_NODESET)))
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+    set = valuePop(ctxt);
+    if (set->type == XPATH_NODESET) {
+	xmlXPathObjectPtr tmp;
+
+	/*
+	 * First convert to a location set
+	 */
+	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
+	xmlXPathFreeObject(set);
+	set = tmp;
+    }
+    oldset = (xmlLocationSetPtr) set->user;
+
+    /*
+     * The loop is to compute the covering range for each item and add it
+     */
+    newset = xmlXPtrLocationSetCreate(NULL);
+    for (i = 0;i < oldset->locNr;i++) {
+	xmlXPtrLocationSetAdd(newset,
+		xmlXPtrCoveringRange(ctxt, oldset->locTab[i]));
+    }
+
+    /*
+     * Save the new value and cleanup
+     */
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+    xmlXPathFreeObject(set);
+}
+
+/**
+ * xmlXPtrInsideRange:
+ * @ctxt:  the XPointer Parser context
+ * @loc:  the location for which the inside range must be computed
+ *
+ * A inside range is a range described in the range-inside() description
+ *
+ * Returns a new location or NULL in case of error
+ */
+xmlXPathObjectPtr
+xmlXPtrInsideRange(xmlXPathParserContextPtr ctxt, xmlXPathObjectPtr loc) {
+    if (loc == NULL)
+	return(NULL);
+    if ((ctxt == NULL) || (ctxt->context == NULL) ||
+	(ctxt->context->doc == NULL))
+	return(NULL);
+    switch (loc->type) {
+        case XPATH_POINT: {
+	    xmlNodePtr node = (xmlNodePtr) loc->user;
+	    switch (node->type) {
+		case XML_PI_NODE:
+		case XML_COMMENT_NODE:
+		case XML_TEXT_NODE:
+		case XML_CDATA_SECTION_NODE: {
+		    if (node->content == NULL) {
+			return(xmlXPtrNewRange(node, 0, node, 0));
+		    } else {
+#ifndef XML_USE_BUFFER_CONTENT
+			return(xmlXPtrNewRange(node, 0, node,
+					       xmlStrlen(node->content)));
+#else
+			return(xmlXPtrNewRange(node, 0, node,
+					       xmlBufferLength(node->content)));
+#endif
+		    }
+		}
+		case XML_ATTRIBUTE_NODE:
+		case XML_ELEMENT_NODE:
+		case XML_ENTITY_REF_NODE:
+		case XML_DOCUMENT_NODE:
+		case XML_NOTATION_NODE:
+		case XML_HTML_DOCUMENT_NODE: {
+		    return(xmlXPtrNewRange(node, 0, node,
+					   xmlXPtrGetArity(node)));
+		}
+		default:
+		    return(NULL);
+	    }
+	    return(NULL);
+	}
+        case XPATH_RANGE: {
+	    xmlNodePtr node = (xmlNodePtr) loc->user;
+	    if (loc->user2 != NULL) {
+		return(xmlXPtrNewRange(node, loc->index,
+			               loc->user2, loc->index2));
+	    } else {
+		switch (node->type) {
+		    case XML_PI_NODE:
+		    case XML_COMMENT_NODE:
+		    case XML_TEXT_NODE:
+		    case XML_CDATA_SECTION_NODE: {
+			if (node->content == NULL) {
+			    return(xmlXPtrNewRange(node, 0, node, 0));
+			} else {
+#ifndef XML_USE_BUFFER_CONTENT
+			    return(xmlXPtrNewRange(node, 0, node,
+						   xmlStrlen(node->content)));
+#else
+			    return(xmlXPtrNewRange(node, 0, node,
+					       xmlBufferLength(node->content)));
+#endif
+			}
+		    }
+		    case XML_ATTRIBUTE_NODE:
+		    case XML_ELEMENT_NODE:
+		    case XML_ENTITY_REF_NODE:
+		    case XML_DOCUMENT_NODE:
+		    case XML_NOTATION_NODE:
+		    case XML_HTML_DOCUMENT_NODE: {
+			return(xmlXPtrNewRange(node, 0, node,
+					       xmlXPtrGetArity(node)));
+		    }
+		    default:
+			return(NULL);
+		}
+		return(NULL);
+	    }
+        }
+	default:
+	    TODO /* missed one case ??? */
+    }
+    return(NULL);
+}
+
+/**
+ * xmlXPtrRangeInsideFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing the range-inside() function 5.4.3
+ *  location-set range-inside(location-set )
+ *
+ *  The range-inside function returns ranges covering the contents of
+ *  the locations in the argument location-set. For each location x in
+ *  the argument location-set, a range location is added to the result
+ *  location-set. If x is a range location, then x is added to the
+ *  result location-set. If x is not a range location, then x is used
+ *  as the container location of the start and end points of the range
+ *  location to be added; the index of the start point of the range is
+ *  zero; if the end point is a character point then its index is the
+ *  length of the string-value of x, and otherwise is the number of
+ *  location children of x.
+ *
+ */
+void
+xmlXPtrRangeInsideFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    int i;
+    xmlXPathObjectPtr set;
+    xmlLocationSetPtr oldset;
+    xmlLocationSetPtr newset;
+
+    CHECK_ARITY(1);
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_LOCATIONSET) &&
+	 (ctxt->value->type != XPATH_NODESET)))
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+    set = valuePop(ctxt);
+    if (set->type == XPATH_NODESET) {
+	xmlXPathObjectPtr tmp;
+
+	/*
+	 * First convert to a location set
+	 */
+	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
+	xmlXPathFreeObject(set);
+	set = tmp;
+    }
+    oldset = (xmlLocationSetPtr) set->user;
+
+    /*
+     * The loop is to compute the covering range for each item and add it
+     */
+    newset = xmlXPtrLocationSetCreate(NULL);
+    for (i = 0;i < oldset->locNr;i++) {
+	xmlXPtrLocationSetAdd(newset,
+		xmlXPtrInsideRange(ctxt, oldset->locTab[i]));
+    }
+
+    /*
+     * Save the new value and cleanup
+     */
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+    xmlXPathFreeObject(set);
+}
+
+/**
+ * xmlXPtrRangeToFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Implement the range-to() XPointer function
+ */
+void
+xmlXPtrRangeToFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    xmlXPathObjectPtr range;
+    const xmlChar *cur;
+    xmlXPathObjectPtr res, obj;
+    xmlXPathObjectPtr tmp;
+    xmlLocationSetPtr newset = NULL;
+    xmlNodeSetPtr oldset;
+    int i;
+
+    CHECK_ARITY(1);
+    /*
+     * Save the expression pointer since we will have to evaluate
+     * it multiple times. Initialize the new set.
+     */
+    CHECK_TYPE(XPATH_NODESET);
+    obj = valuePop(ctxt);
+    oldset = obj->nodesetval;
+    ctxt->context->node = NULL;
+
+    cur = ctxt->cur;
+    newset = xmlXPtrLocationSetCreate(NULL);
+    
+    for (i = 0; i < oldset->nodeNr; i++) {
+	ctxt->cur = cur;
+
+	/*
+	 * Run the evaluation with a node list made of a single item
+	 * in the nodeset.
+	 */
+	ctxt->context->node = oldset->nodeTab[i];
+	tmp = xmlXPathNewNodeSet(ctxt->context->node);
+	valuePush(ctxt, tmp);
+
+	xmlXPathEvalExpr(ctxt);
+	CHECK_ERROR;
+
+	/*
+	 * The result of the evaluation need to be tested to
+	 * decided whether the filter succeeded or not
+	 */
+	res = valuePop(ctxt);
+	range = xmlXPtrNewRangeNodeObject(oldset->nodeTab[i], res);
+	if (range != NULL) {
+	    xmlXPtrLocationSetAdd(newset, range);
+	}
+
+	/*
+	 * Cleanup
+	 */
+	if (res != NULL)
+	    xmlXPathFreeObject(res);
+	if (ctxt->value == tmp) {
+	    res = valuePop(ctxt);
+	    xmlXPathFreeObject(res);
+	}
+	
+	ctxt->context->node = NULL;
+    }
+
+    /*
+     * The result is used as the new evaluation set.
+     */
+    xmlXPathFreeObject(obj);
+    ctxt->context->node = NULL;
+    ctxt->context->contextSize = -1;
+    ctxt->context->proximityPosition = -1;
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+}
+
+/**
+ * xmlXPtrAdvanceNode:
+ * @cur:  the node
+ *
+ * Advance to the next element or text node in document order
+ * TODO: add a stack for entering/exiting entities 
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+xmlNodePtr
+xmlXPtrAdvanceNode(xmlNodePtr cur) {
+next:
+    if (cur == NULL)
+	return(NULL);
+    if (cur->children != NULL) {
+        cur = cur->children ;
+	goto found;
+    }
+    if (cur->next != NULL) {
+	cur = cur->next;
+	goto found;
+    }
+    do {
+        cur = cur->parent;
+        if (cur == NULL) return(NULL);
+        if (cur->next != NULL) {
+	    cur = cur->next;
+	    goto found;
+	}
+    } while (cur != NULL);
+
+found:
+    if ((cur->type != XML_ELEMENT_NODE) &&
+	(cur->type != XML_TEXT_NODE) &&
+	(cur->type != XML_DOCUMENT_NODE) &&
+	(cur->type != XML_HTML_DOCUMENT_NODE) &&
+	(cur->type != XML_CDATA_SECTION_NODE))
+	goto next;
+    if (cur->type == XML_ENTITY_REF_NODE) {
+	TODO
+    }
+    return(cur);
+}
+
+/**
+ * xmlXPtrAdvanceChar:
+ * @node:  the node
+ * @index:  the index
+ * @bytes:  the number of bytes
+ *
+ * Advance a point of the associated number of bytes (not UTF8 chars)
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrAdvanceChar(xmlNodePtr *node, int *index, int bytes) {
+    xmlNodePtr cur;
+    int pos;
+    int len;
+
+    if ((node == NULL) || (index == NULL))
+	return(-1);
+    cur = *node;
+    if (cur == NULL)
+	return(-1);
+    pos = *index;
+
+    while (bytes >= 0) {
+	/*
+	 * First position to the beginning of the first text node
+	 * corresponding to this point
+	 */
+	while ((cur != NULL) &&
+	       ((cur->type == XML_ELEMENT_NODE) ||
+	        (cur->type == XML_DOCUMENT_NODE) ||
+	        (cur->type == XML_HTML_DOCUMENT_NODE))) {
+	    if (pos > 0) {
+		cur = xmlXPtrGetNthChild(cur, pos);
+		pos = 0;
+	    } else {
+		cur = xmlXPtrAdvanceNode(cur);
+		pos = 0;
+	    }
+	}
+
+	if (cur == NULL) {
+	    *node = NULL;
+	    *index = 0;
+	    return(-1);
+	}
+
+	/*
+	 * if there is no move needed return the current value.
+	 */
+	if (pos == 0) pos = 1;
+	if (bytes == 0) {
+	    *node = cur;
+	    *index = pos;
+	    return(0);
+	}
+	/*
+	 * We should have a text (or cdata) node ... 
+	 */
+	len = 0;
+	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
+	}
+	if (pos > len) {
+	    /* Strange, the index in the text node is greater than it's len */
+	    STRANGE
+	    pos = len;
+	}
+	if (pos + bytes >= len) {
+	    bytes -= (len - pos);
+	    cur = xmlXPtrAdvanceNode(cur);
+	    cur = 0;
+	} else if (pos + bytes < len) {
+	    pos += bytes;
+	    *node = cur;
+	    *index = pos;
+	    return(0);
+	}
+    }
+    return(-1);
+}
+
+/**
+ * xmlXPtrMatchString:
+ * @string:  the string to search
+ * @start:  the start textnode
+ * @startindex:  the start index
+ * @end:  the end textnode IN/OUT
+ * @endindex:  the end index IN/OUT
+ *
+ * Check whether the document contains @string at the position
+ * (@start, @startindex) and limited by the (@end, @endindex) point
+ *
+ * Returns -1 in case of failure, 0 if not found, 1 if found in which case
+ *            (@start, @startindex) will indicate the position of the beginning
+ *            of the range and (@end, @endindex) will endicate the end
+ *            of the range
+ */
+int
+xmlXPtrMatchString(const xmlChar *string, xmlNodePtr start, int startindex,
+	            xmlNodePtr *end, int *endindex) {
+    xmlNodePtr cur;
+    int pos; /* 0 based */
+    int len; /* in bytes */
+    int stringlen; /* in bytes */
+    int match;
+
+    if (string == NULL)
+	return(-1);
+    if (start == NULL)
+	return(-1);
+    if ((end == NULL) || (endindex == NULL))
+	return(-1);
+    cur = start;
+    if (cur == NULL)
+	return(-1);
+    pos = startindex - 1;
+    stringlen = xmlStrlen(string);
+
+    while (stringlen > 0) {
+	if ((cur == *end) && (pos + stringlen > *endindex))
+	    return(0);
+	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
+	    if (len >= pos + stringlen) {
+#ifndef XML_USE_BUFFER_CONTENT
+		match = (!xmlStrncmp(&cur->content[pos], string, stringlen));
+#else
+		len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos],
+			           string, stringlen));
+#endif
+		if (match) {
+#ifdef DEBUG_RANGES
+		    xmlGenericError(xmlGenericErrorContext,
+			    "found range %d bytes at index %d of ->",
+			    stringlen, pos + 1);
+		    xmlDebugDumpString(stdout, cur->content);
+		    xmlGenericError(xmlGenericErrorContext, "\n");
+#endif
+		    *end = cur;
+		    *endindex = pos + stringlen;
+		    return(1);
+		} else {
+		    return(0);
+		}
+	    } else {
+                int sub = len - pos;
+#ifndef XML_USE_BUFFER_CONTENT
+		match = (!xmlStrncmp(&cur->content[pos], string, sub));
+#else
+		len = (!xmlStrncmp(&xmlBufferContent(cur->content)[pos],
+			           string, sub));
+#endif
+		if (match) {
+#ifdef DEBUG_RANGES
+		    xmlGenericError(xmlGenericErrorContext,
+			    "found subrange %d bytes at index %d of ->",
+			    sub, pos + 1);
+		    xmlDebugDumpString(stdout, cur->content);
+		    xmlGenericError(xmlGenericErrorContext, "\n");
+#endif
+                    string = &string[sub];
+		    stringlen -= sub;
+		} else {
+		    return(0);
+		}
+	    }
+	}
+	cur = xmlXPtrAdvanceNode(cur);
+	if (cur == NULL)
+	    return(0);
+	pos = 0;
+    }
+    return(1);
+}
+
+/**
+ * xmlXPtrSearchString:
+ * @string:  the string to search
+ * @start:  the start textnode IN/OUT
+ * @startindex:  the start index IN/OUT
+ * @end:  the end textnode
+ * @endindex:  the end index
+ *
+ * Search the next occurence of @string within the document content
+ * until the (@end, @endindex) point is reached
+ *
+ * Returns -1 in case of failure, 0 if not found, 1 if found in which case
+ *            (@start, @startindex) will indicate the position of the beginning
+ *            of the range and (@end, @endindex) will endicate the end
+ *            of the range
+ */
+int
+xmlXPtrSearchString(const xmlChar *string, xmlNodePtr *start, int *startindex,
+	            xmlNodePtr *end, int *endindex) {
+    xmlNodePtr cur;
+    const xmlChar *str;
+    int pos; /* 0 based */
+    int len; /* in bytes */
+    int stringlen; /* in bytes */
+    xmlChar first;
+
+    if (string == NULL)
+	return(-1);
+    if ((start == NULL) || (startindex == NULL))
+	return(-1);
+    if ((end == NULL) || (endindex == NULL))
+	return(-1);
+    cur = *start;
+    if (cur == NULL)
+	return(-1);
+    pos = *startindex - 1;
+    first = string[0];
+    stringlen = xmlStrlen(string);
+
+    while (cur != NULL) {
+	if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
+	    while (pos <= len) {
+		if (first != 0) {
+#ifndef XML_USE_BUFFER_CONTENT
+		    str = xmlStrchr(&cur->content[pos], first);
+#else
+		    str = xmlStrchr(&xmlBufferContent(cur->content)[pos],
+			            first);
+#endif
+		    if (str != NULL) {
+			pos = (str - (xmlChar *)(cur->content));
+#ifdef DEBUG_RANGES
+			xmlGenericError(xmlGenericErrorContext,
+				"found '%c' at index %d of ->",
+				first, pos + 1);
+			xmlDebugDumpString(stdout, cur->content);
+			xmlGenericError(xmlGenericErrorContext, "\n");
+#endif
+			if (xmlXPtrMatchString(string, cur, pos + 1,
+					       end, endindex)) {
+			    *start = cur;
+			    *startindex = pos + 1;
+			    return(1);
+			}
+			pos++;
+		    } else {
+			pos = len + 1;
+		    }
+		} else {
+		    /*
+		     * An empty string is considered to match before each
+		     * character of the string-value and after the final
+		     * character. 
+		     */
+#ifdef DEBUG_RANGES
+		    xmlGenericError(xmlGenericErrorContext,
+			    "found '' at index %d of ->",
+			    pos + 1);
+		    xmlDebugDumpString(stdout, cur->content);
+		    xmlGenericError(xmlGenericErrorContext, "\n");
+#endif
+		    *start = cur;
+		    *startindex = pos + 1;
+		    *end = cur;
+		    *endindex = pos + 1;
+		    return(1);
+		}
+	    }
+	}
+	if ((cur == *end) && (pos >= *endindex))
+	    return(0);
+	cur = xmlXPtrAdvanceNode(cur);
+	if (cur == NULL)
+	    return(0);
+	pos = 1;
+    }
+    return(0);
+}
+
+/**
+ * xmlXPtrGetLastChar:
+ * @node:  the node
+ * @index:  the index
+ *
+ * Computes the point coordinates of the last char of this point
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrGetLastChar(xmlNodePtr *node, int *index) {
+    xmlNodePtr cur;
+    int pos, len = 0;
+
+    if ((node == NULL) || (index == NULL))
+	return(-1);
+    cur = *node;
+    pos = *index;
+
+    if (cur == NULL)
+	return(-1);
+    
+    if ((cur->type == XML_ELEMENT_NODE) ||
+	(cur->type == XML_DOCUMENT_NODE) ||
+	(cur->type == XML_HTML_DOCUMENT_NODE)) {
+	if (pos > 0) {
+	    cur = xmlXPtrGetNthChild(cur, pos);
+	    pos = 0;
+	}
+    }
+    while (cur != NULL) {
+	if (cur->last != NULL)
+	    cur = cur->last;
+	else if (cur->content != NULL) {
+#ifndef XML_USE_BUFFER_CONTENT
+	    len = xmlStrlen(cur->content);
+#else
+	    len = xmlBufferLength(cur->content);
+#endif
+	    break;
+	} else {
+	    return(-1);
+	}
+    }
+    if (cur == NULL)
+	return(-1);
+    *node = cur;
+    *index = len;
+    return(0);
+}
+
+/**
+ * xmlXPtrGetStartPoint:
+ * @obj:  an range
+ * @node:  the resulting node
+ * @index:  the resulting index
+ *
+ * read the object and return the start point coordinates.
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrGetStartPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *index) {
+    if ((obj == NULL) || (node == NULL) || (index == NULL))
+	return(-1);
+
+    switch (obj->type) {
+        case XPATH_POINT:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+        case XPATH_RANGE:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+	default:
+	    return(-1);
+    }
+    return(-1);
+}
+
+/**
+ * xmlXPtrGetEndPoint:
+ * @obj:  an range
+ * @node:  the resulting node
+ * @index:  the resulting index
+ *
+ * read the object and return the end point coordinates.
+ *
+ * Returns -1 in case of failure, 0 otherwise
+ */
+int
+xmlXPtrGetEndPoint(xmlXPathObjectPtr obj, xmlNodePtr *node, int *index) {
+    if ((obj == NULL) || (node == NULL) || (index == NULL))
+	return(-1);
+
+    switch (obj->type) {
+        case XPATH_POINT:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+        case XPATH_RANGE:
+	    *node = obj->user;
+	    if (obj->index <= 0)
+		*index = 0;
+	    else
+		*index = obj->index;
+	    return(0);
+	default:
+	    return(-1);
+    }
+    return(-1);
+}
+
+/**
+ * xmlXPtrStringRangeFunction:
+ * @ctxt:  the XPointer Parser context
+ *
+ * Function implementing the string-range() function
+ * range as described in 5.4.2 
+ *
+ * ------------------------------
+ * [Definition: For each location in the location-set argument,
+ * string-range returns a set of string ranges, a set of substrings in a
+ * string. Specifically, the string-value of the location is searched for
+ * substrings that match the string argument, and the resulting location-set
+ * will contain a range location for each non-overlapping match.]
+ * An empty string is considered to match before each character of the
+ * string-value and after the final character. Whitespace in a string
+ * is matched literally, with no normalization except that provided by
+ * XML for line ends. The third argument gives the position of the first
+ * character to be in the resulting range, relative to the start of the
+ * match. The default value is 1, which makes the range start immediately
+ * before the first character of the matched string. The fourth argument
+ * gives the number of characters in the range; the default is that the
+ * range extends to the end of the matched string.
+ *
+ * Element boundaries, as well as entire embedded nodes such as processing
+ * instructions and comments, are ignored as defined in [XPath].
+ *
+ * If the string in the second argument is not found in the string-value
+ * of the location, or if a value in the third or fourth argument indicates
+ * a string that is beyond the beginning or end of the document, the
+ * expression fails.
+ *
+ * The points of the range-locations in the returned location-set will
+ * all be character points.
+ * ------------------------------
+ */
+void
+xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
+    int i, startindex, endindex, fendindex;
+    xmlNodePtr start, end, fend;
+    xmlXPathObjectPtr set;
+    xmlLocationSetPtr oldset;
+    xmlLocationSetPtr newset;
+    xmlXPathObjectPtr string;
+    xmlXPathObjectPtr position = NULL;
+    xmlXPathObjectPtr number = NULL;
+    int found, pos, num;
+
+    /*
+     * Grab the arguments
+     */
+    if ((nargs < 2) || (nargs > 4))
+	XP_ERROR(XPATH_INVALID_ARITY);
+
+    if (nargs >= 4) {
+	CHECK_TYPE(XPATH_NUMBER);
+	number = valuePop(ctxt);
+	if (number != NULL)
+	    num = number->floatval;
+    }
+    if (nargs >= 3) {
+	CHECK_TYPE(XPATH_NUMBER);
+	position = valuePop(ctxt);
+	if (position != NULL)
+	    pos = position->floatval;
+    }
+    CHECK_TYPE(XPATH_STRING);
+    string = valuePop(ctxt);
+    if ((ctxt->value == NULL) ||
+	((ctxt->value->type != XPATH_LOCATIONSET) &&
+	 (ctxt->value->type != XPATH_NODESET)))
+        XP_ERROR(XPATH_INVALID_TYPE)
+
+    set = valuePop(ctxt);
+    if (set->type == XPATH_NODESET) {
+	xmlXPathObjectPtr tmp;
+
+	/*
+	 * First convert to a location set
+	 */
+	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
+	xmlXPathFreeObject(set);
+	set = tmp;
+    }
+    oldset = (xmlLocationSetPtr) set->user;
+
+    /*
+     * The loop is to search for each element in the location set
+     * the list of location set corresponding to that search
+     */
+    newset = xmlXPtrLocationSetCreate(NULL);
+    for (i = 0;i < oldset->locNr;i++) {
+#ifdef DEBUG_RANGES
+	xmlXPathDebugDumpObject(stdout, oldset->locTab[i], 0);
+#endif
+
+	xmlXPtrGetStartPoint(oldset->locTab[i], &start, &startindex);
+	xmlXPtrGetEndPoint(oldset->locTab[i], &end, &endindex);
+	xmlXPtrAdvanceChar(&start, &startindex, 0);
+	xmlXPtrGetLastChar(&end, &endindex);
+
+#ifdef DEBUG_RANGES
+	xmlGenericError(xmlGenericErrorContext,
+		"from index %d of ->", startindex);
+	xmlDebugDumpString(stdout, start->content);
+	xmlGenericError(xmlGenericErrorContext, "\n");
+	xmlGenericError(xmlGenericErrorContext,
+		"to index %d of ->", endindex);
+	xmlDebugDumpString(stdout, end->content);
+	xmlGenericError(xmlGenericErrorContext, "\n");
+#endif
+	do {
+            fend = end;
+            fendindex = endindex;
+	    found = xmlXPtrSearchString(string->stringval, &start, &startindex,
+		                        &fend, &fendindex);
+	    if (found == 1) {
+		if (position == NULL) {
+		    xmlXPtrLocationSetAdd(newset,
+			 xmlXPtrNewRange(start, startindex, fend, fendindex));
+		} else if (xmlXPtrAdvanceChar(&start, &startindex,
+			                      pos - 1) == 0) {
+		    if ((number != NULL) && (num > 0)) {
+			int rindex;
+			xmlNodePtr rend;
+			rend = start;
+			rindex = startindex - 1;
+			if (xmlXPtrAdvanceChar(&rend, &rindex,
+				               num) == 0) {
+			    xmlXPtrLocationSetAdd(newset,
+					xmlXPtrNewRange(start, startindex,
+							rend, rindex));
+			}
+		    } else if ((number != NULL) && (num <= 0)) {
+			xmlXPtrLocationSetAdd(newset,
+				    xmlXPtrNewRange(start, startindex,
+						    start, startindex));
+		    } else {
+			xmlXPtrLocationSetAdd(newset,
+				    xmlXPtrNewRange(start, startindex,
+						    fend, fendindex));
+		    }
+		}
+		start = fend;
+		startindex = fendindex;
+		if (string->stringval[0] == 0)
+		    startindex++;
+	    }
+	} while (found == 1);
+    }
+
+    /*
+     * Save the new value and cleanup
+     */
+    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+    xmlXPathFreeObject(set);
+    xmlXPathFreeObject(string);
+    if (position) xmlXPathFreeObject(position);
+    if (number) xmlXPathFreeObject(number);
+}
+
+/**
+ * xmlXPtrEvalRangePredicate:
+ * @ctxt:  the XPointer Parser context
+ *
+ *  [8]   Predicate ::=   '[' PredicateExpr ']'
+ *  [9]   PredicateExpr ::=   Expr 
+ *
+ * Evaluate a predicate as in xmlXPathEvalPredicate() but for
+ * a Location Set instead of a node set
+ */
+void
+xmlXPtrEvalRangePredicate(xmlXPathParserContextPtr ctxt) {
+    const xmlChar *cur;
+    xmlXPathObjectPtr res;
+    xmlXPathObjectPtr obj, tmp;
+    xmlLocationSetPtr newset = NULL;
+    xmlLocationSetPtr oldset;
+    int i;
+
+    SKIP_BLANKS;
+    if (CUR != '[') {
+	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
+    }
+    NEXT;
+    SKIP_BLANKS;
+
+    /*
+     * Extract the old set, and then evaluate the result of the
+     * expression for all the element in the set. use it to grow
+     * up a new set.
+     */
+    CHECK_TYPE(XPATH_LOCATIONSET);
+    obj = valuePop(ctxt);
+    oldset = obj->user;
+    ctxt->context->node = NULL;
+
+    if ((oldset == NULL) || (oldset->locNr == 0)) {
+	ctxt->context->contextSize = 0;
+	ctxt->context->proximityPosition = 0;
+	xmlXPathEvalExpr(ctxt);
+	res = valuePop(ctxt);
+	if (res != NULL)
+	    xmlXPathFreeObject(res);
+	valuePush(ctxt, obj);
+	CHECK_ERROR;
+    } else {
+	/*
+	 * Save the expression pointer since we will have to evaluate
+	 * it multiple times. Initialize the new set.
+	 */
+        cur = ctxt->cur;
+	newset = xmlXPtrLocationSetCreate(NULL);
+	
+        for (i = 0; i < oldset->locNr; i++) {
+	    ctxt->cur = cur;
+
+	    /*
+	     * Run the evaluation with a node list made of a single item
+	     * in the nodeset.
+	     */
+	    ctxt->context->node = oldset->locTab[i]->user;
+	    tmp = xmlXPathNewNodeSet(ctxt->context->node);
+	    valuePush(ctxt, tmp);
+	    ctxt->context->contextSize = oldset->locNr;
+	    ctxt->context->proximityPosition = i + 1;
+
+	    xmlXPathEvalExpr(ctxt);
+	    CHECK_ERROR;
+
+	    /*
+	     * The result of the evaluation need to be tested to
+	     * decided whether the filter succeeded or not
+	     */
+	    res = valuePop(ctxt);
+	    if (xmlXPathEvaluatePredicateResult(ctxt, res)) {
+	        xmlXPtrLocationSetAdd(newset,
+			xmlXPathObjectCopy(oldset->locTab[i]));
+	    }
+
+	    /*
+	     * Cleanup
+	     */
+	    if (res != NULL)
+		xmlXPathFreeObject(res);
+	    if (ctxt->value == tmp) {
+		res = valuePop(ctxt);
+		xmlXPathFreeObject(res);
+	    }
+	    
+	    ctxt->context->node = NULL;
+	}
+
+	/*
+	 * The result is used as the new evaluation set.
+	 */
+	xmlXPathFreeObject(obj);
+	ctxt->context->node = NULL;
+	ctxt->context->contextSize = -1;
+	ctxt->context->proximityPosition = -1;
+	valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+    }
+    if (CUR != ']') {
+	XP_ERROR(XPATH_INVALID_PREDICATE_ERROR);
+    }
+
+    NEXT;
+    SKIP_BLANKS;
+}
+
+#else
+#endif
+
diff --git a/xpointer.h b/xpointer.h
new file mode 100644
index 0000000..786fb5a
--- /dev/null
+++ b/xpointer.h
@@ -0,0 +1,57 @@
+/*
+ * xpointer.h : API to handle XML Pointers
+ *
+ * World Wide Web Consortium Working Draft 03-March-1998 
+ * http://www.w3.org/TR/1998/WD-xptr-19980303
+ *
+ * See Copyright for the status of this software.
+ *
+ * Daniel.Veillard@w3.org
+ */
+
+#ifndef __XML_XPTR_H__
+#define __XML_XPTR_H__
+
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * A Location Set
+ */
+typedef struct _xmlLocationSet xmlLocationSet;
+typedef xmlLocationSet *xmlLocationSetPtr;
+struct _xmlLocationSet {
+    int locNr;		      /* number of locations in the set */
+    int locMax;		      /* size of the array as allocated */
+    xmlXPathObjectPtr *locTab;/* array of locations */
+};
+
+/*
+ * Handling of location sets
+ */
+
+void			xmlXPtrFreeLocationSet	(xmlLocationSetPtr obj);
+xmlLocationSetPtr	xmlXPtrLocationSetMerge	(xmlLocationSetPtr val1,
+						 xmlLocationSetPtr val2);
+
+/*
+ * Functions
+ */
+xmlXPathContextPtr	xmlXPtrNewContext	(xmlDocPtr doc,
+						 xmlNodePtr here,
+						 xmlNodePtr origin);
+xmlXPathObjectPtr	xmlXPtrEval		(const xmlChar *str,
+						 xmlXPathContextPtr ctx);
+void			xmlXPtrRangeToFunction	(xmlXPathParserContextPtr ctxt,
+       						 int nargs);
+xmlNodePtr		xmlXPtrBuildNodeList	(xmlXPathObjectPtr obj);
+void		xmlXPtrEvalRangePredicate	(xmlXPathParserContextPtr ctxt);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __XML_XPTR_H__ */