Edit

kc3-lang/libxml2/xmlreader.c

Branch :

  • Show log

    Commit

  • Author : Daniel Veillard
    Date : 2009-09-07 11:19:33
    Hash : 76d36458
    Message : Fixing assorted potential problems raised by scan * encoding.c parser.c relaxng.c runsuite.c tree.c xmlreader.c xmlschemas.c: nothing really serious but better safe than sorry

  • xmlreader.c
  • /*
     * xmlreader.c: implements the xmlTextReader streaming node API
     *
     * NOTE:
     *   XmlTextReader.Normalization Property won't be supported, since
     *     it makes the parser non compliant to the XML recommendation
     *
     * See Copyright for the status of this software.
     *
     * daniel@veillard.com
     */
    
    /*
     * TODOs:
     *   - XML Schemas validation
     */
    #define IN_LIBXML
    #include "libxml.h"
    
    #ifdef LIBXML_READER_ENABLED
    #include <string.h> /* for memset() only ! */
    #include <stdarg.h>
    
    #ifdef HAVE_CTYPE_H
    #include <ctype.h>
    #endif
    #ifdef HAVE_STDLIB_H
    #include <stdlib.h>
    #endif
    
    #include <libxml/xmlmemory.h>
    #include <libxml/xmlIO.h>
    #include <libxml/xmlreader.h>
    #include <libxml/parserInternals.h>
    #ifdef LIBXML_SCHEMAS_ENABLED
    #include <libxml/relaxng.h>
    #include <libxml/xmlschemas.h>
    #endif
    #include <libxml/uri.h>
    #ifdef LIBXML_XINCLUDE_ENABLED
    #include <libxml/xinclude.h>
    #endif
    #ifdef LIBXML_PATTERN_ENABLED
    #include <libxml/pattern.h>
    #endif
    
    #define MAX_ERR_MSG_SIZE 64000
    
    /*
     * The following VA_COPY was coded following an example in
     * the Samba project.  It may not be sufficient for some
     * esoteric implementations of va_list (i.e. it may need
     * something involving a memcpy) but (hopefully) will be
     * sufficient for libxml2.
     */
    #ifndef VA_COPY
      #ifdef HAVE_VA_COPY
        #define VA_COPY(dest, src) va_copy(dest, src)
      #else
        #ifdef HAVE___VA_COPY
          #define VA_COPY(dest,src) __va_copy(dest, src)
        #else
          #define VA_COPY(dest,src) (dest) = (src)
        #endif
      #endif
    #endif
    
    /* #define DEBUG_CALLBACKS */
    /* #define DEBUG_READER */
    
    /**
     * TODO:
     *
     * macro to flag unimplemented blocks
     */
    #define TODO								\
        xmlGenericError(xmlGenericErrorContext,				\
    	    "Unimplemented block at %s:%d\n",				\
                __FILE__, __LINE__);
    
    #ifdef DEBUG_READER
    #define DUMP_READER xmlTextReaderDebug(reader);
    #else
    #define DUMP_READER
    #endif
    
    #define CHUNK_SIZE 512
    /************************************************************************
     *									*
     *	The parser: maps the Text Reader API on top of the existing	*
     *		parsing routines building a tree			*
     *									*
     ************************************************************************/
    
    #define XML_TEXTREADER_INPUT	1
    #define XML_TEXTREADER_CTXT	2
    
    typedef enum {
        XML_TEXTREADER_NONE = -1,
        XML_TEXTREADER_START= 0,
        XML_TEXTREADER_ELEMENT= 1,
        XML_TEXTREADER_END= 2,
        XML_TEXTREADER_EMPTY= 3,
        XML_TEXTREADER_BACKTRACK= 4,
        XML_TEXTREADER_DONE= 5,
        XML_TEXTREADER_ERROR= 6
    } xmlTextReaderState;
    
    typedef enum {
        XML_TEXTREADER_NOT_VALIDATE = 0,
        XML_TEXTREADER_VALIDATE_DTD = 1,
        XML_TEXTREADER_VALIDATE_RNG = 2,
        XML_TEXTREADER_VALIDATE_XSD = 4
    } xmlTextReaderValidate;
    
    struct _xmlTextReader {
        int				mode;	/* the parsing mode */
        xmlDocPtr			doc;    /* when walking an existing doc */
        xmlTextReaderValidate       validate;/* is there any validation */
        int				allocs;	/* what structure were deallocated */
        xmlTextReaderState		state;
        xmlParserCtxtPtr		ctxt;	/* the parser context */
        xmlSAXHandlerPtr		sax;	/* the parser SAX callbacks */
        xmlParserInputBufferPtr	input;	/* the input */
        startElementSAXFunc		startElement;/* initial SAX callbacks */
        endElementSAXFunc		endElement;  /* idem */
        startElementNsSAX2Func	startElementNs;/* idem */
        endElementNsSAX2Func	endElementNs;  /* idem */
        charactersSAXFunc		characters;
        cdataBlockSAXFunc		cdataBlock;
        unsigned int		base;	/* base of the segment in the input */
        unsigned int		cur;	/* current position in the input */
        xmlNodePtr			node;	/* current node */
        xmlNodePtr			curnode;/* current attribute node */
        int				depth;  /* depth of the current node */
        xmlNodePtr			faketext;/* fake xmlNs chld */
        int				preserve;/* preserve the resulting document */
        xmlBufferPtr		buffer; /* used to return const xmlChar * */
        xmlDictPtr			dict;	/* the context dictionnary */
    
        /* entity stack when traversing entities content */
        xmlNodePtr         ent;          /* Current Entity Ref Node */
        int                entNr;        /* Depth of the entities stack */
        int                entMax;       /* Max depth of the entities stack */
        xmlNodePtr        *entTab;       /* array of entities */
    
        /* error handling */
        xmlTextReaderErrorFunc errorFunc;    /* callback function */
        void                  *errorFuncArg; /* callback function user argument */
    
    #ifdef LIBXML_SCHEMAS_ENABLED
        /* Handling of RelaxNG validation */
        xmlRelaxNGPtr          rngSchemas;	/* The Relax NG schemas */
        xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */
        int                    rngValidErrors;/* The number of errors detected */
        xmlNodePtr             rngFullNode;	/* the node if RNG not progressive */
        /* Handling of Schemas validation */
        xmlSchemaPtr          xsdSchemas;	/* The Schemas schemas */
        xmlSchemaValidCtxtPtr xsdValidCtxt;/* The Schemas validation context */
        int                   xsdPreserveCtxt; /* 1 if the context was provided by the user */
        int                   xsdValidErrors;/* The number of errors detected */
        xmlSchemaSAXPlugPtr   xsdPlug;	/* the schemas plug in SAX pipeline */
    #endif
    #ifdef LIBXML_XINCLUDE_ENABLED
        /* Handling of XInclude processing */
        int                xinclude;	/* is xinclude asked for */
        const xmlChar *    xinclude_name;	/* the xinclude name from dict */
        xmlXIncludeCtxtPtr xincctxt;	/* the xinclude context */
        int                in_xinclude;	/* counts for xinclude */
    #endif
    #ifdef LIBXML_PATTERN_ENABLED
        int                patternNr;       /* number of preserve patterns */
        int                patternMax;      /* max preserve patterns */
        xmlPatternPtr     *patternTab;      /* array of preserve patterns */
    #endif
        int                preserves;	/* level of preserves */
        int                parserFlags;	/* the set of options set */
        /* Structured error handling */
        xmlStructuredErrorFunc sErrorFunc;  /* callback function */
    };
    
    #define NODE_IS_EMPTY		0x1
    #define NODE_IS_PRESERVED	0x2
    #define NODE_IS_SPRESERVED	0x4
    
    /**
     * CONSTSTR:
     *
     * Macro used to return an interned string
     */
    #define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1)
    #define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str))
    
    static int xmlTextReaderReadTree(xmlTextReaderPtr reader);
    static int xmlTextReaderNextTree(xmlTextReaderPtr reader);
    
    /************************************************************************
     *									*
     *	Our own version of the freeing routines as we recycle nodes	*
     *									*
     ************************************************************************/
    /**
     * DICT_FREE:
     * @str:  a string
     *
     * Free a string if it is not owned by the "dict" dictionnary in the
     * current scope
     */
    #define DICT_FREE(str)						\
    	if ((str) && ((!dict) ||				\
    	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
    	    xmlFree((char *)(str));
    
    static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
    static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
    
    /**
     * xmlFreeID:
     * @not:  A id
     *
     * Deallocate the memory used by an id definition
     */
    static void
    xmlFreeID(xmlIDPtr id) {
        xmlDictPtr dict = NULL;
    
        if (id == NULL) return;
    
        if (id->doc != NULL)
            dict = id->doc->dict;
    
        if (id->value != NULL)
    	DICT_FREE(id->value)
        xmlFree(id);
    }
    
    /**
     * xmlTextReaderRemoveID:
     * @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
     */
    static int
    xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
        xmlIDTablePtr table;
        xmlIDPtr id;
        xmlChar *ID;
    
        if (doc == NULL) return(-1);
        if (attr == NULL) return(-1);
        table = (xmlIDTablePtr) doc->ids;
        if (table == NULL)
            return(-1);
    
        ID = xmlNodeListGetString(doc, attr->children, 1);
        if (ID == NULL)
    	return(-1);
        id = xmlHashLookup(table, ID);
        xmlFree(ID);
        if (id == NULL || id->attr != attr) {
    	return(-1);
        }
        id->name = attr->name;
        id->attr = NULL;
        return(0);
    }
    
    /**
     * xmlTextReaderFreeProp:
     * @reader:  the xmlTextReaderPtr used
     * @cur:  the node
     *
     * Free a node.
     */
    static void
    xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
        xmlDictPtr dict;
    
        dict = reader->ctxt->dict;
        if (cur == NULL) return;
    
        if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
    
        /* Check for ID removal -> leading to invalid references ! */
        if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
    	((cur->parent->doc->intSubset != NULL) ||
    	 (cur->parent->doc->extSubset != NULL))) {
            if (xmlIsID(cur->parent->doc, cur->parent, cur))
    	    xmlTextReaderRemoveID(cur->parent->doc, cur);
        }
        if (cur->children != NULL)
            xmlTextReaderFreeNodeList(reader, cur->children);
    
        DICT_FREE(cur->name);
        if ((reader != NULL) && (reader->ctxt != NULL) &&
            (reader->ctxt->freeAttrsNr < 100)) {
            cur->next = reader->ctxt->freeAttrs;
    	reader->ctxt->freeAttrs = cur;
    	reader->ctxt->freeAttrsNr++;
        } else {
    	xmlFree(cur);
        }
    }
    
    /**
     * xmlTextReaderFreePropList:
     * @reader:  the xmlTextReaderPtr used
     * @cur:  the first property in the list
     *
     * Free a property and all its siblings, all the children are freed too.
     */
    static void
    xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
        xmlAttrPtr next;
        if (cur == NULL) return;
        while (cur != NULL) {
            next = cur->next;
            xmlTextReaderFreeProp(reader, cur);
    	cur = next;
        }
    }
    
    /**
     * xmlTextReaderFreeNodeList:
     * @reader:  the xmlTextReaderPtr used
     * @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.
     */
    static void
    xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
        xmlNodePtr next;
        xmlDictPtr dict;
    
        dict = reader->ctxt->dict;
        if (cur == NULL) return;
        if (cur->type == XML_NAMESPACE_DECL) {
    	xmlFreeNsList((xmlNsPtr) cur);
    	return;
        }
        if ((cur->type == XML_DOCUMENT_NODE) ||
    	(cur->type == XML_HTML_DOCUMENT_NODE)) {
    	xmlFreeDoc((xmlDocPtr) cur);
    	return;
        }
        while (cur != NULL) {
            next = cur->next;
    	/* unroll to speed up freeing the document */
    	if (cur->type != XML_DTD_NODE) {
    
    	    if ((cur->children != NULL) &&
    		(cur->type != XML_ENTITY_REF_NODE)) {
    		if (cur->children->parent == cur)
    		    xmlTextReaderFreeNodeList(reader, cur->children);
    		cur->children = NULL;
    	    }
    
    	    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    		xmlDeregisterNodeDefaultValue(cur);
    
    	    if (((cur->type == XML_ELEMENT_NODE) ||
    		 (cur->type == XML_XINCLUDE_START) ||
    		 (cur->type == XML_XINCLUDE_END)) &&
    		(cur->properties != NULL))
    		xmlTextReaderFreePropList(reader, cur->properties);
    	    if ((cur->content != (xmlChar *) &(cur->properties)) &&
    	        (cur->type != XML_ELEMENT_NODE) &&
    		(cur->type != XML_XINCLUDE_START) &&
    		(cur->type != XML_XINCLUDE_END) &&
    		(cur->type != XML_ENTITY_REF_NODE)) {
    		DICT_FREE(cur->content);
    	    }
    	    if (((cur->type == XML_ELEMENT_NODE) ||
    	         (cur->type == XML_XINCLUDE_START) ||
    		 (cur->type == XML_XINCLUDE_END)) &&
    		(cur->nsDef != NULL))
    		xmlFreeNsList(cur->nsDef);
    
    	    /*
    	     * we don't free element names here they are interned now
    	     */
    	    if ((cur->type != XML_TEXT_NODE) &&
    		(cur->type != XML_COMMENT_NODE))
    		DICT_FREE(cur->name);
    	    if (((cur->type == XML_ELEMENT_NODE) ||
    		 (cur->type == XML_TEXT_NODE)) &&
    	        (reader != NULL) && (reader->ctxt != NULL) &&
    		(reader->ctxt->freeElemsNr < 100)) {
    	        cur->next = reader->ctxt->freeElems;
    		reader->ctxt->freeElems = cur;
    		reader->ctxt->freeElemsNr++;
    	    } else {
    		xmlFree(cur);
    	    }
    	}
    	cur = next;
        }
    }
    
    /**
     * xmlTextReaderFreeNode:
     * @reader:  the xmlTextReaderPtr used
     * @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.
     */
    static void
    xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
        xmlDictPtr dict;
    
        dict = reader->ctxt->dict;
        if (cur->type == XML_DTD_NODE) {
    	xmlFreeDtd((xmlDtdPtr) cur);
    	return;
        }
        if (cur->type == XML_NAMESPACE_DECL) {
    	xmlFreeNs((xmlNsPtr) cur);
            return;
        }
        if (cur->type == XML_ATTRIBUTE_NODE) {
    	xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
    	return;
        }
    
        if ((cur->children != NULL) &&
    	(cur->type != XML_ENTITY_REF_NODE)) {
    	if (cur->children->parent == cur)
    	    xmlTextReaderFreeNodeList(reader, cur->children);
    	cur->children = NULL;
        }
    
        if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    	xmlDeregisterNodeDefaultValue(cur);
    
        if (((cur->type == XML_ELEMENT_NODE) ||
    	 (cur->type == XML_XINCLUDE_START) ||
    	 (cur->type == XML_XINCLUDE_END)) &&
    	(cur->properties != NULL))
    	xmlTextReaderFreePropList(reader, cur->properties);
        if ((cur->content != (xmlChar *) &(cur->properties)) &&
            (cur->type != XML_ELEMENT_NODE) &&
    	(cur->type != XML_XINCLUDE_START) &&
    	(cur->type != XML_XINCLUDE_END) &&
    	(cur->type != XML_ENTITY_REF_NODE)) {
    	DICT_FREE(cur->content);
        }
        if (((cur->type == XML_ELEMENT_NODE) ||
    	 (cur->type == XML_XINCLUDE_START) ||
    	 (cur->type == XML_XINCLUDE_END)) &&
    	(cur->nsDef != NULL))
    	xmlFreeNsList(cur->nsDef);
    
        /*
         * we don't free names here they are interned now
         */
        if ((cur->type != XML_TEXT_NODE) &&
            (cur->type != XML_COMMENT_NODE))
    	DICT_FREE(cur->name);
    
        if (((cur->type == XML_ELEMENT_NODE) ||
    	 (cur->type == XML_TEXT_NODE)) &&
    	(reader != NULL) && (reader->ctxt != NULL) &&
    	(reader->ctxt->freeElemsNr < 100)) {
    	cur->next = reader->ctxt->freeElems;
    	reader->ctxt->freeElems = cur;
    	reader->ctxt->freeElemsNr++;
        } else {
    	xmlFree(cur);
        }
    }
    
    /**
     * xmlTextReaderFreeIDTable:
     * @table:  An id table
     *
     * Deallocate the memory used by an ID hash table.
     */
    static void
    xmlTextReaderFreeIDTable(xmlIDTablePtr table) {
        xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
    }
    
    /**
     * xmlTextReaderFreeDoc:
     * @reader:  the xmlTextReaderPtr used
     * @cur:  pointer to the document
     *
     * Free up all the structures used by a document, tree included.
     */
    static void
    xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
        xmlDtdPtr extSubset, intSubset;
    
        if (cur == NULL) return;
    
        if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
    
        /*
         * Do this before freeing the children list to avoid ID lookups
         */
        if (cur->ids != NULL) xmlTextReaderFreeIDTable((xmlIDTablePtr) cur->ids);
        cur->ids = NULL;
        if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
        cur->refs = NULL;
        extSubset = cur->extSubset;
        intSubset = cur->intSubset;
        if (intSubset == extSubset)
    	extSubset = NULL;
        if (extSubset != NULL) {
    	xmlUnlinkNode((xmlNodePtr) cur->extSubset);
    	cur->extSubset = NULL;
    	xmlFreeDtd(extSubset);
        }
        if (intSubset != NULL) {
    	xmlUnlinkNode((xmlNodePtr) cur->intSubset);
    	cur->intSubset = NULL;
    	xmlFreeDtd(intSubset);
        }
    
        if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
    
        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->oldNs != NULL) xmlFreeNsList(cur->oldNs);
        if (cur->URL != NULL) xmlFree((char *) cur->URL);
        if (cur->dict != NULL) xmlDictFree(cur->dict);
    
        xmlFree(cur);
    }
    
    /************************************************************************
     *									*
     *			The reader core parser				*
     *									*
     ************************************************************************/
    #ifdef DEBUG_READER
    static void
    xmlTextReaderDebug(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->ctxt == NULL)) {
    	fprintf(stderr, "xmlTextReader NULL\n");
    	return;
        }
        fprintf(stderr, "xmlTextReader: state %d depth %d ",
    	    reader->state, reader->depth);
        if (reader->node == NULL) {
    	fprintf(stderr, "node = NULL\n");
        } else {
    	fprintf(stderr, "node %s\n", reader->node->name);
        }
        fprintf(stderr, "  input: base %d, cur %d, depth %d: ",
    	    reader->base, reader->cur, reader->ctxt->nodeNr);
        if (reader->input->buffer == NULL) {
    	fprintf(stderr, "buffer is NULL\n");
        } else {
    #ifdef LIBXML_DEBUG_ENABLED
    	xmlDebugDumpString(stderr,
    		&reader->input->buffer->content[reader->cur]);
    #endif
    	fprintf(stderr, "\n");
        }
    }
    #endif
    
    /**
     * xmlTextReaderEntPush:
     * @reader:  the xmlTextReaderPtr used
     * @value:  the entity reference node
     *
     * Pushes a new entity reference node on top of the entities stack
     *
     * Returns 0 in case of error, the index in the stack otherwise
     */
    static int
    xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
    {
        if (reader->entMax <= 0) {
    	reader->entMax = 10;
    	reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
    		                                  sizeof(reader->entTab[0]));
            if (reader->entTab == NULL) {
                xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
                return (0);
            }
        }
        if (reader->entNr >= reader->entMax) {
            reader->entMax *= 2;
            reader->entTab =
                (xmlNodePtr *) xmlRealloc(reader->entTab,
                                          reader->entMax *
                                          sizeof(reader->entTab[0]));
            if (reader->entTab == NULL) {
                xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
                return (0);
            }
        }
        reader->entTab[reader->entNr] = value;
        reader->ent = value;
        return (reader->entNr++);
    }
    
    /**
     * xmlTextReaderEntPop:
     * @reader:  the xmlTextReaderPtr used
     *
     * Pops the top element entity from the entities stack
     *
     * Returns the entity just removed
     */
    static xmlNodePtr
    xmlTextReaderEntPop(xmlTextReaderPtr reader)
    {
        xmlNodePtr ret;
    
        if (reader->entNr <= 0)
            return (NULL);
        reader->entNr--;
        if (reader->entNr > 0)
            reader->ent = reader->entTab[reader->entNr - 1];
        else
            reader->ent = NULL;
        ret = reader->entTab[reader->entNr];
        reader->entTab[reader->entNr] = NULL;
        return (ret);
    }
    
    /**
     * xmlTextReaderStartElement:
     * @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.
     */
    static void
    xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
    	                  const xmlChar **atts) {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderStartElement(%s)\n", fullname);
    #endif
        if ((reader != NULL) && (reader->startElement != NULL)) {
    	reader->startElement(ctx, fullname, atts);
    	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
    	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
    	    (ctxt->input->cur[1] == '>'))
    	    ctxt->node->extra = NODE_IS_EMPTY;
        }
        if (reader != NULL)
    	reader->state = XML_TEXTREADER_ELEMENT;
    }
    
    /**
     * xmlTextReaderEndElement:
     * @ctx: the user data (XML parser context)
     * @fullname:  The element name, including namespace prefix
     *
     * called when an ending tag has been processed.
     */
    static void
    xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderEndElement(%s)\n", fullname);
    #endif
        if ((reader != NULL) && (reader->endElement != NULL)) {
    	reader->endElement(ctx, fullname);
        }
    }
    
    /**
     * xmlTextReaderStartElementNs:
     * @ctx: the user data (XML parser context)
     * @localname:  the local name of the element
     * @prefix:  the element namespace prefix if available
     * @URI:  the element namespace name if available
     * @nb_namespaces:  number of namespace definitions on that node
     * @namespaces:  pointer to the array of prefix/URI pairs namespace definitions
     * @nb_attributes:  the number of attributes on that node
     * nb_defaulted:  the number of defaulted attributes.
     * @attributes:  pointer to the array of (localname/prefix/URI/value/end)
     *               attribute values.
     *
     * called when an opening tag has been processed.
     */
    static void
    xmlTextReaderStartElementNs(void *ctx,
                          const xmlChar *localname,
    		      const xmlChar *prefix,
    		      const xmlChar *URI,
    		      int nb_namespaces,
    		      const xmlChar **namespaces,
    		      int nb_attributes,
    		      int nb_defaulted,
    		      const xmlChar **attributes)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderStartElementNs(%s)\n", localname);
    #endif
        if ((reader != NULL) && (reader->startElementNs != NULL)) {
    	reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
    	                       namespaces, nb_attributes, nb_defaulted,
    			       attributes);
    	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
    	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
    	    (ctxt->input->cur[1] == '>'))
    	    ctxt->node->extra = NODE_IS_EMPTY;
        }
        if (reader != NULL)
    	reader->state = XML_TEXTREADER_ELEMENT;
    }
    
    /**
     * xmlTextReaderEndElementNs:
     * @ctx: the user data (XML parser context)
     * @localname:  the local name of the element
     * @prefix:  the element namespace prefix if available
     * @URI:  the element namespace name if available
     *
     * called when an ending tag has been processed.
     */
    static void
    xmlTextReaderEndElementNs(void *ctx,
                              const xmlChar * localname,
                              const xmlChar * prefix,
    		          const xmlChar * URI)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderEndElementNs(%s)\n", localname);
    #endif
        if ((reader != NULL) && (reader->endElementNs != NULL)) {
    	reader->endElementNs(ctx, localname, prefix, URI);
        }
    }
    
    
    /**
     * xmlTextReaderCharacters:
     * @ctx: the user data (XML parser context)
     * @ch:  a xmlChar string
     * @len: the number of xmlChar
     *
     * receiving some chars from the parser.
     */
    static void
    xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderCharacters()\n");
    #endif
        if ((reader != NULL) && (reader->characters != NULL)) {
    	reader->characters(ctx, ch, len);
        }
    }
    
    /**
     * xmlTextReaderCDataBlock:
     * @ctx: the user data (XML parser context)
     * @value:  The pcdata content
     * @len:  the block length
     *
     * called when a pcdata block has been parsed
     */
    static void
    xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
    {
        xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderCDataBlock()\n");
    #endif
        if ((reader != NULL) && (reader->cdataBlock != NULL)) {
    	reader->cdataBlock(ctx, ch, len);
        }
    }
    
    /**
     * xmlTextReaderPushData:
     * @reader:  the xmlTextReaderPtr used
     *
     * Push data down the progressive parser until a significant callback
     * got raised.
     *
     * Returns -1 in case of failure, 0 otherwise
     */
    static int
    xmlTextReaderPushData(xmlTextReaderPtr reader) {
        xmlBufferPtr inbuf;
        int val, s;
        xmlTextReaderState oldstate;
    
        if ((reader->input == NULL) || (reader->input->buffer == NULL))
    	return(-1);
    
        oldstate = reader->state;
        reader->state = XML_TEXTREADER_NONE;
        inbuf = reader->input->buffer;
    
        while (reader->state == XML_TEXTREADER_NONE) {
    	if (inbuf->use < reader->cur + CHUNK_SIZE) {
    	    /*
    	     * Refill the buffer unless we are at the end of the stream
    	     */
    	    if (reader->mode != XML_TEXTREADER_MODE_EOF) {
    		val = xmlParserInputBufferRead(reader->input, 4096);
    		if ((val == 0) &&
    		    (inbuf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) {
    		    if (inbuf->use == reader->cur) {
    			reader->mode = XML_TEXTREADER_MODE_EOF;
    			reader->state = oldstate;
    		    }
    		} else if (val < 0) {
    		    reader->mode = XML_TEXTREADER_MODE_EOF;
    		    reader->state = oldstate;
    		    if ((oldstate != XML_TEXTREADER_START) ||
    			(reader->ctxt->myDoc != NULL))
    			return(val);
    		} else if (val == 0) {
    		    /* mark the end of the stream and process the remains */
    		    reader->mode = XML_TEXTREADER_MODE_EOF;
    		    break;
    		}
    
    	    } else
    		break;
    	}
    	/*
    	 * parse by block of CHUNK_SIZE bytes, various tests show that
    	 * it's the best tradeoff at least on a 1.2GH Duron
    	 */
    	if (inbuf->use >= reader->cur + CHUNK_SIZE) {
    	    val = xmlParseChunk(reader->ctxt,
    		          (const char *) &inbuf->content[reader->cur],
    			  CHUNK_SIZE, 0);
    	    reader->cur += CHUNK_SIZE;
    	    if ((val != 0) || (reader->ctxt->wellFormed == 0))
    		return(-1);
    	} else {
    	    s = inbuf->use - reader->cur;
    	    val = xmlParseChunk(reader->ctxt,
    		          (const char *) &inbuf->content[reader->cur],
    			  s, 0);
    	    reader->cur += s;
    	    if ((val != 0) || (reader->ctxt->wellFormed == 0))
    		return(-1);
    	    break;
    	}
        }
    
        /*
         * Discard the consumed input when needed and possible
         */
        if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
            if (inbuf->alloc != XML_BUFFER_ALLOC_IMMUTABLE) {
    	    if ((reader->cur >= 4096) &&
    		(inbuf->use - reader->cur <= CHUNK_SIZE)) {
    		val = xmlBufferShrink(inbuf, reader->cur);
    		if (val >= 0) {
    		    reader->cur -= val;
    		}
    	    }
    	}
        }
    
        /*
         * At the end of the stream signal that the work is done to the Push
         * parser.
         */
        else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
    	if (reader->state != XML_TEXTREADER_DONE) {
    	    s = inbuf->use - reader->cur;
    	    val = xmlParseChunk(reader->ctxt,
    		    (const char *) &inbuf->content[reader->cur],
    		    s, 1);
    	    reader->cur = inbuf->use;
    	    reader->state  = XML_TEXTREADER_DONE;
    	    if ((val != 0) || (reader->ctxt->wellFormed == 0))
    	        return(-1);
    	}
        }
        reader->state = oldstate;
        return(0);
    }
    
    #ifdef LIBXML_REGEXP_ENABLED
    /**
     * xmlTextReaderValidatePush:
     * @reader:  the xmlTextReaderPtr used
     *
     * Push the current node for validation
     */
    static void
    xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
        xmlNodePtr node = reader->node;
    
    #ifdef LIBXML_VALID_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
            (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
    	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
    	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
    				    reader->ctxt->myDoc, node, node->name);
    	} else {
    	    /* TODO use the BuildQName interface */
    	    xmlChar *qname;
    
    	    qname = xmlStrdup(node->ns->prefix);
    	    qname = xmlStrcat(qname, BAD_CAST ":");
    	    qname = xmlStrcat(qname, node->name);
    	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
    				    reader->ctxt->myDoc, node, qname);
    	    if (qname != NULL)
    		xmlFree(qname);
    	}
        }
    #endif /* LIBXML_VALID_ENABLED */
    #ifdef LIBXML_SCHEMAS_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
                   (reader->rngValidCtxt != NULL)) {
    	int ret;
    
    	if (reader->rngFullNode != NULL) return;
    	ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
    	                                    reader->ctxt->myDoc,
    					    node);
    	if (ret == 0) {
    	    /*
    	     * this element requires a full tree
    	     */
    	    node = xmlTextReaderExpand(reader);
    	    if (node == NULL) {
    printf("Expand failed !\n");
    	        ret = -1;
    	    } else {
    		ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
    						    reader->ctxt->myDoc,
    						    node);
    		reader->rngFullNode = node;
    	    }
    	}
    	if (ret != 1)
    	    reader->rngValidErrors++;
        }
    #endif
    }
    
    /**
     * xmlTextReaderValidateCData:
     * @reader:  the xmlTextReaderPtr used
     * @data:  pointer to the CData
     * @len:  lenght of the CData block in bytes.
     *
     * Push some CData for validation
     */
    static void
    xmlTextReaderValidateCData(xmlTextReaderPtr reader,
                               const xmlChar *data, int len) {
    #ifdef LIBXML_VALID_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
            (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
    	reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
    	                                            data, len);
        }
    #endif /* LIBXML_VALID_ENABLED */
    #ifdef LIBXML_SCHEMAS_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
                   (reader->rngValidCtxt != NULL)) {
    	int ret;
    
    	if (reader->rngFullNode != NULL) return;
    	ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
    	if (ret != 1)
    	    reader->rngValidErrors++;
        }
    #endif
    }
    
    /**
     * xmlTextReaderValidatePop:
     * @reader:  the xmlTextReaderPtr used
     *
     * Pop the current node from validation
     */
    static void
    xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
        xmlNodePtr node = reader->node;
    
    #ifdef LIBXML_VALID_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
            (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
    	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
    	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
    				    reader->ctxt->myDoc, node, node->name);
    	} else {
    	    /* TODO use the BuildQName interface */
    	    xmlChar *qname;
    
    	    qname = xmlStrdup(node->ns->prefix);
    	    qname = xmlStrcat(qname, BAD_CAST ":");
    	    qname = xmlStrcat(qname, node->name);
    	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
    				    reader->ctxt->myDoc, node, qname);
    	    if (qname != NULL)
    		xmlFree(qname);
    	}
        }
    #endif /* LIBXML_VALID_ENABLED */
    #ifdef LIBXML_SCHEMAS_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
                   (reader->rngValidCtxt != NULL)) {
    	int ret;
    
    	if (reader->rngFullNode != NULL) {
    	    if (node == reader->rngFullNode)
    	        reader->rngFullNode = NULL;
    	    return;
    	}
    	ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
    	                                   reader->ctxt->myDoc,
    					   node);
    	if (ret != 1)
    	    reader->rngValidErrors++;
        }
    #endif
    }
    
    /**
     * xmlTextReaderValidateEntity:
     * @reader:  the xmlTextReaderPtr used
     *
     * Handle the validation when an entity reference is encountered and
     * entity substitution is not activated. As a result the parser interface
     * must walk through the entity and do the validation calls
     */
    static void
    xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
        xmlNodePtr oldnode = reader->node;
        xmlNodePtr node = reader->node;
        xmlParserCtxtPtr ctxt = reader->ctxt;
    
        do {
    	if (node->type == XML_ENTITY_REF_NODE) {
    	    /*
    	     * Case where the underlying tree is not availble, lookup the entity
    	     * and walk it.
    	     */
    	    if ((node->children == NULL) && (ctxt->sax != NULL) &&
    		(ctxt->sax->getEntity != NULL)) {
    		node->children = (xmlNodePtr)
    		    ctxt->sax->getEntity(ctxt, node->name);
    	    }
    
    	    if ((node->children != NULL) &&
    		(node->children->type == XML_ENTITY_DECL) &&
    		(node->children->children != NULL)) {
    		xmlTextReaderEntPush(reader, node);
    		node = node->children->children;
    		continue;
    	    } else {
    		/*
    		 * The error has probably be raised already.
    		 */
    		if (node == oldnode)
    		    break;
    		node = node->next;
    	    }
    #ifdef LIBXML_REGEXP_ENABLED
    	} else if (node->type == XML_ELEMENT_NODE) {
    	    reader->node = node;
    	    xmlTextReaderValidatePush(reader);
    	} else if ((node->type == XML_TEXT_NODE) ||
    		   (node->type == XML_CDATA_SECTION_NODE)) {
                xmlTextReaderValidateCData(reader, node->content,
    	                               xmlStrlen(node->content));
    #endif
    	}
    
    	/*
    	 * go to next node
    	 */
    	if (node->children != NULL) {
    	    node = node->children;
    	    continue;
    	} else if (node->type == XML_ELEMENT_NODE) {
    	    xmlTextReaderValidatePop(reader);
    	}
    	if (node->next != NULL) {
    	    node = node->next;
    	    continue;
    	}
    	do {
    	    node = node->parent;
    	    if (node->type == XML_ELEMENT_NODE) {
    	        xmlNodePtr tmp;
    		if (reader->entNr == 0) {
    		    while ((tmp = node->last) != NULL) {
    			if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
    			    xmlUnlinkNode(tmp);
    			    xmlTextReaderFreeNode(reader, tmp);
    			} else
    			    break;
    		    }
    		}
    		reader->node = node;
    		xmlTextReaderValidatePop(reader);
    	    }
    	    if ((node->type == XML_ENTITY_DECL) &&
    		(reader->ent != NULL) && (reader->ent->children == node)) {
    		node = xmlTextReaderEntPop(reader);
    	    }
    	    if (node == oldnode)
    		break;
    	    if (node->next != NULL) {
    		node = node->next;
    		break;
    	    }
    	} while ((node != NULL) && (node != oldnode));
        } while ((node != NULL) && (node != oldnode));
        reader->node = oldnode;
    }
    #endif /* LIBXML_REGEXP_ENABLED */
    
    
    /**
     * xmlTextReaderGetSuccessor:
     * @cur:  the current node
     *
     * Get the successor of a node if available.
     *
     * Returns the successor node or NULL
     */
    static xmlNodePtr
    xmlTextReaderGetSuccessor(xmlNodePtr cur) {
        if (cur == NULL) return(NULL) ; /* ERROR */
        if (cur->next != NULL) return(cur->next) ;
        do {
            cur = cur->parent;
            if (cur == NULL) break;
            if (cur->next != NULL) return(cur->next);
        } while (cur != NULL);
        return(cur);
    }
    
    /**
     * xmlTextReaderDoExpand:
     * @reader:  the xmlTextReaderPtr used
     *
     * Makes sure that the current node is fully read as well as all its
     * descendant. It means the full DOM subtree must be available at the
     * end of the call.
     *
     * Returns 1 if the node was expanded successfully, 0 if there is no more
     *          nodes to read, or -1 in case of error
     */
    static int
    xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
        int val;
    
        if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
            return(-1);
        do {
    	if (reader->ctxt->instate == XML_PARSER_EOF) return(1);
    
            if (xmlTextReaderGetSuccessor(reader->node) != NULL)
    	    return(1);
    	if (reader->ctxt->nodeNr < reader->depth)
    	    return(1);
    	if (reader->mode == XML_TEXTREADER_MODE_EOF)
    	    return(1);
    	val = xmlTextReaderPushData(reader);
    	if (val < 0){
    	    reader->mode = XML_TEXTREADER_MODE_ERROR;
    	    return(-1);
    	}
        } while(reader->mode != XML_TEXTREADER_MODE_EOF);
        return(1);
    }
    
    /**
     * xmlTextReaderCollectSiblings:
     * @node:    the first child
     *
     *  Traverse depth-first through all sibling nodes and their children
     *  nodes and concatenate their content. This is an auxiliary function
     *  to xmlTextReaderReadString.
     *
     *  Returns a string containing the content, or NULL in case of error.
     */
    static xmlChar *
    xmlTextReaderCollectSiblings(xmlNodePtr node)
    {
        xmlBufferPtr buffer;
        xmlChar *ret;
    
        buffer = xmlBufferCreate();
        if (buffer == NULL)
           return NULL;
    
        for ( ; node != NULL; node = node->next) {
           switch (node->type) {
           case XML_TEXT_NODE:
           case XML_CDATA_SECTION_NODE:
               xmlBufferCat(buffer, node->content);
               break;
           case XML_ELEMENT_NODE: {
               xmlChar *tmp;
    
    	   tmp = xmlTextReaderCollectSiblings(node->children);
               xmlBufferCat(buffer, tmp);
    	   xmlFree(tmp);
    	   break;
           }
           default:
               break;
           }
        }
        ret = buffer->content;
        buffer->content = NULL;
        xmlBufferFree(buffer);
        return(ret);
    }
    
    /**
     * xmlTextReaderRead:
     * @reader:  the xmlTextReaderPtr used
     *
     *  Moves the position of the current instance to the next node in
     *  the stream, exposing its properties.
     *
     *  Returns 1 if the node was read successfully, 0 if there is no more
     *          nodes to read, or -1 in case of error
     */
    int
    xmlTextReaderRead(xmlTextReaderPtr reader) {
        int val, olddepth = 0;
        xmlTextReaderState oldstate = XML_TEXTREADER_START;
        xmlNodePtr oldnode = NULL;
    
    
        if (reader == NULL)
    	return(-1);
        reader->curnode = NULL;
        if (reader->doc != NULL)
            return(xmlTextReaderReadTree(reader));
        if (reader->ctxt == NULL)
    	return(-1);
        if (reader->ctxt->wellFormed != 1)
    	return(-1);
    
    #ifdef DEBUG_READER
        fprintf(stderr, "\nREAD ");
        DUMP_READER
    #endif
        if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
    	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
    	/*
    	 * Initial state
    	 */
    	do {
    	    val = xmlTextReaderPushData(reader);
    		if (val < 0){
    			reader->mode = XML_TEXTREADER_MODE_ERROR;
    			reader->state = XML_TEXTREADER_ERROR;
    		return(-1);
    		}
    	} while ((reader->ctxt->node == NULL) &&
    		 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
    		  (reader->state != XML_TEXTREADER_DONE)));
    	if (reader->ctxt->node == NULL) {
    	    if (reader->ctxt->myDoc != NULL) {
    		reader->node = reader->ctxt->myDoc->children;
    	    }
    	    if (reader->node == NULL){
    			reader->mode = XML_TEXTREADER_MODE_ERROR;
    			reader->state = XML_TEXTREADER_ERROR;
    		return(-1);
    		}
    	    reader->state = XML_TEXTREADER_ELEMENT;
    	} else {
    	    if (reader->ctxt->myDoc != NULL) {
    		reader->node = reader->ctxt->myDoc->children;
    	    }
    	    if (reader->node == NULL)
    		reader->node = reader->ctxt->nodeTab[0];
    	    reader->state = XML_TEXTREADER_ELEMENT;
    	}
    	reader->depth = 0;
    	reader->ctxt->parseMode = XML_PARSE_READER;
    	goto node_found;
        }
        oldstate = reader->state;
        olddepth = reader->ctxt->nodeNr;
        oldnode = reader->node;
    
    get_next_node:
        if (reader->node == NULL) {
    	if (reader->mode == XML_TEXTREADER_MODE_EOF)
    	    return(0);
    	else
    	    return(-1);
        }
    
        /*
         * If we are not backtracking on ancestors or examined nodes,
         * that the parser didn't finished or that we arent at the end
         * of stream, continue processing.
         */
        while ((reader->node != NULL) && (reader->node->next == NULL) &&
    	   (reader->ctxt->nodeNr == olddepth) &&
               ((oldstate == XML_TEXTREADER_BACKTRACK) ||
                (reader->node->children == NULL) ||
    	    (reader->node->type == XML_ENTITY_REF_NODE) ||
    	    ((reader->node->children != NULL) &&
    	     (reader->node->children->type == XML_TEXT_NODE) &&
    	     (reader->node->children->next == NULL)) ||
    	    (reader->node->type == XML_DTD_NODE) ||
    	    (reader->node->type == XML_DOCUMENT_NODE) ||
    	    (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
    	   ((reader->ctxt->node == NULL) ||
    	    (reader->ctxt->node == reader->node) ||
    	    (reader->ctxt->node == reader->node->parent)) &&
    	   (reader->ctxt->instate != XML_PARSER_EOF)) {
    	val = xmlTextReaderPushData(reader);
    	if (val < 0){
    		reader->mode = XML_TEXTREADER_MODE_ERROR;
    		reader->state = XML_TEXTREADER_ERROR;
    	    return(-1);
    	}
    	if (reader->node == NULL)
    	    goto node_end;
        }
        if (oldstate != XML_TEXTREADER_BACKTRACK) {
    	if ((reader->node->children != NULL) &&
    	    (reader->node->type != XML_ENTITY_REF_NODE) &&
    	    (reader->node->type != XML_XINCLUDE_START) &&
    	    (reader->node->type != XML_DTD_NODE)) {
    	    reader->node = reader->node->children;
    	    reader->depth++;
    	    reader->state = XML_TEXTREADER_ELEMENT;
    	    goto node_found;
    	}
        }
        if (reader->node->next != NULL) {
    	if ((oldstate == XML_TEXTREADER_ELEMENT) &&
                (reader->node->type == XML_ELEMENT_NODE) &&
    	    (reader->node->children == NULL) &&
    	    ((reader->node->extra & NODE_IS_EMPTY) == 0)
    #ifdef LIBXML_XINCLUDE_ENABLED
    	    && (reader->in_xinclude <= 0)
    #endif
    	    ) {
    	    reader->state = XML_TEXTREADER_END;
    	    goto node_found;
    	}
    #ifdef LIBXML_REGEXP_ENABLED
    	if ((reader->validate) &&
    	    (reader->node->type == XML_ELEMENT_NODE))
    	    xmlTextReaderValidatePop(reader);
    #endif /* LIBXML_REGEXP_ENABLED */
            if ((reader->preserves > 0) &&
    	    (reader->node->extra & NODE_IS_SPRESERVED))
    	    reader->preserves--;
    	reader->node = reader->node->next;
    	reader->state = XML_TEXTREADER_ELEMENT;
    
    	/*
    	 * Cleanup of the old node
    	 */
    	if ((reader->preserves == 0) &&
    #ifdef LIBXML_XINCLUDE_ENABLED
    	    (reader->in_xinclude == 0) &&
    #endif
    	    (reader->entNr == 0) &&
    	    (reader->node->prev != NULL) &&
                (reader->node->prev->type != XML_DTD_NODE) &&
    	    (reader->entNr == 0)) {
    	    xmlNodePtr tmp = reader->node->prev;
    	    if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
    		xmlUnlinkNode(tmp);
    		xmlTextReaderFreeNode(reader, tmp);
    	    }
    	}
    
    	goto node_found;
        }
        if ((oldstate == XML_TEXTREADER_ELEMENT) &&
    	(reader->node->type == XML_ELEMENT_NODE) &&
    	(reader->node->children == NULL) &&
    	((reader->node->extra & NODE_IS_EMPTY) == 0)) {;
    	reader->state = XML_TEXTREADER_END;
    	goto node_found;
        }
    #ifdef LIBXML_REGEXP_ENABLED
        if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
    	xmlTextReaderValidatePop(reader);
    #endif /* LIBXML_REGEXP_ENABLED */
        if ((reader->preserves > 0) &&
    	(reader->node->extra & NODE_IS_SPRESERVED))
    	reader->preserves--;
        reader->node = reader->node->parent;
        if ((reader->node == NULL) ||
    	(reader->node->type == XML_DOCUMENT_NODE) ||
    #ifdef LIBXML_DOCB_ENABLED
    	(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
    #endif
    	(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
    	if (reader->mode != XML_TEXTREADER_MODE_EOF) {
    	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
    	    reader->state = XML_TEXTREADER_DONE;
    	    if (val != 0)
    	        return(-1);
    	}
    	reader->node = NULL;
    	reader->depth = -1;
    
    	/*
    	 * Cleanup of the old node
    	 */
    	if ((oldnode != NULL) && (reader->preserves == 0) &&
    #ifdef LIBXML_XINCLUDE_ENABLED
    	    (reader->in_xinclude == 0) &&
    #endif
    	    (reader->entNr == 0) &&
    	    (oldnode->type != XML_DTD_NODE) &&
    	    ((oldnode->extra & NODE_IS_PRESERVED) == 0) &&
    	    (reader->entNr == 0)) {
    	    xmlUnlinkNode(oldnode);
    	    xmlTextReaderFreeNode(reader, oldnode);
    	}
    
    	goto node_end;
        }
        if ((reader->preserves == 0) &&
    #ifdef LIBXML_XINCLUDE_ENABLED
            (reader->in_xinclude == 0) &&
    #endif
    	(reader->entNr == 0) &&
            (reader->node->last != NULL) &&
            ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) {
    	xmlNodePtr tmp = reader->node->last;
    	xmlUnlinkNode(tmp);
    	xmlTextReaderFreeNode(reader, tmp);
        }
        reader->depth--;
        reader->state = XML_TEXTREADER_BACKTRACK;
    
    node_found:
        DUMP_READER
    
        /*
         * If we are in the middle of a piece of CDATA make sure it's finished
         */
        if ((reader->node != NULL) &&
            (reader->node->next == NULL) &&
            ((reader->node->type == XML_TEXT_NODE) ||
    	 (reader->node->type == XML_CDATA_SECTION_NODE))) {
                if (xmlTextReaderExpand(reader) == NULL)
    	        return -1;
        }
    
    #ifdef LIBXML_XINCLUDE_ENABLED
        /*
         * Handle XInclude if asked for
         */
        if ((reader->xinclude) && (reader->node != NULL) &&
    	(reader->node->type == XML_ELEMENT_NODE) &&
    	(reader->node->ns != NULL) &&
    	((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
    	 (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
    	if (reader->xincctxt == NULL) {
    	    reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
    	    xmlXIncludeSetFlags(reader->xincctxt,
    	                        reader->parserFlags & (~XML_PARSE_NOXINCNODE));
    	}
    	/*
    	 * expand that node and process it
    	 */
    	if (xmlTextReaderExpand(reader) == NULL)
    	    return -1;
    	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
        }
        if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
            reader->in_xinclude++;
    	goto get_next_node;
        }
        if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) {
            reader->in_xinclude--;
    	goto get_next_node;
        }
    #endif
        /*
         * Handle entities enter and exit when in entity replacement mode
         */
        if ((reader->node != NULL) &&
    	(reader->node->type == XML_ENTITY_REF_NODE) &&
    	(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
    	/*
    	 * Case where the underlying tree is not availble, lookup the entity
    	 * and walk it.
    	 */
    	if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
    	    (reader->ctxt->sax->getEntity != NULL)) {
    	    reader->node->children = (xmlNodePtr)
    		reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
    	}
    
    	if ((reader->node->children != NULL) &&
    	    (reader->node->children->type == XML_ENTITY_DECL) &&
    	    (reader->node->children->children != NULL)) {
    	    xmlTextReaderEntPush(reader, reader->node);
    	    reader->node = reader->node->children->children;
    	}
    #ifdef LIBXML_REGEXP_ENABLED
        } else if ((reader->node != NULL) &&
    	       (reader->node->type == XML_ENTITY_REF_NODE) &&
    	       (reader->ctxt != NULL) && (reader->validate)) {
    	xmlTextReaderValidateEntity(reader);
    #endif /* LIBXML_REGEXP_ENABLED */
        }
        if ((reader->node != NULL) &&
    	(reader->node->type == XML_ENTITY_DECL) &&
    	(reader->ent != NULL) && (reader->ent->children == reader->node)) {
    	reader->node = xmlTextReaderEntPop(reader);
    	reader->depth++;
            goto get_next_node;
        }
    #ifdef LIBXML_REGEXP_ENABLED
        if ((reader->validate) && (reader->node != NULL)) {
    	xmlNodePtr node = reader->node;
    
    	if ((node->type == XML_ELEMENT_NODE) &&
                ((reader->state != XML_TEXTREADER_END) &&
    	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
    	    xmlTextReaderValidatePush(reader);
    	} else if ((node->type == XML_TEXT_NODE) ||
    		   (node->type == XML_CDATA_SECTION_NODE)) {
                xmlTextReaderValidateCData(reader, node->content,
    	                               xmlStrlen(node->content));
    	}
        }
    #endif /* LIBXML_REGEXP_ENABLED */
    #ifdef LIBXML_PATTERN_ENABLED
        if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
            (reader->state != XML_TEXTREADER_BACKTRACK)) {
            int i;
    	for (i = 0;i < reader->patternNr;i++) {
    	     if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
    	         xmlTextReaderPreserve(reader);
    		 break;
                 }
    	}
        }
    #endif /* LIBXML_PATTERN_ENABLED */
    #ifdef LIBXML_SCHEMAS_ENABLED
        if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) &&
            (reader->xsdValidErrors == 0) &&
    	(reader->xsdValidCtxt != NULL)) {
    	reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt);
        }
    #endif /* LIBXML_PATTERN_ENABLED */
        return(1);
    node_end:
        reader->state = XML_TEXTREADER_DONE;
        return(0);
    }
    
    /**
     * xmlTextReaderReadState:
     * @reader:  the xmlTextReaderPtr used
     *
     * Gets the read state of the reader.
     *
     * Returns the state value, or -1 in case of error
     */
    int
    xmlTextReaderReadState(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        return(reader->mode);
    }
    
    /**
     * xmlTextReaderExpand:
     * @reader:  the xmlTextReaderPtr used
     *
     * Reads the contents of the current node and the full subtree. It then makes
     * the subtree available until the next xmlTextReaderRead() call
     *
     * Returns a node pointer valid until the next xmlTextReaderRead() call
     *         or NULL in case of error.
     */
    xmlNodePtr
    xmlTextReaderExpand(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->node == NULL))
            return(NULL);
        if (reader->doc != NULL)
            return(reader->node);
        if (reader->ctxt == NULL)
            return(NULL);
        if (xmlTextReaderDoExpand(reader) < 0)
            return(NULL);
        return(reader->node);
    }
    
    /**
     * xmlTextReaderNext:
     * @reader:  the xmlTextReaderPtr used
     *
     * Skip to the node following the current one in document order while
     * avoiding the subtree if any.
     *
     * Returns 1 if the node was read successfully, 0 if there is no more
     *          nodes to read, or -1 in case of error
     */
    int
    xmlTextReaderNext(xmlTextReaderPtr reader) {
        int ret;
        xmlNodePtr cur;
    
        if (reader == NULL)
    	return(-1);
        if (reader->doc != NULL)
            return(xmlTextReaderNextTree(reader));
        cur = reader->node;
        if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
            return(xmlTextReaderRead(reader));
        if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK)
            return(xmlTextReaderRead(reader));
        if (cur->extra & NODE_IS_EMPTY)
            return(xmlTextReaderRead(reader));
        do {
            ret = xmlTextReaderRead(reader);
    	if (ret != 1)
    	    return(ret);
        } while (reader->node != cur);
        return(xmlTextReaderRead(reader));
    }
    
    #ifdef LIBXML_WRITER_ENABLED
    /**
     * xmlTextReaderReadInnerXml:
     * @reader:  the xmlTextReaderPtr used
     *
     * Reads the contents of the current node, including child nodes and markup.
     *
     * Returns a string containing the XML content, or NULL if the current node
     *         is neither an element nor attribute, or has no child nodes. The
     *         string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
    {
        xmlChar *resbuf;
        xmlNodePtr node, cur_node;
        xmlBufferPtr buff, buff2;
        xmlDocPtr doc;
    
        if (xmlTextReaderExpand(reader) == NULL) {
            return NULL;
        }
        doc = reader->doc;
        buff = xmlBufferCreate();
        for (cur_node = reader->node->children; cur_node != NULL;
             cur_node = cur_node->next) {
            node = xmlDocCopyNode(cur_node, doc, 1);
            buff2 = xmlBufferCreate();
            if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) {
                xmlFreeNode(node);
                xmlBufferFree(buff2);
                xmlBufferFree(buff);
                return NULL;
            }
            xmlBufferCat(buff, buff2->content);
            xmlFreeNode(node);
            xmlBufferFree(buff2);
        }
        resbuf = buff->content;
        buff->content = NULL;
    
        xmlBufferFree(buff);
        return resbuf;
    }
    #endif
    
    #ifdef LIBXML_WRITER_ENABLED
    /**
     * xmlTextReaderReadOuterXml:
     * @reader:  the xmlTextReaderPtr used
     *
     * Reads the contents of the current node, including child nodes and markup.
     *
     * Returns a string containing the XML content, or NULL if the current node
     *         is neither an element nor attribute, or has no child nodes. The
     *         string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
    {
        xmlChar *resbuf;
        xmlNodePtr node;
        xmlBufferPtr buff;
        xmlDocPtr doc;
    
        node = reader->node;
        doc = reader->doc;
        if (xmlTextReaderExpand(reader) == NULL) {
            return NULL;
        }
        node = xmlDocCopyNode(node, doc, 1);
        buff = xmlBufferCreate();
        if (xmlNodeDump(buff, doc, node, 0, 0) == -1) {
            xmlFreeNode(node);
            xmlBufferFree(buff);
            return NULL;
        }
    
        resbuf = buff->content;
        buff->content = NULL;
    
        xmlFreeNode(node);
        xmlBufferFree(buff);
        return resbuf;
    }
    #endif
    
    /**
     * xmlTextReaderReadString:
     * @reader:  the xmlTextReaderPtr used
     *
     * Reads the contents of an element or a text node as a string.
     *
     * Returns a string containing the contents of the Element or Text node,
     *         or NULL if the reader is positioned on any other type of node.
     *         The string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderReadString(xmlTextReaderPtr reader)
    {
        xmlNodePtr node;
    
        if ((reader == NULL) || (reader->node == NULL))
           return(NULL);
    
        node = (reader->curnode != NULL) ? reader->curnode : reader->node;
        switch (node->type) {
        case XML_TEXT_NODE:
           if (node->content != NULL)
               return(xmlStrdup(node->content));
           break;
        case XML_ELEMENT_NODE:
    	if (xmlTextReaderDoExpand(reader) != -1) {
    	    return xmlTextReaderCollectSiblings(node->children);
    	}
        case XML_ATTRIBUTE_NODE:
    	TODO
    	break;
        default:
           break;
        }
        return(NULL);
    }
    
    #if 0
    /**
     * xmlTextReaderReadBase64:
     * @reader:  the xmlTextReaderPtr used
     * @array:  a byte array to store the content.
     * @offset:  the zero-based index into array where the method should
     *           begin to write.
     * @len:  the number of bytes to write.
     *
     * Reads and decodes the Base64 encoded contents of an element and
     * stores the result in a byte buffer.
     *
     * Returns the number of bytes written to array, or zero if the current
     *         instance is not positioned on an element or -1 in case of error.
     */
    int
    xmlTextReaderReadBase64(xmlTextReaderPtr reader,
                            unsigned char *array ATTRIBUTE_UNUSED,
    	                int offset ATTRIBUTE_UNUSED,
    			int len ATTRIBUTE_UNUSED) {
        if ((reader == NULL) || (reader->ctxt == NULL))
    	return(-1);
        if (reader->ctxt->wellFormed != 1)
    	return(-1);
    
        if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
    	return(0);
        TODO
        return(0);
    }
    
    /**
     * xmlTextReaderReadBinHex:
     * @reader:  the xmlTextReaderPtr used
     * @array:  a byte array to store the content.
     * @offset:  the zero-based index into array where the method should
     *           begin to write.
     * @len:  the number of bytes to write.
     *
     * Reads and decodes the BinHex encoded contents of an element and
     * stores the result in a byte buffer.
     *
     * Returns the number of bytes written to array, or zero if the current
     *         instance is not positioned on an element or -1 in case of error.
     */
    int
    xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
                            unsigned char *array ATTRIBUTE_UNUSED,
    	                int offset ATTRIBUTE_UNUSED,
    			int len ATTRIBUTE_UNUSED) {
        if ((reader == NULL) || (reader->ctxt == NULL))
    	return(-1);
        if (reader->ctxt->wellFormed != 1)
    	return(-1);
    
        if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
    	return(0);
        TODO
        return(0);
    }
    #endif
    
    /************************************************************************
     *									*
     *			Operating on a preparsed tree			*
     *									*
     ************************************************************************/
    static int
    xmlTextReaderNextTree(xmlTextReaderPtr reader)
    {
        if (reader == NULL)
            return(-1);
    
        if (reader->state == XML_TEXTREADER_END)
            return(0);
    
        if (reader->node == NULL) {
            if (reader->doc->children == NULL) {
                reader->state = XML_TEXTREADER_END;
                return(0);
            }
    
            reader->node = reader->doc->children;
            reader->state = XML_TEXTREADER_START;
            return(1);
        }
    
        if (reader->state != XML_TEXTREADER_BACKTRACK) {
    	/* Here removed traversal to child, because we want to skip the subtree,
    	replace with traversal to sibling to skip subtree */
            if (reader->node->next != 0) {
    	    /* Move to sibling if present,skipping sub-tree */
                reader->node = reader->node->next;
                reader->state = XML_TEXTREADER_START;
                return(1);
            }
    
    	/* if reader->node->next is NULL mean no subtree for current node,
    	so need to move to sibling of parent node if present */
            if ((reader->node->type == XML_ELEMENT_NODE) ||
                (reader->node->type == XML_ATTRIBUTE_NODE)) {
                reader->state = XML_TEXTREADER_BACKTRACK;
    	    /* This will move to parent if present */
                xmlTextReaderRead(reader);
            }
        }
    
        if (reader->node->next != 0) {
            reader->node = reader->node->next;
            reader->state = XML_TEXTREADER_START;
            return(1);
        }
    
        if (reader->node->parent != 0) {
            if (reader->node->parent->type == XML_DOCUMENT_NODE) {
                reader->state = XML_TEXTREADER_END;
                return(0);
            }
    
            reader->node = reader->node->parent;
            reader->depth--;
            reader->state = XML_TEXTREADER_BACKTRACK;
    	/* Repeat process to move to sibling of parent node if present */
            xmlTextReaderNextTree(reader);
        }
    
        reader->state = XML_TEXTREADER_END;
    
        return(1);
    }
    
    /**
     * xmlTextReaderReadTree:
     * @reader:  the xmlTextReaderPtr used
     *
     *  Moves the position of the current instance to the next node in
     *  the stream, exposing its properties.
     *
     *  Returns 1 if the node was read successfully, 0 if there is no more
     *          nodes to read, or -1 in case of error
     */
    static int
    xmlTextReaderReadTree(xmlTextReaderPtr reader) {
        if (reader->state == XML_TEXTREADER_END)
            return(0);
    
    next_node:
        if (reader->node == NULL) {
            if (reader->doc->children == NULL) {
                reader->state = XML_TEXTREADER_END;
                return(0);
            }
    
            reader->node = reader->doc->children;
            reader->state = XML_TEXTREADER_START;
            goto found_node;
        }
    
        if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
            (reader->node->type != XML_DTD_NODE) &&
            (reader->node->type != XML_XINCLUDE_START) &&
    	(reader->node->type != XML_ENTITY_REF_NODE)) {
            if (reader->node->children != NULL) {
                reader->node = reader->node->children;
                reader->depth++;
                reader->state = XML_TEXTREADER_START;
                goto found_node;
            }
    
            if (reader->node->type == XML_ATTRIBUTE_NODE) {
                reader->state = XML_TEXTREADER_BACKTRACK;
                goto found_node;
            }
        }
    
        if (reader->node->next != NULL) {
            reader->node = reader->node->next;
            reader->state = XML_TEXTREADER_START;
            goto found_node;
        }
    
        if (reader->node->parent != NULL) {
            if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
    	    (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
                reader->state = XML_TEXTREADER_END;
                return(0);
            }
    
            reader->node = reader->node->parent;
            reader->depth--;
            reader->state = XML_TEXTREADER_BACKTRACK;
            goto found_node;
        }
    
        reader->state = XML_TEXTREADER_END;
    
    found_node:
        if ((reader->node->type == XML_XINCLUDE_START) ||
            (reader->node->type == XML_XINCLUDE_END))
    	goto next_node;
    
        return(1);
    }
    
    /**
     * xmlTextReaderNextSibling:
     * @reader:  the xmlTextReaderPtr used
     *
     * Skip to the node following the current one in document order while
     * avoiding the subtree if any.
     * Currently implemented only for Readers built on a document
     *
     * Returns 1 if the node was read successfully, 0 if there is no more
     *          nodes to read, or -1 in case of error
     */
    int
    xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
        if (reader == NULL)
            return(-1);
        if (reader->doc == NULL) {
            /* TODO */
    	return(-1);
        }
    
        if (reader->state == XML_TEXTREADER_END)
            return(0);
    
        if (reader->node == NULL)
            return(xmlTextReaderNextTree(reader));
    
        if (reader->node->next != NULL) {
            reader->node = reader->node->next;
            reader->state = XML_TEXTREADER_START;
            return(1);
        }
    
        return(0);
    }
    
    /************************************************************************
     *									*
     *			Constructor and destructors			*
     *									*
     ************************************************************************/
    /**
     * xmlNewTextReader:
     * @input: the xmlParserInputBufferPtr used to read data
     * @URI: the URI information for the source if available
     *
     * Create an xmlTextReader structure fed with @input
     *
     * Returns the new xmlTextReaderPtr or NULL in case of error
     */
    xmlTextReaderPtr
    xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
        xmlTextReaderPtr ret;
    
        if (input == NULL)
    	return(NULL);
        ret = xmlMalloc(sizeof(xmlTextReader));
        if (ret == NULL) {
            xmlGenericError(xmlGenericErrorContext,
    		"xmlNewTextReader : malloc failed\n");
    	return(NULL);
        }
        memset(ret, 0, sizeof(xmlTextReader));
        ret->doc = NULL;
        ret->entTab = NULL;
        ret->entMax = 0;
        ret->entNr = 0;
        ret->input = input;
        ret->buffer = xmlBufferCreateSize(100);
        if (ret->buffer == NULL) {
            xmlFree(ret);
            xmlGenericError(xmlGenericErrorContext,
    		"xmlNewTextReader : malloc failed\n");
    	return(NULL);
        }
        ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
        if (ret->sax == NULL) {
    	xmlBufferFree(ret->buffer);
    	xmlFree(ret);
            xmlGenericError(xmlGenericErrorContext,
    		"xmlNewTextReader : malloc failed\n");
    	return(NULL);
        }
        xmlSAXVersion(ret->sax, 2);
        ret->startElement = ret->sax->startElement;
        ret->sax->startElement = xmlTextReaderStartElement;
        ret->endElement = ret->sax->endElement;
        ret->sax->endElement = xmlTextReaderEndElement;
    #ifdef LIBXML_SAX1_ENABLED
        if (ret->sax->initialized == XML_SAX2_MAGIC) {
    #endif /* LIBXML_SAX1_ENABLED */
    	ret->startElementNs = ret->sax->startElementNs;
    	ret->sax->startElementNs = xmlTextReaderStartElementNs;
    	ret->endElementNs = ret->sax->endElementNs;
    	ret->sax->endElementNs = xmlTextReaderEndElementNs;
    #ifdef LIBXML_SAX1_ENABLED
        } else {
    	ret->startElementNs = NULL;
    	ret->endElementNs = NULL;
        }
    #endif /* LIBXML_SAX1_ENABLED */
        ret->characters = ret->sax->characters;
        ret->sax->characters = xmlTextReaderCharacters;
        ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
        ret->cdataBlock = ret->sax->cdataBlock;
        ret->sax->cdataBlock = xmlTextReaderCDataBlock;
    
        ret->mode = XML_TEXTREADER_MODE_INITIAL;
        ret->node = NULL;
        ret->curnode = NULL;
        if (ret->input->buffer->use < 4) {
    	xmlParserInputBufferRead(input, 4);
        }
        if (ret->input->buffer->use >= 4) {
    	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
    			(const char *) ret->input->buffer->content, 4, URI);
    	ret->base = 0;
    	ret->cur = 4;
        } else {
    	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
    	ret->base = 0;
    	ret->cur = 0;
        }
    
        if (ret->ctxt == NULL) {
            xmlGenericError(xmlGenericErrorContext,
    		"xmlNewTextReader : malloc failed\n");
    	xmlBufferFree(ret->buffer);
    	xmlFree(ret->sax);
    	xmlFree(ret);
    	return(NULL);
        }
        ret->ctxt->parseMode = XML_PARSE_READER;
        ret->ctxt->_private = ret;
        ret->ctxt->linenumbers = 1;
        ret->ctxt->dictNames = 1;
        ret->allocs = XML_TEXTREADER_CTXT;
        /*
         * use the parser dictionnary to allocate all elements and attributes names
         */
        ret->ctxt->docdict = 1;
        ret->dict = ret->ctxt->dict;
    #ifdef LIBXML_XINCLUDE_ENABLED
        ret->xinclude = 0;
    #endif
    #ifdef LIBXML_PATTERN_ENABLED
        ret->patternMax = 0;
        ret->patternTab = NULL;
    #endif
        return(ret);
    }
    
    /**
     * xmlNewTextReaderFilename:
     * @URI: the URI of the resource to process
     *
     * Create an xmlTextReader structure fed with the resource at @URI
     *
     * Returns the new xmlTextReaderPtr or NULL in case of error
     */
    xmlTextReaderPtr
    xmlNewTextReaderFilename(const char *URI) {
        xmlParserInputBufferPtr input;
        xmlTextReaderPtr ret;
        char *directory = NULL;
    
        input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
        if (input == NULL)
    	return(NULL);
        ret = xmlNewTextReader(input, URI);
        if (ret == NULL) {
    	xmlFreeParserInputBuffer(input);
    	return(NULL);
        }
        ret->allocs |= XML_TEXTREADER_INPUT;
        if (ret->ctxt->directory == NULL)
            directory = xmlParserGetDirectory(URI);
        if ((ret->ctxt->directory == NULL) && (directory != NULL))
            ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
        if (directory != NULL)
    	xmlFree(directory);
        return(ret);
    }
    
    /**
     * xmlFreeTextReader:
     * @reader:  the xmlTextReaderPtr
     *
     * Deallocate all the resources associated to the reader
     */
    void
    xmlFreeTextReader(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return;
    #ifdef LIBXML_SCHEMAS_ENABLED
        if (reader->rngSchemas != NULL) {
    	xmlRelaxNGFree(reader->rngSchemas);
    	reader->rngSchemas = NULL;
        }
        if (reader->rngValidCtxt != NULL) {
    	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
    	reader->rngValidCtxt = NULL;
        }
        if (reader->xsdPlug != NULL) {
    	xmlSchemaSAXUnplug(reader->xsdPlug);
    	reader->xsdPlug = NULL;
        }
        if (reader->xsdValidCtxt != NULL) {
    	if (! reader->xsdPreserveCtxt)
    	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
    	reader->xsdValidCtxt = NULL;
        }
        if (reader->xsdSchemas != NULL) {
    	xmlSchemaFree(reader->xsdSchemas);
    	reader->xsdSchemas = NULL;
        }
    #endif
    #ifdef LIBXML_XINCLUDE_ENABLED
        if (reader->xincctxt != NULL)
    	xmlXIncludeFreeContext(reader->xincctxt);
    #endif
    #ifdef LIBXML_PATTERN_ENABLED
        if (reader->patternTab != NULL) {
            int i;
    	for (i = 0;i < reader->patternNr;i++) {
    	    if (reader->patternTab[i] != NULL)
    	        xmlFreePattern(reader->patternTab[i]);
    	}
    	xmlFree(reader->patternTab);
        }
    #endif
        if (reader->faketext != NULL) {
    	xmlFreeNode(reader->faketext);
        }
        if (reader->ctxt != NULL) {
            if (reader->dict == reader->ctxt->dict)
    	    reader->dict = NULL;
    	if (reader->ctxt->myDoc != NULL) {
    	    if (reader->preserve == 0)
    		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
    	    reader->ctxt->myDoc = NULL;
    	}
    	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
    	    (reader->ctxt->vctxt.vstateMax > 0)){
    	    xmlFree(reader->ctxt->vctxt.vstateTab);
    	    reader->ctxt->vctxt.vstateTab = NULL;
    	    reader->ctxt->vctxt.vstateMax = 0;
    	}
    	if (reader->allocs & XML_TEXTREADER_CTXT)
    	    xmlFreeParserCtxt(reader->ctxt);
        }
        if (reader->sax != NULL)
    	xmlFree(reader->sax);
        if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
    	xmlFreeParserInputBuffer(reader->input);
        if (reader->buffer != NULL)
            xmlBufferFree(reader->buffer);
        if (reader->entTab != NULL)
    	xmlFree(reader->entTab);
        if (reader->dict != NULL)
            xmlDictFree(reader->dict);
        xmlFree(reader);
    }
    
    /************************************************************************
     *									*
     *			Methods for XmlTextReader			*
     *									*
     ************************************************************************/
    /**
     * xmlTextReaderClose:
     * @reader:  the xmlTextReaderPtr used
     *
     * This method releases any resources allocated by the current instance
     * changes the state to Closed and close any underlying input.
     *
     * Returns 0 or -1 in case of error
     */
    int
    xmlTextReaderClose(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        reader->node = NULL;
        reader->curnode = NULL;
        reader->mode = XML_TEXTREADER_MODE_CLOSED;
        if (reader->ctxt != NULL) {
    	xmlStopParser(reader->ctxt);
    	if (reader->ctxt->myDoc != NULL) {
    	    if (reader->preserve == 0)
    		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
    	    reader->ctxt->myDoc = NULL;
    	}
        }
        if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
    	xmlFreeParserInputBuffer(reader->input);
    	reader->allocs -= XML_TEXTREADER_INPUT;
        }
        return(0);
    }
    
    /**
     * xmlTextReaderGetAttributeNo:
     * @reader:  the xmlTextReaderPtr used
     * @no: the zero-based index of the attribute relative to the containing element
     *
     * Provides the value of the attribute with the specified index relative
     * to the containing element.
     *
     * Returns a string containing the value of the specified attribute, or NULL
     *    in case of error. The string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
        xmlChar *ret;
        int i;
        xmlAttrPtr cur;
        xmlNsPtr ns;
    
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        if (reader->curnode != NULL)
    	return(NULL);
        /* TODO: handle the xmlDecl */
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(NULL);
    
        ns = reader->node->nsDef;
        for (i = 0;(i < no) && (ns != NULL);i++) {
    	ns = ns->next;
        }
        if (ns != NULL)
    	return(xmlStrdup(ns->href));
    
        cur = reader->node->properties;
        if (cur == NULL)
    	return(NULL);
        for (;i < no;i++) {
    	cur = cur->next;
    	if (cur == NULL)
    	    return(NULL);
        }
        /* TODO walk the DTD if present */
    
        ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
        if (ret == NULL) return(xmlStrdup((xmlChar *)""));
        return(ret);
    }
    
    /**
     * xmlTextReaderGetAttribute:
     * @reader:  the xmlTextReaderPtr used
     * @name: the qualified name of the attribute.
     *
     * Provides the value of the attribute with the specified qualified name.
     *
     * Returns a string containing the value of the specified attribute, or NULL
     *    in case of error. The string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
        xmlChar *prefix = NULL;
        xmlChar *localname;
        xmlNsPtr ns;
        xmlChar *ret = NULL;
    
        if ((reader == NULL) || (name == NULL))
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        if (reader->curnode != NULL)
    	return(NULL);
    
        /* TODO: handle the xmlDecl */
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(NULL);
    
        localname = xmlSplitQName2(name, &prefix);
        if (localname == NULL) {
    		/*
    		 * Namespace default decl
    		 */
    		if (xmlStrEqual(name, BAD_CAST "xmlns")) {
    			ns = reader->node->nsDef;
    			while (ns != NULL) {
    				if (ns->prefix == NULL) {
    					return(xmlStrdup(ns->href));
    				}
    				ns = ns->next;
    			}
    			return NULL;
    		}
    		return(xmlGetNoNsProp(reader->node, name));
    	}
    
        /*
         * Namespace default decl
         */
        if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
    		ns = reader->node->nsDef;
    		while (ns != NULL) {
    			if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
    				ret = xmlStrdup(ns->href);
    				break;
    			}
    			ns = ns->next;
    		}
        } else {
    		ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
    		if (ns != NULL)
    			ret = xmlGetNsProp(reader->node, localname, ns->href);
    	}
    
        xmlFree(localname);
        if (prefix != NULL)
            xmlFree(prefix);
        return(ret);
    }
    
    
    /**
     * xmlTextReaderGetAttributeNs:
     * @reader:  the xmlTextReaderPtr used
     * @localName: the local name of the attribute.
     * @namespaceURI: the namespace URI of the attribute.
     *
     * Provides the value of the specified attribute
     *
     * Returns a string containing the value of the specified attribute, or NULL
     *    in case of error. The string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
    			    const xmlChar *namespaceURI) {
        xmlChar *prefix = NULL;
        xmlNsPtr ns;
    
        if ((reader == NULL) || (localName == NULL))
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        if (reader->curnode != NULL)
    	return(NULL);
    
        /* TODO: handle the xmlDecl */
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(NULL);
    
        if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
    		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
    			prefix = BAD_CAST localName;
    		}
    		ns = reader->node->nsDef;
    		while (ns != NULL) {
    			if ((prefix == NULL && ns->prefix == NULL) ||
    				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
    				return xmlStrdup(ns->href);
    			}
    			ns = ns->next;
    		}
    		return NULL;
        }
    
        return(xmlGetNsProp(reader->node, localName, namespaceURI));
    }
    
    /**
     * xmlTextReaderGetRemainder:
     * @reader:  the xmlTextReaderPtr used
     *
     * Method to get the remainder of the buffered XML. this method stops the
     * parser, set its state to End Of File and return the input stream with
     * what is left that the parser did not use.
     *
     * The implementation is not good, the parser certainly procgressed past
     * what's left in reader->input, and there is an allocation problem. Best
     * would be to rewrite it differently.
     *
     * Returns the xmlParserInputBufferPtr attached to the XML or NULL
     *    in case of error.
     */
    xmlParserInputBufferPtr
    xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
        xmlParserInputBufferPtr ret = NULL;
    
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
    
        reader->node = NULL;
        reader->curnode = NULL;
        reader->mode = XML_TEXTREADER_MODE_EOF;
        if (reader->ctxt != NULL) {
    	xmlStopParser(reader->ctxt);
    	if (reader->ctxt->myDoc != NULL) {
    	    if (reader->preserve == 0)
    		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
    	    reader->ctxt->myDoc = NULL;
    	}
        }
        if (reader->allocs & XML_TEXTREADER_INPUT) {
    	ret = reader->input;
    	reader->input = NULL;
    	reader->allocs -= XML_TEXTREADER_INPUT;
        } else {
    	/*
    	 * Hum, one may need to duplicate the data structure because
    	 * without reference counting the input may be freed twice:
    	 *   - by the layer which allocated it.
    	 *   - by the layer to which would have been returned to.
    	 */
    	TODO
    	return(NULL);
        }
        return(ret);
    }
    
    /**
     * xmlTextReaderLookupNamespace:
     * @reader:  the xmlTextReaderPtr used
     * @prefix: the prefix whose namespace URI is to be resolved. To return
     *          the default namespace, specify NULL
     *
     * Resolves a namespace prefix in the scope of the current element.
     *
     * Returns a string containing the namespace URI to which the prefix maps
     *    or NULL in case of error. The string must be deallocated by the caller.
     */
    xmlChar *
    xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
        xmlNsPtr ns;
    
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
    
        ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
        if (ns == NULL)
    	return(NULL);
        return(xmlStrdup(ns->href));
    }
    
    /**
     * xmlTextReaderMoveToAttributeNo:
     * @reader:  the xmlTextReaderPtr used
     * @no: the zero-based index of the attribute relative to the containing
     *      element.
     *
     * Moves the position of the current instance to the attribute with
     * the specified index relative to the containing element.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not found
     */
    int
    xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
        int i;
        xmlAttrPtr cur;
        xmlNsPtr ns;
    
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        /* TODO: handle the xmlDecl */
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(-1);
    
        reader->curnode = NULL;
    
        ns = reader->node->nsDef;
        for (i = 0;(i < no) && (ns != NULL);i++) {
    	ns = ns->next;
        }
        if (ns != NULL) {
    	reader->curnode = (xmlNodePtr) ns;
    	return(1);
        }
    
        cur = reader->node->properties;
        if (cur == NULL)
    	return(0);
        for (;i < no;i++) {
    	cur = cur->next;
    	if (cur == NULL)
    	    return(0);
        }
        /* TODO walk the DTD if present */
    
        reader->curnode = (xmlNodePtr) cur;
        return(1);
    }
    
    /**
     * xmlTextReaderMoveToAttribute:
     * @reader:  the xmlTextReaderPtr used
     * @name: the qualified name of the attribute.
     *
     * Moves the position of the current instance to the attribute with
     * the specified qualified name.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not found
     */
    int
    xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
        xmlChar *prefix = NULL;
        xmlChar *localname;
        xmlNsPtr ns;
        xmlAttrPtr prop;
    
        if ((reader == NULL) || (name == NULL))
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
    
        /* TODO: handle the xmlDecl */
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(0);
    
        localname = xmlSplitQName2(name, &prefix);
        if (localname == NULL) {
    	/*
    	 * Namespace default decl
    	 */
    	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
    	    ns = reader->node->nsDef;
    	    while (ns != NULL) {
    		if (ns->prefix == NULL) {
    		    reader->curnode = (xmlNodePtr) ns;
    		    return(1);
    		}
    		ns = ns->next;
    	    }
    	    return(0);
    	}
    
    	prop = reader->node->properties;
    	while (prop != NULL) {
    	    /*
    	     * One need to have
    	     *   - same attribute names
    	     *   - and the attribute carrying that namespace
    	     */
    	    if ((xmlStrEqual(prop->name, name)) &&
    		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
    		reader->curnode = (xmlNodePtr) prop;
    		return(1);
    	    }
    	    prop = prop->next;
    	}
    	return(0);
        }
    
        /*
         * Namespace default decl
         */
        if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
    	ns = reader->node->nsDef;
    	while (ns != NULL) {
    	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
    		reader->curnode = (xmlNodePtr) ns;
    		goto found;
    	    }
    	    ns = ns->next;
    	}
    	goto not_found;
        }
        prop = reader->node->properties;
        while (prop != NULL) {
    	/*
    	 * One need to have
    	 *   - same attribute names
    	 *   - and the attribute carrying that namespace
    	 */
    	if ((xmlStrEqual(prop->name, localname)) &&
    	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
    	    reader->curnode = (xmlNodePtr) prop;
    	    goto found;
    	}
    	prop = prop->next;
        }
    not_found:
        if (localname != NULL)
            xmlFree(localname);
        if (prefix != NULL)
            xmlFree(prefix);
        return(0);
    
    found:
        if (localname != NULL)
            xmlFree(localname);
        if (prefix != NULL)
            xmlFree(prefix);
        return(1);
    }
    
    /**
     * xmlTextReaderMoveToAttributeNs:
     * @reader:  the xmlTextReaderPtr used
     * @localName:  the local name of the attribute.
     * @namespaceURI:  the namespace URI of the attribute.
     *
     * Moves the position of the current instance to the attribute with the
     * specified local name and namespace URI.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not found
     */
    int
    xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
    	const xmlChar *localName, const xmlChar *namespaceURI) {
        xmlAttrPtr prop;
        xmlNodePtr node;
        xmlNsPtr ns;
        xmlChar *prefix = NULL;
    
        if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(0);
        node = reader->node;
    
        if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
    		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
    			prefix = BAD_CAST localName;
    		}
    		ns = reader->node->nsDef;
    		while (ns != NULL) {
    			if ((prefix == NULL && ns->prefix == NULL) ||
    				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
    				reader->curnode = (xmlNodePtr) ns;
    				return(1);
    			}
    			ns = ns->next;
    		}
    		return(0);
        }
    
        prop = node->properties;
        while (prop != NULL) {
    	/*
    	 * One need to have
    	 *   - same attribute names
    	 *   - and the attribute carrying that namespace
    	 */
            if (xmlStrEqual(prop->name, localName) &&
    	    ((prop->ns != NULL) &&
    	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
    	    reader->curnode = (xmlNodePtr) prop;
    	    return(1);
            }
    	prop = prop->next;
        }
        return(0);
    }
    
    /**
     * xmlTextReaderMoveToFirstAttribute:
     * @reader:  the xmlTextReaderPtr used
     *
     * Moves the position of the current instance to the first attribute
     * associated with the current node.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not found
     */
    int
    xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(0);
    
        if (reader->node->nsDef != NULL) {
    	reader->curnode = (xmlNodePtr) reader->node->nsDef;
    	return(1);
        }
        if (reader->node->properties != NULL) {
    	reader->curnode = (xmlNodePtr) reader->node->properties;
    	return(1);
        }
        return(0);
    }
    
    /**
     * xmlTextReaderMoveToNextAttribute:
     * @reader:  the xmlTextReaderPtr used
     *
     * Moves the position of the current instance to the next attribute
     * associated with the current node.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not found
     */
    int
    xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(0);
        if (reader->curnode == NULL)
    	return(xmlTextReaderMoveToFirstAttribute(reader));
    
        if (reader->curnode->type == XML_NAMESPACE_DECL) {
    	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
    	if (ns->next != NULL) {
    	    reader->curnode = (xmlNodePtr) ns->next;
    	    return(1);
    	}
    	if (reader->node->properties != NULL) {
    	    reader->curnode = (xmlNodePtr) reader->node->properties;
    	    return(1);
    	}
    	return(0);
        } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
    	       (reader->curnode->next != NULL)) {
    	reader->curnode = reader->curnode->next;
    	return(1);
        }
        return(0);
    }
    
    /**
     * xmlTextReaderMoveToElement:
     * @reader:  the xmlTextReaderPtr used
     *
     * Moves the position of the current instance to the node that
     * contains the current Attribute  node.
     *
     * Returns 1 in case of success, -1 in case of error, 0 if not moved
     */
    int
    xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(0);
        if (reader->curnode != NULL) {
    	reader->curnode = NULL;
    	return(1);
        }
        return(0);
    }
    
    /**
     * xmlTextReaderReadAttributeValue:
     * @reader:  the xmlTextReaderPtr used
     *
     * Parses an attribute value into one or more Text and EntityReference nodes.
     *
     * Returns 1 in case of success, 0 if the reader was not positionned on an
     *         ttribute node or all the attribute values have been read, or -1
     *         in case of error.
     */
    int
    xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        if (reader->curnode == NULL)
    	return(0);
        if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
    	if (reader->curnode->children == NULL)
    	    return(0);
    	reader->curnode = reader->curnode->children;
        } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
    	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
    
    	if (reader->faketext == NULL) {
    	    reader->faketext = xmlNewDocText(reader->node->doc,
    		                             ns->href);
    	} else {
                if ((reader->faketext->content != NULL) &&
    	        (reader->faketext->content !=
    		 (xmlChar *) &(reader->faketext->properties)))
    		xmlFree(reader->faketext->content);
    	    reader->faketext->content = xmlStrdup(ns->href);
    	}
    	reader->curnode = reader->faketext;
        } else {
    	if (reader->curnode->next == NULL)
    	    return(0);
    	reader->curnode = reader->curnode->next;
        }
        return(1);
    }
    
    /**
     * xmlTextReaderConstEncoding:
     * @reader:  the xmlTextReaderPtr used
     *
     * Determine the encoding of the document being read.
     *
     * Returns a string containing the encoding of the document or NULL in
     * case of error.  The string is deallocated with the reader.
     */
    const xmlChar *
    xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
        xmlDocPtr doc = NULL;
        if (reader == NULL)
    	return(NULL);
        if (reader->doc != NULL)
            doc = reader->doc;
        else if (reader->ctxt != NULL)
    	doc = reader->ctxt->myDoc;
        if (doc == NULL)
    	return(NULL);
    
        if (doc->encoding == NULL)
    	return(NULL);
        else
          return(CONSTSTR(doc->encoding));
    }
    
    
    /************************************************************************
     *									*
     *			Acces API to the current node			*
     *									*
     ************************************************************************/
    /**
     * xmlTextReaderAttributeCount:
     * @reader:  the xmlTextReaderPtr used
     *
     * Provides the number of attributes of the current node
     *
     * Returns 0 i no attributes, -1 in case of error or the attribute count
     */
    int
    xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
        int ret;
        xmlAttrPtr attr;
        xmlNsPtr ns;
        xmlNodePtr node;
    
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(0);
    
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
    
        if (node->type != XML_ELEMENT_NODE)
    	return(0);
        if ((reader->state == XML_TEXTREADER_END) ||
    	(reader->state == XML_TEXTREADER_BACKTRACK))
    	return(0);
        ret = 0;
        attr = node->properties;
        while (attr != NULL) {
    	ret++;
    	attr = attr->next;
        }
        ns = node->nsDef;
        while (ns != NULL) {
    	ret++;
    	ns = ns->next;
        }
        return(ret);
    }
    
    /**
     * xmlTextReaderNodeType:
     * @reader:  the xmlTextReaderPtr used
     *
     * Get the node type of the current node
     * Reference:
     * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html
     *
     * Returns the xmlNodeType of the current node or -1 in case of error
     */
    int
    xmlTextReaderNodeType(xmlTextReaderPtr reader) {
        xmlNodePtr node;
    
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(XML_READER_TYPE_NONE);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        switch (node->type) {
            case XML_ELEMENT_NODE:
    	    if ((reader->state == XML_TEXTREADER_END) ||
    		(reader->state == XML_TEXTREADER_BACKTRACK))
    		return(XML_READER_TYPE_END_ELEMENT);
    	    return(XML_READER_TYPE_ELEMENT);
            case XML_NAMESPACE_DECL:
            case XML_ATTRIBUTE_NODE:
    	    return(XML_READER_TYPE_ATTRIBUTE);
            case XML_TEXT_NODE:
    	    if (xmlIsBlankNode(reader->node)) {
    		if (xmlNodeGetSpacePreserve(reader->node))
    		    return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
    		else
    		    return(XML_READER_TYPE_WHITESPACE);
    	    } else {
    		return(XML_READER_TYPE_TEXT);
    	    }
            case XML_CDATA_SECTION_NODE:
    	    return(XML_READER_TYPE_CDATA);
            case XML_ENTITY_REF_NODE:
    	    return(XML_READER_TYPE_ENTITY_REFERENCE);
            case XML_ENTITY_NODE:
    	    return(XML_READER_TYPE_ENTITY);
            case XML_PI_NODE:
    	    return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
            case XML_COMMENT_NODE:
    	    return(XML_READER_TYPE_COMMENT);
            case XML_DOCUMENT_NODE:
            case XML_HTML_DOCUMENT_NODE:
    #ifdef LIBXML_DOCB_ENABLED
            case XML_DOCB_DOCUMENT_NODE:
    #endif
    	    return(XML_READER_TYPE_DOCUMENT);
            case XML_DOCUMENT_FRAG_NODE:
    	    return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
            case XML_NOTATION_NODE:
    	    return(XML_READER_TYPE_NOTATION);
            case XML_DOCUMENT_TYPE_NODE:
            case XML_DTD_NODE:
    	    return(XML_READER_TYPE_DOCUMENT_TYPE);
    
            case XML_ELEMENT_DECL:
            case XML_ATTRIBUTE_DECL:
            case XML_ENTITY_DECL:
            case XML_XINCLUDE_START:
            case XML_XINCLUDE_END:
    	    return(XML_READER_TYPE_NONE);
        }
        return(-1);
    }
    
    /**
     * xmlTextReaderIsEmptyElement:
     * @reader:  the xmlTextReaderPtr used
     *
     * Check if the current node is empty
     *
     * Returns 1 if empty, 0 if not and -1 in case of error
     */
    int
    xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->node == NULL))
    	return(-1);
        if (reader->node->type != XML_ELEMENT_NODE)
    	return(0);
        if (reader->curnode != NULL)
    	return(0);
        if (reader->node->children != NULL)
    	return(0);
        if (reader->state == XML_TEXTREADER_END)
    	return(0);
        if (reader->doc != NULL)
            return(1);
    #ifdef LIBXML_XINCLUDE_ENABLED
        if (reader->in_xinclude > 0)
            return(1);
    #endif
        return((reader->node->extra & NODE_IS_EMPTY) != 0);
    }
    
    /**
     * xmlTextReaderLocalName:
     * @reader:  the xmlTextReaderPtr used
     *
     * The local name of the node.
     *
     * Returns the local name or NULL if not available,
     *   if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderLocalName(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        if (node->type == XML_NAMESPACE_DECL) {
    	xmlNsPtr ns = (xmlNsPtr) node;
    	if (ns->prefix == NULL)
    	    return(xmlStrdup(BAD_CAST "xmlns"));
    	else
    	    return(xmlStrdup(ns->prefix));
        }
        if ((node->type != XML_ELEMENT_NODE) &&
    	(node->type != XML_ATTRIBUTE_NODE))
    	return(xmlTextReaderName(reader));
        return(xmlStrdup(node->name));
    }
    
    /**
     * xmlTextReaderConstLocalName:
     * @reader:  the xmlTextReaderPtr used
     *
     * The local name of the node.
     *
     * Returns the local name or NULL if not available, the
     *         string will be deallocated with the reader.
     */
    const xmlChar *
    xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        if (node->type == XML_NAMESPACE_DECL) {
    	xmlNsPtr ns = (xmlNsPtr) node;
    	if (ns->prefix == NULL)
    	    return(CONSTSTR(BAD_CAST "xmlns"));
    	else
    	    return(ns->prefix);
        }
        if ((node->type != XML_ELEMENT_NODE) &&
    	(node->type != XML_ATTRIBUTE_NODE))
    	return(xmlTextReaderConstName(reader));
        return(node->name);
    }
    
    /**
     * xmlTextReaderName:
     * @reader:  the xmlTextReaderPtr used
     *
     * The qualified name of the node, equal to Prefix :LocalName.
     *
     * Returns the local name or NULL if not available,
     *   if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderName(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        xmlChar *ret;
    
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        switch (node->type) {
            case XML_ELEMENT_NODE:
            case XML_ATTRIBUTE_NODE:
    	    if ((node->ns == NULL) ||
    		(node->ns->prefix == NULL))
    		return(xmlStrdup(node->name));
    
    	    ret = xmlStrdup(node->ns->prefix);
    	    ret = xmlStrcat(ret, BAD_CAST ":");
    	    ret = xmlStrcat(ret, node->name);
    	    return(ret);
            case XML_TEXT_NODE:
    	    return(xmlStrdup(BAD_CAST "#text"));
            case XML_CDATA_SECTION_NODE:
    	    return(xmlStrdup(BAD_CAST "#cdata-section"));
            case XML_ENTITY_NODE:
            case XML_ENTITY_REF_NODE:
    	    return(xmlStrdup(node->name));
            case XML_PI_NODE:
    	    return(xmlStrdup(node->name));
            case XML_COMMENT_NODE:
    	    return(xmlStrdup(BAD_CAST "#comment"));
            case XML_DOCUMENT_NODE:
            case XML_HTML_DOCUMENT_NODE:
    #ifdef LIBXML_DOCB_ENABLED
            case XML_DOCB_DOCUMENT_NODE:
    #endif
    	    return(xmlStrdup(BAD_CAST "#document"));
            case XML_DOCUMENT_FRAG_NODE:
    	    return(xmlStrdup(BAD_CAST "#document-fragment"));
            case XML_NOTATION_NODE:
    	    return(xmlStrdup(node->name));
            case XML_DOCUMENT_TYPE_NODE:
            case XML_DTD_NODE:
    	    return(xmlStrdup(node->name));
            case XML_NAMESPACE_DECL: {
    	    xmlNsPtr ns = (xmlNsPtr) node;
    
    	    ret = xmlStrdup(BAD_CAST "xmlns");
    	    if (ns->prefix == NULL)
    		return(ret);
    	    ret = xmlStrcat(ret, BAD_CAST ":");
    	    ret = xmlStrcat(ret, ns->prefix);
    	    return(ret);
    	}
    
            case XML_ELEMENT_DECL:
            case XML_ATTRIBUTE_DECL:
            case XML_ENTITY_DECL:
            case XML_XINCLUDE_START:
            case XML_XINCLUDE_END:
    	    return(NULL);
        }
        return(NULL);
    }
    
    /**
     * xmlTextReaderConstName:
     * @reader:  the xmlTextReaderPtr used
     *
     * The qualified name of the node, equal to Prefix :LocalName.
     *
     * Returns the local name or NULL if not available, the string is
     *         deallocated with the reader.
     */
    const xmlChar *
    xmlTextReaderConstName(xmlTextReaderPtr reader) {
        xmlNodePtr node;
    
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        switch (node->type) {
            case XML_ELEMENT_NODE:
            case XML_ATTRIBUTE_NODE:
    	    if ((node->ns == NULL) ||
    		(node->ns->prefix == NULL))
    		return(node->name);
    	    return(CONSTQSTR(node->ns->prefix, node->name));
            case XML_TEXT_NODE:
    	    return(CONSTSTR(BAD_CAST "#text"));
            case XML_CDATA_SECTION_NODE:
    	    return(CONSTSTR(BAD_CAST "#cdata-section"));
            case XML_ENTITY_NODE:
            case XML_ENTITY_REF_NODE:
    	    return(CONSTSTR(node->name));
            case XML_PI_NODE:
    	    return(CONSTSTR(node->name));
            case XML_COMMENT_NODE:
    	    return(CONSTSTR(BAD_CAST "#comment"));
            case XML_DOCUMENT_NODE:
            case XML_HTML_DOCUMENT_NODE:
    #ifdef LIBXML_DOCB_ENABLED
            case XML_DOCB_DOCUMENT_NODE:
    #endif
    	    return(CONSTSTR(BAD_CAST "#document"));
            case XML_DOCUMENT_FRAG_NODE:
    	    return(CONSTSTR(BAD_CAST "#document-fragment"));
            case XML_NOTATION_NODE:
    	    return(CONSTSTR(node->name));
            case XML_DOCUMENT_TYPE_NODE:
            case XML_DTD_NODE:
    	    return(CONSTSTR(node->name));
            case XML_NAMESPACE_DECL: {
    	    xmlNsPtr ns = (xmlNsPtr) node;
    
    	    if (ns->prefix == NULL)
    		return(CONSTSTR(BAD_CAST "xmlns"));
    	    return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
    	}
    
            case XML_ELEMENT_DECL:
            case XML_ATTRIBUTE_DECL:
            case XML_ENTITY_DECL:
            case XML_XINCLUDE_START:
            case XML_XINCLUDE_END:
    	    return(NULL);
        }
        return(NULL);
    }
    
    /**
     * xmlTextReaderPrefix:
     * @reader:  the xmlTextReaderPtr used
     *
     * A shorthand reference to the namespace associated with the node.
     *
     * Returns the prefix or NULL if not available,
     *    if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderPrefix(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        if (node->type == XML_NAMESPACE_DECL) {
    	xmlNsPtr ns = (xmlNsPtr) node;
    	if (ns->prefix == NULL)
    	    return(NULL);
    	return(xmlStrdup(BAD_CAST "xmlns"));
        }
        if ((node->type != XML_ELEMENT_NODE) &&
    	(node->type != XML_ATTRIBUTE_NODE))
    	return(NULL);
        if ((node->ns != NULL) && (node->ns->prefix != NULL))
    	return(xmlStrdup(node->ns->prefix));
        return(NULL);
    }
    
    /**
     * xmlTextReaderConstPrefix:
     * @reader:  the xmlTextReaderPtr used
     *
     * A shorthand reference to the namespace associated with the node.
     *
     * Returns the prefix or NULL if not available, the string is deallocated
     *         with the reader.
     */
    const xmlChar *
    xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        if (node->type == XML_NAMESPACE_DECL) {
    	xmlNsPtr ns = (xmlNsPtr) node;
    	if (ns->prefix == NULL)
    	    return(NULL);
    	return(CONSTSTR(BAD_CAST "xmlns"));
        }
        if ((node->type != XML_ELEMENT_NODE) &&
    	(node->type != XML_ATTRIBUTE_NODE))
    	return(NULL);
        if ((node->ns != NULL) && (node->ns->prefix != NULL))
    	return(CONSTSTR(node->ns->prefix));
        return(NULL);
    }
    
    /**
     * xmlTextReaderNamespaceUri:
     * @reader:  the xmlTextReaderPtr used
     *
     * The URI defining the namespace associated with the node.
     *
     * Returns the namespace URI or NULL if not available,
     *    if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        if (node->type == XML_NAMESPACE_DECL)
    	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
        if ((node->type != XML_ELEMENT_NODE) &&
    	(node->type != XML_ATTRIBUTE_NODE))
    	return(NULL);
        if (node->ns != NULL)
    	return(xmlStrdup(node->ns->href));
        return(NULL);
    }
    
    /**
     * xmlTextReaderConstNamespaceUri:
     * @reader:  the xmlTextReaderPtr used
     *
     * The URI defining the namespace associated with the node.
     *
     * Returns the namespace URI or NULL if not available, the string
     *         will be deallocated with the reader
     */
    const xmlChar *
    xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
        if (node->type == XML_NAMESPACE_DECL)
    	return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
        if ((node->type != XML_ELEMENT_NODE) &&
    	(node->type != XML_ATTRIBUTE_NODE))
    	return(NULL);
        if (node->ns != NULL)
    	return(CONSTSTR(node->ns->href));
        return(NULL);
    }
    
    /**
     * xmlTextReaderBaseUri:
     * @reader:  the xmlTextReaderPtr used
     *
     * The base URI of the node.
     *
     * Returns the base URI or NULL if not available,
     *    if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        return(xmlNodeGetBase(NULL, reader->node));
    }
    
    /**
     * xmlTextReaderConstBaseUri:
     * @reader:  the xmlTextReaderPtr used
     *
     * The base URI of the node.
     *
     * Returns the base URI or NULL if not available, the string
     *         will be deallocated with the reader
     */
    const xmlChar *
    xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
        xmlChar *tmp;
        const xmlChar *ret;
    
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        tmp = xmlNodeGetBase(NULL, reader->node);
        if (tmp == NULL)
            return(NULL);
        ret = CONSTSTR(tmp);
        xmlFree(tmp);
        return(ret);
    }
    
    /**
     * xmlTextReaderDepth:
     * @reader:  the xmlTextReaderPtr used
     *
     * The depth of the node in the tree.
     *
     * Returns the depth or -1 in case of error
     */
    int
    xmlTextReaderDepth(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(0);
    
        if (reader->curnode != NULL) {
    	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
    	    (reader->curnode->type == XML_NAMESPACE_DECL))
    	    return(reader->depth + 1);
    	return(reader->depth + 2);
        }
        return(reader->depth);
    }
    
    /**
     * xmlTextReaderHasAttributes:
     * @reader:  the xmlTextReaderPtr used
     *
     * Whether the node has attributes.
     *
     * Returns 1 if true, 0 if false, and -1 in case or error
     */
    int
    xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(0);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
    
        if ((node->type == XML_ELEMENT_NODE) &&
    	((node->properties != NULL) || (node->nsDef != NULL)))
    	return(1);
        /* TODO: handle the xmlDecl */
        return(0);
    }
    
    /**
     * xmlTextReaderHasValue:
     * @reader:  the xmlTextReaderPtr used
     *
     * Whether the node can have a text value.
     *
     * Returns 1 if true, 0 if false, and -1 in case or error
     */
    int
    xmlTextReaderHasValue(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(0);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
    
        switch (node->type) {
            case XML_ATTRIBUTE_NODE:
            case XML_TEXT_NODE:
            case XML_CDATA_SECTION_NODE:
            case XML_PI_NODE:
            case XML_COMMENT_NODE:
            case XML_NAMESPACE_DECL:
    	    return(1);
    	default:
    	    break;
        }
        return(0);
    }
    
    /**
     * xmlTextReaderValue:
     * @reader:  the xmlTextReaderPtr used
     *
     * Provides the text value of the node if present
     *
     * Returns the string or NULL if not available. The result must be deallocated
     *     with xmlFree()
     */
    xmlChar *
    xmlTextReaderValue(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
    
        switch (node->type) {
            case XML_NAMESPACE_DECL:
    	    return(xmlStrdup(((xmlNsPtr) node)->href));
            case XML_ATTRIBUTE_NODE:{
    	    xmlAttrPtr attr = (xmlAttrPtr) node;
    
    	    if (attr->parent != NULL)
    		return (xmlNodeListGetString
    			(attr->parent->doc, attr->children, 1));
    	    else
    		return (xmlNodeListGetString(NULL, attr->children, 1));
    	    break;
    	}
            case XML_TEXT_NODE:
            case XML_CDATA_SECTION_NODE:
            case XML_PI_NODE:
            case XML_COMMENT_NODE:
                if (node->content != NULL)
                    return (xmlStrdup(node->content));
    	default:
    	    break;
        }
        return(NULL);
    }
    
    /**
     * xmlTextReaderConstValue:
     * @reader:  the xmlTextReaderPtr used
     *
     * Provides the text value of the node if present
     *
     * Returns the string or NULL if not available. The result will be
     *     deallocated on the next Read() operation.
     */
    const xmlChar *
    xmlTextReaderConstValue(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
    
        switch (node->type) {
            case XML_NAMESPACE_DECL:
    	    return(((xmlNsPtr) node)->href);
            case XML_ATTRIBUTE_NODE:{
    	    xmlAttrPtr attr = (xmlAttrPtr) node;
    
    	    if ((attr->children != NULL) &&
    	        (attr->children->type == XML_TEXT_NODE) &&
    		(attr->children->next == NULL))
    		return(attr->children->content);
    	    else {
    		if (reader->buffer == NULL)
    		    reader->buffer = xmlBufferCreateSize(100);
    		if (reader->buffer == NULL) {
    		    xmlGenericError(xmlGenericErrorContext,
    				    "xmlTextReaderSetup : malloc failed\n");
    		    return (NULL);
    		}
    	        reader->buffer->use = 0;
    	        xmlNodeBufGetContent(reader->buffer, node);
    		return(reader->buffer->content);
    	    }
    	    break;
    	}
            case XML_TEXT_NODE:
            case XML_CDATA_SECTION_NODE:
            case XML_PI_NODE:
            case XML_COMMENT_NODE:
    	    return(node->content);
    	default:
    	    break;
        }
        return(NULL);
    }
    
    /**
     * xmlTextReaderIsDefault:
     * @reader:  the xmlTextReaderPtr used
     *
     * Whether an Attribute  node was generated from the default value
     * defined in the DTD or schema.
     *
     * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
     */
    int
    xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        return(0);
    }
    
    /**
     * xmlTextReaderQuoteChar:
     * @reader:  the xmlTextReaderPtr used
     *
     * The quotation mark character used to enclose the value of an attribute.
     *
     * Returns " or ' and -1 in case of error
     */
    int
    xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        /* TODO maybe lookup the attribute value for " first */
        return((int) '"');
    }
    
    /**
     * xmlTextReaderXmlLang:
     * @reader:  the xmlTextReaderPtr used
     *
     * The xml:lang scope within which the node resides.
     *
     * Returns the xml:lang value or NULL if none exists.,
     *    if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        return(xmlNodeGetLang(reader->node));
    }
    
    /**
     * xmlTextReaderConstXmlLang:
     * @reader:  the xmlTextReaderPtr used
     *
     * The xml:lang scope within which the node resides.
     *
     * Returns the xml:lang value or NULL if none exists.
     */
    const xmlChar *
    xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
        xmlChar *tmp;
        const xmlChar *ret;
    
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        tmp = xmlNodeGetLang(reader->node);
        if (tmp == NULL)
            return(NULL);
        ret = CONSTSTR(tmp);
        xmlFree(tmp);
        return(ret);
    }
    
    /**
     * xmlTextReaderConstString:
     * @reader:  the xmlTextReaderPtr used
     * @str:  the string to intern.
     *
     * Get an interned string from the reader, allows for example to
     * speedup string name comparisons
     *
     * Returns an interned copy of the string or NULL in case of error. The
     *         string will be deallocated with the reader.
     */
    const xmlChar *
    xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
        if (reader == NULL)
    	return(NULL);
        return(CONSTSTR(str));
    }
    
    /**
     * xmlTextReaderNormalization:
     * @reader:  the xmlTextReaderPtr used
     *
     * The value indicating whether to normalize white space and attribute values.
     * Since attribute value and end of line normalizations are a MUST in the XML
     * specification only the value true is accepted. The broken bahaviour of
     * accepting out of range character entities like &#0; is of course not
     * supported either.
     *
     * Returns 1 or -1 in case of error.
     */
    int
    xmlTextReaderNormalization(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(-1);
        return(1);
    }
    
    /************************************************************************
     *									*
     *			Extensions to the base APIs			*
     *									*
     ************************************************************************/
    
    /**
     * xmlTextReaderSetParserProp:
     * @reader:  the xmlTextReaderPtr used
     * @prop:  the xmlParserProperties to set
     * @value:  usually 0 or 1 to (de)activate it
     *
     * Change the parser processing behaviour by changing some of its internal
     * properties. Note that some properties can only be changed before any
     * read has been done.
     *
     * Returns 0 if the call was successful, or -1 in case of error
     */
    int
    xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
        xmlParserProperties p = (xmlParserProperties) prop;
        xmlParserCtxtPtr ctxt;
    
        if ((reader == NULL) || (reader->ctxt == NULL))
    	return(-1);
        ctxt = reader->ctxt;
    
        switch (p) {
            case XML_PARSER_LOADDTD:
    	    if (value != 0) {
    		if (ctxt->loadsubset == 0) {
    		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
    			return(-1);
    		    ctxt->loadsubset = XML_DETECT_IDS;
    		}
    	    } else {
    		ctxt->loadsubset = 0;
    	    }
    	    return(0);
            case XML_PARSER_DEFAULTATTRS:
    	    if (value != 0) {
    		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
    	    } else {
    		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
    		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
    	    }
    	    return(0);
            case XML_PARSER_VALIDATE:
    	    if (value != 0) {
    		ctxt->validate = 1;
    		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
    	    } else {
    		ctxt->validate = 0;
    	    }
    	    return(0);
            case XML_PARSER_SUBST_ENTITIES:
    	    if (value != 0) {
    		ctxt->replaceEntities = 1;
    	    } else {
    		ctxt->replaceEntities = 0;
    	    }
    	    return(0);
        }
        return(-1);
    }
    
    /**
     * xmlTextReaderGetParserProp:
     * @reader:  the xmlTextReaderPtr used
     * @prop:  the xmlParserProperties to get
     *
     * Read the parser internal property.
     *
     * Returns the value, usually 0 or 1, or -1 in case of error.
     */
    int
    xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
        xmlParserProperties p = (xmlParserProperties) prop;
        xmlParserCtxtPtr ctxt;
    
        if ((reader == NULL) || (reader->ctxt == NULL))
    	return(-1);
        ctxt = reader->ctxt;
    
        switch (p) {
            case XML_PARSER_LOADDTD:
    	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
    		return(1);
    	    return(0);
            case XML_PARSER_DEFAULTATTRS:
    	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
    		return(1);
    	    return(0);
            case XML_PARSER_VALIDATE:
    	    return(reader->validate);
    	case XML_PARSER_SUBST_ENTITIES:
    	    return(ctxt->replaceEntities);
        }
        return(-1);
    }
    
    
    /**
     * xmlTextReaderGetParserLineNumber:
     * @reader: the user data (XML reader context)
     *
     * Provide the line number of the current parsing point.
     *
     * Returns an int or 0 if not available
     */
    int
    xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
    {
        if ((reader == NULL) || (reader->ctxt == NULL) ||
            (reader->ctxt->input == NULL)) {
            return (0);
        }
        return (reader->ctxt->input->line);
    }
    
    /**
     * xmlTextReaderGetParserColumnNumber:
     * @reader: the user data (XML reader context)
     *
     * Provide the column number of the current parsing point.
     *
     * Returns an int or 0 if not available
     */
    int
    xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
    {
        if ((reader == NULL) || (reader->ctxt == NULL) ||
            (reader->ctxt->input == NULL)) {
            return (0);
        }
        return (reader->ctxt->input->col);
    }
    
    /**
     * xmlTextReaderCurrentNode:
     * @reader:  the xmlTextReaderPtr used
     *
     * Hacking interface allowing to get the xmlNodePtr correponding to the
     * current node being accessed by the xmlTextReader. This is dangerous
     * because the underlying node may be destroyed on the next Reads.
     *
     * Returns the xmlNodePtr or NULL in case of error.
     */
    xmlNodePtr
    xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(NULL);
    
        if (reader->curnode != NULL)
    	return(reader->curnode);
        return(reader->node);
    }
    
    /**
     * xmlTextReaderPreserve:
     * @reader:  the xmlTextReaderPtr used
     *
     * This tells the XML Reader to preserve the current node.
     * The caller must also use xmlTextReaderCurrentDoc() to
     * keep an handle on the resulting document once parsing has finished
     *
     * Returns the xmlNodePtr or NULL in case of error.
     */
    xmlNodePtr
    xmlTextReaderPreserve(xmlTextReaderPtr reader) {
        xmlNodePtr cur, parent;
    
        if (reader == NULL)
    	return(NULL);
    
        if (reader->curnode != NULL)
            cur = reader->curnode;
        else
            cur = reader->node;
        if (cur == NULL)
            return(NULL);
    
        if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
    	cur->extra |= NODE_IS_PRESERVED;
    	cur->extra |= NODE_IS_SPRESERVED;
        }
        reader->preserves++;
    
        parent = cur->parent;;
        while (parent != NULL) {
            if (parent->type == XML_ELEMENT_NODE)
    	    parent->extra |= NODE_IS_PRESERVED;
    	parent = parent->parent;
        }
        return(cur);
    }
    
    #ifdef LIBXML_PATTERN_ENABLED
    /**
     * xmlTextReaderPreservePattern:
     * @reader:  the xmlTextReaderPtr used
     * @pattern:  an XPath subset pattern
     * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
     *
     * This tells the XML Reader to preserve all nodes matched by the
     * pattern. The caller must also use xmlTextReaderCurrentDoc() to
     * keep an handle on the resulting document once parsing has finished
     *
     * Returns a positive number in case of success and -1 in case of error
     */
    int
    xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
                                 const xmlChar **namespaces)
    {
        xmlPatternPtr comp;
    
        if ((reader == NULL) || (pattern == NULL))
    	return(-1);
    
        comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
        if (comp == NULL)
            return(-1);
    
        if (reader->patternMax <= 0) {
    	reader->patternMax = 4;
    	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
    					      sizeof(reader->patternTab[0]));
            if (reader->patternTab == NULL) {
                xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
                return (-1);
            }
        }
        if (reader->patternNr >= reader->patternMax) {
            xmlPatternPtr *tmp;
            reader->patternMax *= 2;
    	tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
                                          reader->patternMax *
                                          sizeof(reader->patternTab[0]));
            if (tmp == NULL) {
                xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
    	    reader->patternMax /= 2;
                return (-1);
            }
    	reader->patternTab = tmp;
        }
        reader->patternTab[reader->patternNr] = comp;
        return(reader->patternNr++);
    }
    #endif
    
    /**
     * xmlTextReaderCurrentDoc:
     * @reader:  the xmlTextReaderPtr used
     *
     * Hacking interface allowing to get the xmlDocPtr correponding to the
     * current document being accessed by the xmlTextReader.
     * NOTE: as a result of this call, the reader will not destroy the
     *       associated XML document and calling xmlFreeDoc() on the result
     *       is needed once the reader parsing has finished.
     *
     * Returns the xmlDocPtr or NULL in case of error.
     */
    xmlDocPtr
    xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(NULL);
        if (reader->doc != NULL)
            return(reader->doc);
        if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
    	return(NULL);
    
        reader->preserve = 1;
        return(reader->ctxt->myDoc);
    }
    
    #ifdef LIBXML_SCHEMAS_ENABLED
    static char *xmlTextReaderBuildMessage(const char *msg, va_list ap);
    
    static void XMLCDECL
    xmlTextReaderValidityError(void *ctxt, const char *msg, ...);
    
    static void XMLCDECL
    xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);
    
    static void XMLCDECL
    xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
    {
        xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
    
        char *str;
    
        va_list ap;
    
        va_start(ap, msg);
        str = xmlTextReaderBuildMessage(msg, ap);
        if (!reader->errorFunc) {
            xmlTextReaderValidityError(ctx, "%s", str);
        } else {
            reader->errorFunc(reader->errorFuncArg, str,
                              XML_PARSER_SEVERITY_VALIDITY_ERROR,
                              NULL /* locator */ );
        }
        if (str != NULL)
            xmlFree(str);
        va_end(ap);
    }
    
    static void XMLCDECL
    xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
    {
        xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
    
        char *str;
    
        va_list ap;
    
        va_start(ap, msg);
        str = xmlTextReaderBuildMessage(msg, ap);
        if (!reader->errorFunc) {
            xmlTextReaderValidityWarning(ctx, "%s", str);
        } else {
            reader->errorFunc(reader->errorFuncArg, str,
                              XML_PARSER_SEVERITY_VALIDITY_WARNING,
                              NULL /* locator */ );
        }
        if (str != NULL)
            xmlFree(str);
        va_end(ap);
    }
    
    static void
      xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
    
    static void
    xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error)
    {
        xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
    
        if (reader->sErrorFunc) {
            reader->sErrorFunc(reader->errorFuncArg, error);
        } else {
            xmlTextReaderStructuredError(reader, error);
        }
    }
    /**
     * xmlTextReaderRelaxNGSetSchema:
     * @reader:  the xmlTextReaderPtr used
     * @schema:  a precompiled RelaxNG schema
     *
     * Use RelaxNG to validate the document as it is processed.
     * Activation is only possible before the first Read().
     * if @schema is NULL, then RelaxNG validation is desactivated.
     @ The @schema should not be freed until the reader is deallocated
     * or its use has been deactivated.
     *
     * Returns 0 in case the RelaxNG validation could be (des)activated and
     *         -1 in case of error.
     */
    int
    xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
        if (reader == NULL)
            return(-1);
        if (schema == NULL) {
            if (reader->rngSchemas != NULL) {
    	    xmlRelaxNGFree(reader->rngSchemas);
    	    reader->rngSchemas = NULL;
    	}
            if (reader->rngValidCtxt != NULL) {
    	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
    	    reader->rngValidCtxt = NULL;
            }
    	return(0);
        }
        if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
    	return(-1);
        if (reader->rngSchemas != NULL) {
    	xmlRelaxNGFree(reader->rngSchemas);
    	reader->rngSchemas = NULL;
        }
        if (reader->rngValidCtxt != NULL) {
    	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
    	reader->rngValidCtxt = NULL;
        }
        reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
        if (reader->rngValidCtxt == NULL)
            return(-1);
        if (reader->errorFunc != NULL) {
    	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
    			xmlTextReaderValidityErrorRelay,
    			xmlTextReaderValidityWarningRelay,
    			reader);
        }
    	if (reader->sErrorFunc != NULL) {
    		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
    			xmlTextReaderValidityStructuredRelay,
    			reader);
        }
        reader->rngValidErrors = 0;
        reader->rngFullNode = NULL;
        reader->validate = XML_TEXTREADER_VALIDATE_RNG;
        return(0);
    }
    
    /**
     * xmlTextReaderSetSchema:
     * @reader:  the xmlTextReaderPtr used
     * @schema:  a precompiled Schema schema
     *
     * Use XSD Schema to validate the document as it is processed.
     * Activation is only possible before the first Read().
     * if @schema is NULL, then Schema validation is desactivated.
     @ The @schema should not be freed until the reader is deallocated
     * or its use has been deactivated.
     *
     * Returns 0 in case the Schema validation could be (des)activated and
     *         -1 in case of error.
     */
    int
    xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
        if (reader == NULL)
            return(-1);
        if (schema == NULL) {
    	if (reader->xsdPlug != NULL) {
    	    xmlSchemaSAXUnplug(reader->xsdPlug);
    	    reader->xsdPlug = NULL;
    	}
            if (reader->xsdValidCtxt != NULL) {
    	    if (! reader->xsdPreserveCtxt)
    		xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
    	    reader->xsdValidCtxt = NULL;
            }
    	reader->xsdPreserveCtxt = 0;
            if (reader->xsdSchemas != NULL) {
    	    xmlSchemaFree(reader->xsdSchemas);
    	    reader->xsdSchemas = NULL;
    	}
    	return(0);
        }
        if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
    	return(-1);
        if (reader->xsdPlug != NULL) {
    	xmlSchemaSAXUnplug(reader->xsdPlug);
    	reader->xsdPlug = NULL;
        }
        if (reader->xsdValidCtxt != NULL) {
    	if (! reader->xsdPreserveCtxt)
    	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
    	reader->xsdValidCtxt = NULL;
        }
        reader->xsdPreserveCtxt = 0;
        if (reader->xsdSchemas != NULL) {
    	xmlSchemaFree(reader->xsdSchemas);
    	reader->xsdSchemas = NULL;
        }
        reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
        if (reader->xsdValidCtxt == NULL) {
    	xmlSchemaFree(reader->xsdSchemas);
    	reader->xsdSchemas = NULL;
            return(-1);
        }
        reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
                                           &(reader->ctxt->sax),
    				       &(reader->ctxt->userData));
        if (reader->xsdPlug == NULL) {
    	xmlSchemaFree(reader->xsdSchemas);
    	reader->xsdSchemas = NULL;
    	xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
    	reader->xsdValidCtxt = NULL;
    	return(-1);
        }
        if (reader->errorFunc != NULL) {
    	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
    			xmlTextReaderValidityErrorRelay,
    			xmlTextReaderValidityWarningRelay,
    			reader);
        }
    	if (reader->sErrorFunc != NULL) {
    		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
    			xmlTextReaderValidityStructuredRelay,
    			reader);
        }
        reader->xsdValidErrors = 0;
        reader->validate = XML_TEXTREADER_VALIDATE_XSD;
        return(0);
    }
    
    /**
     * xmlTextReaderRelaxNGValidate:
     * @reader:  the xmlTextReaderPtr used
     * @rng:  the path to a RelaxNG schema or NULL
     *
     * Use RelaxNG to validate the document as it is processed.
     * Activation is only possible before the first Read().
     * if @rng is NULL, then RelaxNG validation is deactivated.
     *
     * Returns 0 in case the RelaxNG validation could be (de)activated and
     *         -1 in case of error.
     */
    int
    xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
        xmlRelaxNGParserCtxtPtr ctxt;
    
        if (reader == NULL)
            return(-1);
    
        if (rng == NULL) {
            if (reader->rngValidCtxt != NULL) {
    	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
    	    reader->rngValidCtxt = NULL;
            }
            if (reader->rngSchemas != NULL) {
    	    xmlRelaxNGFree(reader->rngSchemas);
    	    reader->rngSchemas = NULL;
    	}
    	return(0);
        }
        if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
    	return(-1);
        if (reader->rngSchemas != NULL) {
    	xmlRelaxNGFree(reader->rngSchemas);
    	reader->rngSchemas = NULL;
        }
        if (reader->rngValidCtxt != NULL) {
    	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
    	reader->rngValidCtxt = NULL;
        }
        ctxt = xmlRelaxNGNewParserCtxt(rng);
        if (reader->errorFunc != NULL) {
    	xmlRelaxNGSetParserErrors(ctxt,
    			 xmlTextReaderValidityErrorRelay,
    			 xmlTextReaderValidityWarningRelay,
    			 reader);
        }
        if (reader->sErrorFunc != NULL) {
    	xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
    			xmlTextReaderValidityStructuredRelay,
    			reader);
        }
        reader->rngSchemas = xmlRelaxNGParse(ctxt);
        xmlRelaxNGFreeParserCtxt(ctxt);
        if (reader->rngSchemas == NULL)
            return(-1);
        reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
        if (reader->rngValidCtxt == NULL) {
    	xmlRelaxNGFree(reader->rngSchemas);
    	reader->rngSchemas = NULL;
            return(-1);
        }
        if (reader->errorFunc != NULL) {
    	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
    			 xmlTextReaderValidityErrorRelay,
    			 xmlTextReaderValidityWarningRelay,
    			 reader);
        }
    	if (reader->sErrorFunc != NULL) {
    		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
    			xmlTextReaderValidityStructuredRelay,
    			reader);
        }
        reader->rngValidErrors = 0;
        reader->rngFullNode = NULL;
        reader->validate = XML_TEXTREADER_VALIDATE_RNG;
        return(0);
    }
    
    /**
     * xmlTextReaderSchemaValidateInternal:
     * @reader:  the xmlTextReaderPtr used
     * @xsd:  the path to a W3C XSD schema or NULL
     * @ctxt: the XML Schema validation context or NULL
     * @options: options (not used yet)
     *
     * Validate the document as it is processed using XML Schema.
     * Activation is only possible before the first Read().
     * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
     *
     * Returns 0 in case the schemas validation could be (de)activated and
     *         -1 in case of error.
     */
    static int
    xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
    				    const char *xsd,
    				    xmlSchemaValidCtxtPtr ctxt,
    				    int options ATTRIBUTE_UNUSED)
    {
        if (reader == NULL)
            return(-1);
    
        if ((xsd != NULL) && (ctxt != NULL))
    	return(-1);
    
        if (((xsd != NULL) || (ctxt != NULL)) &&
    	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
            (reader->ctxt == NULL)))
    	return(-1);
    
        /* Cleanup previous validation stuff. */
        if (reader->xsdPlug != NULL) {
    	xmlSchemaSAXUnplug(reader->xsdPlug);
    	reader->xsdPlug = NULL;
        }
        if (reader->xsdValidCtxt != NULL) {
    	if (! reader->xsdPreserveCtxt)
    	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
    	reader->xsdValidCtxt = NULL;
        }
        reader->xsdPreserveCtxt = 0;
        if (reader->xsdSchemas != NULL) {
    	xmlSchemaFree(reader->xsdSchemas);
    	reader->xsdSchemas = NULL;
        }
    
        if ((xsd == NULL) && (ctxt == NULL)) {
    	/* We just want to deactivate the validation, so get out. */
    	return(0);
        }
    
        if (xsd != NULL) {
    	xmlSchemaParserCtxtPtr pctxt;
    	/* Parse the schema and create validation environment. */
    	pctxt = xmlSchemaNewParserCtxt(xsd);
    	if (reader->errorFunc != NULL) {
    	    xmlSchemaSetParserErrors(pctxt,
    		xmlTextReaderValidityErrorRelay,
    		xmlTextReaderValidityWarningRelay,
    		reader);
    	}
    	reader->xsdSchemas = xmlSchemaParse(pctxt);
    	xmlSchemaFreeParserCtxt(pctxt);
    	if (reader->xsdSchemas == NULL)
    	    return(-1);
    	reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
    	if (reader->xsdValidCtxt == NULL) {
    	    xmlSchemaFree(reader->xsdSchemas);
    	    reader->xsdSchemas = NULL;
    	    return(-1);
    	}
    	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
    	    &(reader->ctxt->sax),
    	    &(reader->ctxt->userData));
    	if (reader->xsdPlug == NULL) {
    	    xmlSchemaFree(reader->xsdSchemas);
    	    reader->xsdSchemas = NULL;
    	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
    	    reader->xsdValidCtxt = NULL;
    	    return(-1);
    	}
        } else {
    	/* Use the given validation context. */
    	reader->xsdValidCtxt = ctxt;
    	reader->xsdPreserveCtxt = 1;
    	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
    	    &(reader->ctxt->sax),
    	    &(reader->ctxt->userData));
    	if (reader->xsdPlug == NULL) {
    	    reader->xsdValidCtxt = NULL;
    	    reader->xsdPreserveCtxt = 0;
    	    return(-1);
    	}
        }
        /*
        * Redirect the validation context's error channels to use
        * the reader channels.
        * TODO: In case the user provides the validation context we
        *   could make this redirection optional.
        */
        if (reader->errorFunc != NULL) {
    	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
    			 xmlTextReaderValidityErrorRelay,
    			 xmlTextReaderValidityWarningRelay,
    			 reader);
        }
    	if (reader->sErrorFunc != NULL) {
    		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
    			xmlTextReaderValidityStructuredRelay,
    			reader);
        }
        reader->xsdValidErrors = 0;
        reader->validate = XML_TEXTREADER_VALIDATE_XSD;
        return(0);
    }
    
    /**
     * xmlTextReaderSchemaValidateCtxt:
     * @reader:  the xmlTextReaderPtr used
     * @ctxt: the XML Schema validation context or NULL
     * @options: options (not used yet)
     *
     * Use W3C XSD schema context to validate the document as it is processed.
     * Activation is only possible before the first Read().
     * If @ctxt is NULL, then XML Schema validation is deactivated.
     *
     * Returns 0 in case the schemas validation could be (de)activated and
     *         -1 in case of error.
     */
    int
    xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
    				    xmlSchemaValidCtxtPtr ctxt,
    				    int options)
    {
        return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
    }
    
    /**
     * xmlTextReaderSchemaValidate:
     * @reader:  the xmlTextReaderPtr used
     * @xsd:  the path to a W3C XSD schema or NULL
     *
     * Use W3C XSD schema to validate the document as it is processed.
     * Activation is only possible before the first Read().
     * If @xsd is NULL, then XML Schema validation is deactivated.
     *
     * Returns 0 in case the schemas validation could be (de)activated and
     *         -1 in case of error.
     */
    int
    xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
    {
        return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
    }
    #endif
    
    /**
     * xmlTextReaderIsNamespaceDecl:
     * @reader: the xmlTextReaderPtr used
     *
     * Determine whether the current node is a namespace declaration
     * rather than a regular attribute.
     *
     * Returns 1 if the current node is a namespace declaration, 0 if it
     * is a regular attribute or other type of node, or -1 in case of
     * error.
     */
    int
    xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
        xmlNodePtr node;
        if (reader == NULL)
    	return(-1);
        if (reader->node == NULL)
    	return(-1);
        if (reader->curnode != NULL)
    	node = reader->curnode;
        else
    	node = reader->node;
    
        if (XML_NAMESPACE_DECL == node->type)
    	return(1);
        else
    	return(0);
    }
    
    /**
     * xmlTextReaderConstXmlVersion:
     * @reader:  the xmlTextReaderPtr used
     *
     * Determine the XML version of the document being read.
     *
     * Returns a string containing the XML version of the document or NULL
     * in case of error.  The string is deallocated with the reader.
     */
    const xmlChar *
    xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
        xmlDocPtr doc = NULL;
        if (reader == NULL)
    	return(NULL);
        if (reader->doc != NULL)
            doc = reader->doc;
        else if (reader->ctxt != NULL)
    	doc = reader->ctxt->myDoc;
        if (doc == NULL)
    	return(NULL);
    
        if (doc->version == NULL)
    	return(NULL);
        else
          return(CONSTSTR(doc->version));
    }
    
    /**
     * xmlTextReaderStandalone:
     * @reader:  the xmlTextReaderPtr used
     *
     * Determine the standalone status of the document being read.
     *
     * Returns 1 if the document was declared to be standalone, 0 if it
     * was declared to be not standalone, or -1 if the document did not
     * specify its standalone status or in case of error.
     */
    int
    xmlTextReaderStandalone(xmlTextReaderPtr reader) {
        xmlDocPtr doc = NULL;
        if (reader == NULL)
    	return(-1);
        if (reader->doc != NULL)
            doc = reader->doc;
        else if (reader->ctxt != NULL)
    	doc = reader->ctxt->myDoc;
        if (doc == NULL)
    	return(-1);
    
        return(doc->standalone);
    }
    
    /************************************************************************
     *									*
     *			Error Handling Extensions                       *
     *									*
     ************************************************************************/
    
    /* helper to build a xmlMalloc'ed string from a format and va_list */
    static char *
    xmlTextReaderBuildMessage(const char *msg, va_list ap) {
        int size = 0;
        int chars;
        char *larger;
        char *str = NULL;
        va_list aq;
    
        while (1) {
            VA_COPY(aq, ap);
            chars = vsnprintf(str, size, msg, aq);
            va_end(aq);
            if (chars < 0) {
    	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
    	    if (str)
    		xmlFree(str);
    	    return NULL;
    	}
    	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
                break;
            if (chars < MAX_ERR_MSG_SIZE)
    	size = chars + 1;
    	else
    		size = MAX_ERR_MSG_SIZE;
            if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
    	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
    	    if (str)
                    xmlFree(str);
                return NULL;
            }
            str = larger;
        }
    
        return str;
    }
    
    /**
     * xmlTextReaderLocatorLineNumber:
     * @locator: the xmlTextReaderLocatorPtr used
     *
     * Obtain the line number for the given locator.
     *
     * Returns the line number or -1 in case of error.
     */
    int
    xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
        /* we know that locator is a xmlParserCtxtPtr */
        xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
        int ret = -1;
    
        if (locator == NULL)
            return(-1);
        if (ctx->node != NULL) {
    	ret = xmlGetLineNo(ctx->node);
        }
        else {
    	/* inspired from error.c */
    	xmlParserInputPtr input;
    	input = ctx->input;
    	if ((input->filename == NULL) && (ctx->inputNr > 1))
    	    input = ctx->inputTab[ctx->inputNr - 2];
    	if (input != NULL) {
    	    ret = input->line;
    	}
    	else {
    	    ret = -1;
    	}
        }
    
        return ret;
    }
    
    /**
     * xmlTextReaderLocatorBaseURI:
     * @locator: the xmlTextReaderLocatorPtr used
     *
     * Obtain the base URI for the given locator.
     *
     * Returns the base URI or NULL in case of error,
     *    if non NULL it need to be freed by the caller.
     */
    xmlChar *
    xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
        /* we know that locator is a xmlParserCtxtPtr */
        xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
        xmlChar *ret = NULL;
    
        if (locator == NULL)
            return(NULL);
        if (ctx->node != NULL) {
    	ret = xmlNodeGetBase(NULL,ctx->node);
        }
        else {
    	/* inspired from error.c */
    	xmlParserInputPtr input;
    	input = ctx->input;
    	if ((input->filename == NULL) && (ctx->inputNr > 1))
    	    input = ctx->inputTab[ctx->inputNr - 2];
    	if (input != NULL) {
    	    ret = xmlStrdup(BAD_CAST input->filename);
    	}
    	else {
    	    ret = NULL;
    	}
        }
    
        return ret;
    }
    
    static void
    xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
                              char *str)
    {
        xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
    
        xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
    
        if (str != NULL) {
            if (reader->errorFunc)
                reader->errorFunc(reader->errorFuncArg, str, severity,
                                  (xmlTextReaderLocatorPtr) ctx);
            xmlFree(str);
        }
    }
    
    static void
    xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error)
    {
        xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
    
        xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
    
        if (error && reader->sErrorFunc) {
            reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
        }
    }
    
    static void XMLCDECL
    xmlTextReaderError(void *ctxt, const char *msg, ...)
    {
        va_list ap;
    
        va_start(ap, msg);
        xmlTextReaderGenericError(ctxt,
                                  XML_PARSER_SEVERITY_ERROR,
                                  xmlTextReaderBuildMessage(msg, ap));
        va_end(ap);
    
    }
    
    static void XMLCDECL
    xmlTextReaderWarning(void *ctxt, const char *msg, ...)
    {
        va_list ap;
    
        va_start(ap, msg);
        xmlTextReaderGenericError(ctxt,
                                  XML_PARSER_SEVERITY_WARNING,
                                  xmlTextReaderBuildMessage(msg, ap));
        va_end(ap);
    }
    
    static void XMLCDECL
    xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
    {
        va_list ap;
    
        int len = xmlStrlen((const xmlChar *) msg);
    
        if ((len > 1) && (msg[len - 2] != ':')) {
            /*
             * some callbacks only report locator information:
             * skip them (mimicking behaviour in error.c)
             */
            va_start(ap, msg);
            xmlTextReaderGenericError(ctxt,
                                      XML_PARSER_SEVERITY_VALIDITY_ERROR,
                                      xmlTextReaderBuildMessage(msg, ap));
            va_end(ap);
        }
    }
    
    static void XMLCDECL
    xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
    {
        va_list ap;
    
        int len = xmlStrlen((const xmlChar *) msg);
    
        if ((len != 0) && (msg[len - 1] != ':')) {
            /*
             * some callbacks only report locator information:
             * skip them (mimicking behaviour in error.c)
             */
            va_start(ap, msg);
            xmlTextReaderGenericError(ctxt,
                                      XML_PARSER_SEVERITY_VALIDITY_WARNING,
                                      xmlTextReaderBuildMessage(msg, ap));
            va_end(ap);
        }
    }
    
    /**
     * xmlTextReaderSetErrorHandler:
     * @reader:  the xmlTextReaderPtr used
     * @f:	the callback function to call on error and warnings
     * @arg:    a user argument to pass to the callback function
     *
     * Register a callback function that will be called on error and warnings.
     *
     * If @f is NULL, the default error and warning handlers are restored.
     */
    void
    xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
                                 xmlTextReaderErrorFunc f, void *arg)
    {
        if (f != NULL) {
            reader->ctxt->sax->error = xmlTextReaderError;
            reader->ctxt->sax->serror = NULL;
            reader->ctxt->vctxt.error = xmlTextReaderValidityError;
            reader->ctxt->sax->warning = xmlTextReaderWarning;
            reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
            reader->errorFunc = f;
            reader->sErrorFunc = NULL;
            reader->errorFuncArg = arg;
    #ifdef LIBXML_SCHEMAS_ENABLED
            if (reader->rngValidCtxt) {
                xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
                                         xmlTextReaderValidityErrorRelay,
                                         xmlTextReaderValidityWarningRelay,
                                         reader);
                xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
                                                   reader);
            }
            if (reader->xsdValidCtxt) {
                xmlSchemaSetValidErrors(reader->xsdValidCtxt,
                                        xmlTextReaderValidityErrorRelay,
                                        xmlTextReaderValidityWarningRelay,
                                        reader);
                xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
                                                  reader);
            }
    #endif
        } else {
            /* restore defaults */
            reader->ctxt->sax->error = xmlParserError;
            reader->ctxt->vctxt.error = xmlParserValidityError;
            reader->ctxt->sax->warning = xmlParserWarning;
            reader->ctxt->vctxt.warning = xmlParserValidityWarning;
            reader->errorFunc = NULL;
            reader->sErrorFunc = NULL;
            reader->errorFuncArg = NULL;
    #ifdef LIBXML_SCHEMAS_ENABLED
            if (reader->rngValidCtxt) {
                xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
                                         reader);
                xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
                                                   reader);
            }
            if (reader->xsdValidCtxt) {
                xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
                                        reader);
                xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
                                                  reader);
            }
    #endif
        }
    }
    
    /**
    * xmlTextReaderSetStructuredErrorHandler:
     * @reader:  the xmlTextReaderPtr used
     * @f:	the callback function to call on error and warnings
     * @arg:    a user argument to pass to the callback function
     *
     * Register a callback function that will be called on error and warnings.
     *
     * If @f is NULL, the default error and warning handlers are restored.
     */
    void
    xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
                                           xmlStructuredErrorFunc f, void *arg)
    {
        if (f != NULL) {
            reader->ctxt->sax->error = NULL;
            reader->ctxt->sax->serror = xmlTextReaderStructuredError;
            reader->ctxt->vctxt.error = xmlTextReaderValidityError;
            reader->ctxt->sax->warning = xmlTextReaderWarning;
            reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
            reader->sErrorFunc = f;
            reader->errorFunc = NULL;
            reader->errorFuncArg = arg;
    #ifdef LIBXML_SCHEMAS_ENABLED
            if (reader->rngValidCtxt) {
                xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
                                         reader);
                xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
                                            xmlTextReaderValidityStructuredRelay,
                                                   reader);
            }
            if (reader->xsdValidCtxt) {
                xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
                                        reader);
                xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
                                           xmlTextReaderValidityStructuredRelay,
                                                  reader);
            }
    #endif
        } else {
            /* restore defaults */
            reader->ctxt->sax->error = xmlParserError;
            reader->ctxt->sax->serror = NULL;
            reader->ctxt->vctxt.error = xmlParserValidityError;
            reader->ctxt->sax->warning = xmlParserWarning;
            reader->ctxt->vctxt.warning = xmlParserValidityWarning;
            reader->errorFunc = NULL;
            reader->sErrorFunc = NULL;
            reader->errorFuncArg = NULL;
    #ifdef LIBXML_SCHEMAS_ENABLED
            if (reader->rngValidCtxt) {
                xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
                                         reader);
                xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
                                                   reader);
            }
            if (reader->xsdValidCtxt) {
                xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
                                        reader);
                xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
                                                  reader);
            }
    #endif
        }
    }
    
    /**
     * xmlTextReaderIsValid:
     * @reader:  the xmlTextReaderPtr used
     *
     * Retrieve the validity status from the parser context
     *
     * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
     */
    int
    xmlTextReaderIsValid(xmlTextReaderPtr reader)
    {
        if (reader == NULL)
            return (-1);
    #ifdef LIBXML_SCHEMAS_ENABLED
        if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
            return (reader->rngValidErrors == 0);
        if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
            return (reader->xsdValidErrors == 0);
    #endif
        if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
            return (reader->ctxt->valid);
        return (0);
    }
    
    /**
     * xmlTextReaderGetErrorHandler:
     * @reader:  the xmlTextReaderPtr used
     * @f:	the callback function or NULL is no callback has been registered
     * @arg:    a user argument
     *
     * Retrieve the error callback function and user argument.
     */
    void
    xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
                                 xmlTextReaderErrorFunc * f, void **arg)
    {
        if (f != NULL)
            *f = reader->errorFunc;
        if (arg != NULL)
            *arg = reader->errorFuncArg;
    }
    /************************************************************************
     *									*
     *	New set (2.6.0) of simpler and more flexible APIs		*
     *									*
     ************************************************************************/
    
    /**
     * xmlTextReaderSetup:
     * @reader:  an XML reader
     * @input: xmlParserInputBufferPtr used to feed the reader, will
     *         be destroyed with it.
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Setup an XML reader with new options
     *
     * Returns 0 in case of success and -1 in case of error.
     */
    int
    xmlTextReaderSetup(xmlTextReaderPtr reader,
                       xmlParserInputBufferPtr input, const char *URL,
                       const char *encoding, int options)
    {
        if (reader == NULL) {
            if (input != NULL)
    	    xmlFreeParserInputBuffer(input);
            return (-1);
        }
    
        /*
         * we force the generation of compact text nodes on the reader
         * since usr applications should never modify the tree
         */
        options |= XML_PARSE_COMPACT;
    
        reader->doc = NULL;
        reader->entNr = 0;
        reader->parserFlags = options;
        reader->validate = XML_TEXTREADER_NOT_VALIDATE;
        if ((input != NULL) && (reader->input != NULL) &&
            (reader->allocs & XML_TEXTREADER_INPUT)) {
    	xmlFreeParserInputBuffer(reader->input);
    	reader->input = NULL;
    	reader->allocs -= XML_TEXTREADER_INPUT;
        }
        if (input != NULL) {
    	reader->input = input;
    	reader->allocs |= XML_TEXTREADER_INPUT;
        }
        if (reader->buffer == NULL)
            reader->buffer = xmlBufferCreateSize(100);
        if (reader->buffer == NULL) {
            xmlGenericError(xmlGenericErrorContext,
                            "xmlTextReaderSetup : malloc failed\n");
            return (-1);
        }
        if (reader->sax == NULL)
    	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
        if (reader->sax == NULL) {
            xmlGenericError(xmlGenericErrorContext,
                            "xmlTextReaderSetup : malloc failed\n");
            return (-1);
        }
        xmlSAXVersion(reader->sax, 2);
        reader->startElement = reader->sax->startElement;
        reader->sax->startElement = xmlTextReaderStartElement;
        reader->endElement = reader->sax->endElement;
        reader->sax->endElement = xmlTextReaderEndElement;
    #ifdef LIBXML_SAX1_ENABLED
        if (reader->sax->initialized == XML_SAX2_MAGIC) {
    #endif /* LIBXML_SAX1_ENABLED */
            reader->startElementNs = reader->sax->startElementNs;
            reader->sax->startElementNs = xmlTextReaderStartElementNs;
            reader->endElementNs = reader->sax->endElementNs;
            reader->sax->endElementNs = xmlTextReaderEndElementNs;
    #ifdef LIBXML_SAX1_ENABLED
        } else {
            reader->startElementNs = NULL;
            reader->endElementNs = NULL;
        }
    #endif /* LIBXML_SAX1_ENABLED */
        reader->characters = reader->sax->characters;
        reader->sax->characters = xmlTextReaderCharacters;
        reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
        reader->cdataBlock = reader->sax->cdataBlock;
        reader->sax->cdataBlock = xmlTextReaderCDataBlock;
    
        reader->mode = XML_TEXTREADER_MODE_INITIAL;
        reader->node = NULL;
        reader->curnode = NULL;
        if (input != NULL) {
            if (reader->input->buffer->use < 4) {
                xmlParserInputBufferRead(input, 4);
            }
            if (reader->ctxt == NULL) {
                if (reader->input->buffer->use >= 4) {
                    reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
    		       (const char *) reader->input->buffer->content, 4, URL);
                    reader->base = 0;
                    reader->cur = 4;
                } else {
                    reader->ctxt =
                        xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
                    reader->base = 0;
                    reader->cur = 0;
                }
            } else {
    	    xmlParserInputPtr inputStream;
    	    xmlParserInputBufferPtr buf;
    	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
    
    	    xmlCtxtReset(reader->ctxt);
    	    buf = xmlAllocParserInputBuffer(enc);
    	    if (buf == NULL) return(-1);
    	    inputStream = xmlNewInputStream(reader->ctxt);
    	    if (inputStream == NULL) {
    		xmlFreeParserInputBuffer(buf);
    		return(-1);
    	    }
    
    	    if (URL == NULL)
    		inputStream->filename = NULL;
    	    else
    		inputStream->filename = (char *)
    		    xmlCanonicPath((const xmlChar *) URL);
    	    inputStream->buf = buf;
    	    inputStream->base = inputStream->buf->buffer->content;
    	    inputStream->cur = inputStream->buf->buffer->content;
    	    inputStream->end =
                &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
    
    	    inputPush(reader->ctxt, inputStream);
    	    reader->cur = 0;
    	}
            if (reader->ctxt == NULL) {
                xmlGenericError(xmlGenericErrorContext,
                                "xmlTextReaderSetup : malloc failed\n");
                return (-1);
            }
        }
        if (reader->dict != NULL) {
            if (reader->ctxt->dict != NULL) {
    	    if (reader->dict != reader->ctxt->dict) {
    		xmlDictFree(reader->dict);
    		reader->dict = reader->ctxt->dict;
    	    }
    	} else {
    	    reader->ctxt->dict = reader->dict;
    	}
        } else {
    	if (reader->ctxt->dict == NULL)
    	    reader->ctxt->dict = xmlDictCreate();
            reader->dict = reader->ctxt->dict;
        }
        reader->ctxt->_private = reader;
        reader->ctxt->linenumbers = 1;
        reader->ctxt->dictNames = 1;
        /*
         * use the parser dictionnary to allocate all elements and attributes names
         */
        reader->ctxt->docdict = 1;
        reader->ctxt->parseMode = XML_PARSE_READER;
    
    #ifdef LIBXML_XINCLUDE_ENABLED
        if (reader->xincctxt != NULL) {
    	xmlXIncludeFreeContext(reader->xincctxt);
    	reader->xincctxt = NULL;
        }
        if (options & XML_PARSE_XINCLUDE) {
            reader->xinclude = 1;
    	reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
    	options -= XML_PARSE_XINCLUDE;
        } else
            reader->xinclude = 0;
        reader->in_xinclude = 0;
    #endif
    #ifdef LIBXML_PATTERN_ENABLED
        if (reader->patternTab == NULL) {
            reader->patternNr = 0;
    	reader->patternMax = 0;
        }
        while (reader->patternNr > 0) {
            reader->patternNr--;
    	if (reader->patternTab[reader->patternNr] != NULL) {
    	    xmlFreePattern(reader->patternTab[reader->patternNr]);
                reader->patternTab[reader->patternNr] = NULL;
    	}
        }
    #endif
    
        if (options & XML_PARSE_DTDVALID)
            reader->validate = XML_TEXTREADER_VALIDATE_DTD;
    
        xmlCtxtUseOptions(reader->ctxt, options);
        if (encoding != NULL) {
            xmlCharEncodingHandlerPtr hdlr;
    
            hdlr = xmlFindCharEncodingHandler(encoding);
            if (hdlr != NULL)
                xmlSwitchToEncoding(reader->ctxt, hdlr);
        }
        if ((URL != NULL) && (reader->ctxt->input != NULL) &&
            (reader->ctxt->input->filename == NULL))
            reader->ctxt->input->filename = (char *)
                xmlStrdup((const xmlChar *) URL);
    
        reader->doc = NULL;
    
        return (0);
    }
    
    /**
     * xmlTextReaderByteConsumed:
     * @reader: an XML reader
     *
     * This function provides the current index of the parser used
     * by the reader, relative to the start of the current entity.
     * This function actually just wraps a call to xmlBytesConsumed()
     * for the parser context associated with the reader.
     * See xmlBytesConsumed() for more information.
     *
     * Returns the index in bytes from the beginning of the entity or -1
     *         in case the index could not be computed.
     */
    long
    xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->ctxt == NULL))
            return(-1);
        return(xmlByteConsumed(reader->ctxt));
    }
    
    
    /**
     * xmlReaderWalker:
     * @doc:  a preparsed document
     *
     * Create an xmltextReader for a preparsed document.
     *
     * Returns the new reader or NULL in case of error.
     */
    xmlTextReaderPtr
    xmlReaderWalker(xmlDocPtr doc)
    {
        xmlTextReaderPtr ret;
    
        if (doc == NULL)
            return(NULL);
    
        ret = xmlMalloc(sizeof(xmlTextReader));
        if (ret == NULL) {
            xmlGenericError(xmlGenericErrorContext,
    		"xmlNewTextReader : malloc failed\n");
    	return(NULL);
        }
        memset(ret, 0, sizeof(xmlTextReader));
        ret->entNr = 0;
        ret->input = NULL;
        ret->mode = XML_TEXTREADER_MODE_INITIAL;
        ret->node = NULL;
        ret->curnode = NULL;
        ret->base = 0;
        ret->cur = 0;
        ret->allocs = XML_TEXTREADER_CTXT;
        ret->doc = doc;
        ret->state = XML_TEXTREADER_START;
        ret->dict = xmlDictCreate();
        return(ret);
    }
    
    /**
     * xmlReaderForDoc:
     * @cur:  a pointer to a zero terminated string
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Create an xmltextReader for an XML in-memory document.
     * The parsing flags @options are a combination of xmlParserOption.
     *
     * Returns the new reader or NULL in case of error.
     */
    xmlTextReaderPtr
    xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
                    int options)
    {
        int len;
    
        if (cur == NULL)
            return (NULL);
        len = xmlStrlen(cur);
    
        return (xmlReaderForMemory
                ((const char *) cur, len, URL, encoding, options));
    }
    
    /**
     * xmlReaderForFile:
     * @filename:  a file or URL
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * parse an XML file from the filesystem or the network.
     * The parsing flags @options are a combination of xmlParserOption.
     *
     * Returns the new reader or NULL in case of error.
     */
    xmlTextReaderPtr
    xmlReaderForFile(const char *filename, const char *encoding, int options)
    {
        xmlTextReaderPtr reader;
    
        reader = xmlNewTextReaderFilename(filename);
        if (reader == NULL)
            return (NULL);
        xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
        return (reader);
    }
    
    /**
     * xmlReaderForMemory:
     * @buffer:  a pointer to a char array
     * @size:  the size of the array
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Create an xmltextReader for an XML in-memory document.
     * The parsing flags @options are a combination of xmlParserOption.
     *
     * Returns the new reader or NULL in case of error.
     */
    xmlTextReaderPtr
    xmlReaderForMemory(const char *buffer, int size, const char *URL,
                       const char *encoding, int options)
    {
        xmlTextReaderPtr reader;
        xmlParserInputBufferPtr buf;
    
        buf = xmlParserInputBufferCreateStatic(buffer, size,
                                          XML_CHAR_ENCODING_NONE);
        if (buf == NULL) {
            return (NULL);
        }
        reader = xmlNewTextReader(buf, URL);
        if (reader == NULL) {
            xmlFreeParserInputBuffer(buf);
            return (NULL);
        }
        reader->allocs |= XML_TEXTREADER_INPUT;
        xmlTextReaderSetup(reader, NULL, URL, encoding, options);
        return (reader);
    }
    
    /**
     * xmlReaderForFd:
     * @fd:  an open file descriptor
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Create an xmltextReader for an XML from a file descriptor.
     * The parsing flags @options are a combination of xmlParserOption.
     * NOTE that the file descriptor will not be closed when the
     *      reader is closed or reset.
     *
     * Returns the new reader or NULL in case of error.
     */
    xmlTextReaderPtr
    xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
    {
        xmlTextReaderPtr reader;
        xmlParserInputBufferPtr input;
    
        if (fd < 0)
            return (NULL);
    
        input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
        if (input == NULL)
            return (NULL);
        input->closecallback = NULL;
        reader = xmlNewTextReader(input, URL);
        if (reader == NULL) {
            xmlFreeParserInputBuffer(input);
            return (NULL);
        }
        reader->allocs |= XML_TEXTREADER_INPUT;
        xmlTextReaderSetup(reader, NULL, URL, encoding, options);
        return (reader);
    }
    
    /**
     * xmlReaderForIO:
     * @ioread:  an I/O read function
     * @ioclose:  an I/O close function
     * @ioctx:  an I/O handler
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Create an xmltextReader for an XML document from I/O functions and source.
     * The parsing flags @options are a combination of xmlParserOption.
     *
     * Returns the new reader or NULL in case of error.
     */
    xmlTextReaderPtr
    xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
                   void *ioctx, const char *URL, const char *encoding,
                   int options)
    {
        xmlTextReaderPtr reader;
        xmlParserInputBufferPtr input;
    
        if (ioread == NULL)
            return (NULL);
    
        input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
                                             XML_CHAR_ENCODING_NONE);
        if (input == NULL)
            return (NULL);
        reader = xmlNewTextReader(input, URL);
        if (reader == NULL) {
            xmlFreeParserInputBuffer(input);
            return (NULL);
        }
        reader->allocs |= XML_TEXTREADER_INPUT;
        xmlTextReaderSetup(reader, NULL, URL, encoding, options);
        return (reader);
    }
    
    /**
     * xmlReaderNewWalker:
     * @reader:  an XML reader
     * @doc:  a preparsed document
     *
     * Setup an xmltextReader to parse a preparsed XML document.
     * This reuses the existing @reader xmlTextReader.
     *
     * Returns 0 in case of success and -1 in case of error
     */
    int
    xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
    {
        if (doc == NULL)
            return (-1);
        if (reader == NULL)
            return (-1);
    
        if (reader->input != NULL) {
            xmlFreeParserInputBuffer(reader->input);
        }
        if (reader->ctxt != NULL) {
    	xmlCtxtReset(reader->ctxt);
        }
    
        reader->entNr = 0;
        reader->input = NULL;
        reader->mode = XML_TEXTREADER_MODE_INITIAL;
        reader->node = NULL;
        reader->curnode = NULL;
        reader->base = 0;
        reader->cur = 0;
        reader->allocs = XML_TEXTREADER_CTXT;
        reader->doc = doc;
        reader->state = XML_TEXTREADER_START;
        if (reader->dict == NULL) {
            if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
    	    reader->dict = reader->ctxt->dict;
    	else
    	    reader->dict = xmlDictCreate();
        }
        return(0);
    }
    
    /**
     * xmlReaderNewDoc:
     * @reader:  an XML reader
     * @cur:  a pointer to a zero terminated string
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Setup an xmltextReader to parse an XML in-memory document.
     * The parsing flags @options are a combination of xmlParserOption.
     * This reuses the existing @reader xmlTextReader.
     *
     * Returns 0 in case of success and -1 in case of error
     */
    int
    xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
                    const char *URL, const char *encoding, int options)
    {
    
        int len;
    
        if (cur == NULL)
            return (-1);
        if (reader == NULL)
            return (-1);
    
        len = xmlStrlen(cur);
        return (xmlReaderNewMemory(reader, (const char *)cur, len,
                                   URL, encoding, options));
    }
    
    /**
     * xmlReaderNewFile:
     * @reader:  an XML reader
     * @filename:  a file or URL
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * parse an XML file from the filesystem or the network.
     * The parsing flags @options are a combination of xmlParserOption.
     * This reuses the existing @reader xmlTextReader.
     *
     * Returns 0 in case of success and -1 in case of error
     */
    int
    xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
                     const char *encoding, int options)
    {
        xmlParserInputBufferPtr input;
    
        if (filename == NULL)
            return (-1);
        if (reader == NULL)
            return (-1);
    
        input =
            xmlParserInputBufferCreateFilename(filename,
                                               XML_CHAR_ENCODING_NONE);
        if (input == NULL)
            return (-1);
        return (xmlTextReaderSetup(reader, input, filename, encoding, options));
    }
    
    /**
     * xmlReaderNewMemory:
     * @reader:  an XML reader
     * @buffer:  a pointer to a char array
     * @size:  the size of the array
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Setup an xmltextReader to parse an XML in-memory document.
     * The parsing flags @options are a combination of xmlParserOption.
     * This reuses the existing @reader xmlTextReader.
     *
     * Returns 0 in case of success and -1 in case of error
     */
    int
    xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
                       const char *URL, const char *encoding, int options)
    {
        xmlParserInputBufferPtr input;
    
        if (reader == NULL)
            return (-1);
        if (buffer == NULL)
            return (-1);
    
        input = xmlParserInputBufferCreateStatic(buffer, size,
                                          XML_CHAR_ENCODING_NONE);
        if (input == NULL) {
            return (-1);
        }
        return (xmlTextReaderSetup(reader, input, URL, encoding, options));
    }
    
    /**
     * xmlReaderNewFd:
     * @reader:  an XML reader
     * @fd:  an open file descriptor
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Setup an xmltextReader to parse an XML from a file descriptor.
     * NOTE that the file descriptor will not be closed when the
     *      reader is closed or reset.
     * The parsing flags @options are a combination of xmlParserOption.
     * This reuses the existing @reader xmlTextReader.
     *
     * Returns 0 in case of success and -1 in case of error
     */
    int
    xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
                   const char *URL, const char *encoding, int options)
    {
        xmlParserInputBufferPtr input;
    
        if (fd < 0)
            return (-1);
        if (reader == NULL)
            return (-1);
    
        input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
        if (input == NULL)
            return (-1);
        input->closecallback = NULL;
        return (xmlTextReaderSetup(reader, input, URL, encoding, options));
    }
    
    /**
     * xmlReaderNewIO:
     * @reader:  an XML reader
     * @ioread:  an I/O read function
     * @ioclose:  an I/O close function
     * @ioctx:  an I/O handler
     * @URL:  the base URL to use for the document
     * @encoding:  the document encoding, or NULL
     * @options:  a combination of xmlParserOption
     *
     * Setup an xmltextReader to parse an XML document from I/O functions
     * and source.
     * The parsing flags @options are a combination of xmlParserOption.
     * This reuses the existing @reader xmlTextReader.
     *
     * Returns 0 in case of success and -1 in case of error
     */
    int
    xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
                   xmlInputCloseCallback ioclose, void *ioctx,
                   const char *URL, const char *encoding, int options)
    {
        xmlParserInputBufferPtr input;
    
        if (ioread == NULL)
            return (-1);
        if (reader == NULL)
            return (-1);
    
        input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
                                             XML_CHAR_ENCODING_NONE);
        if (input == NULL)
            return (-1);
        return (xmlTextReaderSetup(reader, input, URL, encoding, options));
    }
    /************************************************************************
     *									*
     *			Utilities					*
     *									*
     ************************************************************************/
    #ifdef NOT_USED_YET
    
    /**
     * xmlBase64Decode:
     * @in:  the input buffer
     * @inlen:  the size of the input (in), the size read from it (out)
     * @to:  the output buffer
     * @tolen:  the size of the output (in), the size written to (out)
     *
     * Base64 decoder, reads from @in and save in @to
     * TODO: tell jody when this is actually exported
     *
     * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
     *         2 if there wasn't enough space on the output or -1 in case of error.
     */
    static int
    xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
                    unsigned char *to, unsigned long *tolen)
    {
        unsigned long incur;        /* current index in in[] */
    
        unsigned long inblk;        /* last block index in in[] */
    
        unsigned long outcur;       /* current index in out[] */
    
        unsigned long inmax;        /* size of in[] */
    
        unsigned long outmax;       /* size of out[] */
    
        unsigned char cur;          /* the current value read from in[] */
    
        unsigned char intmp[4], outtmp[4];  /* temporary buffers for the convert */
    
        int nbintmp;                /* number of byte in intmp[] */
    
        int is_ignore;              /* cur should be ignored */
    
        int is_end = 0;             /* the end of the base64 was found */
    
        int retval = 1;
    
        int i;
    
        if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
            return (-1);
    
        incur = 0;
        inblk = 0;
        outcur = 0;
        inmax = *inlen;
        outmax = *tolen;
        nbintmp = 0;
    
        while (1) {
            if (incur >= inmax)
                break;
            cur = in[incur++];
            is_ignore = 0;
            if ((cur >= 'A') && (cur <= 'Z'))
                cur = cur - 'A';
            else if ((cur >= 'a') && (cur <= 'z'))
                cur = cur - 'a' + 26;
            else if ((cur >= '0') && (cur <= '9'))
                cur = cur - '0' + 52;
            else if (cur == '+')
                cur = 62;
            else if (cur == '/')
                cur = 63;
            else if (cur == '.')
                cur = 0;
            else if (cur == '=')    /*no op , end of the base64 stream */
                is_end = 1;
            else {
                is_ignore = 1;
                if (nbintmp == 0)
                    inblk = incur;
            }
    
            if (!is_ignore) {
                int nbouttmp = 3;
    
                int is_break = 0;
    
                if (is_end) {
                    if (nbintmp == 0)
                        break;
                    if ((nbintmp == 1) || (nbintmp == 2))
                        nbouttmp = 1;
                    else
                        nbouttmp = 2;
                    nbintmp = 3;
                    is_break = 1;
                }
                intmp[nbintmp++] = cur;
                /*
                 * if intmp is full, push the 4byte sequence as a 3 byte
                 * sequence out
                 */
                if (nbintmp == 4) {
                    nbintmp = 0;
                    outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
                    outtmp[1] =
                        ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
                    outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
                    if (outcur + 3 >= outmax) {
                        retval = 2;
                        break;
                    }
    
                    for (i = 0; i < nbouttmp; i++)
                        to[outcur++] = outtmp[i];
                    inblk = incur;
                }
    
                if (is_break) {
                    retval = 0;
                    break;
                }
            }
        }
    
        *tolen = outcur;
        *inlen = inblk;
        return (retval);
    }
    
    /*
     * Test routine for the xmlBase64Decode function
     */
    #if 0
    int
    main(int argc, char **argv)
    {
        char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
    
        char output[100];
    
        char output2[100];
    
        char output3[100];
    
        unsigned long inlen = strlen(input);
    
        unsigned long outlen = 100;
    
        int ret;
    
        unsigned long cons, tmp, tmp2, prod;
    
        /*
         * Direct
         */
        ret = xmlBase64Decode(input, &inlen, output, &outlen);
    
        output[outlen] = 0;
        printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen,
               outlen, output)indent: Standard input:179: Error:Unmatched #endif
    ;
    
        /*
         * output chunking
         */
        cons = 0;
        prod = 0;
        while (cons < inlen) {
            tmp = 5;
            tmp2 = inlen - cons;
    
            printf("%ld %ld\n", cons, prod);
            ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
            cons += tmp2;
            prod += tmp;
            printf("%ld %ld\n", cons, prod);
        }
        output2[outlen] = 0;
        printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
               prod, output2);
    
        /*
         * input chunking
         */
        cons = 0;
        prod = 0;
        while (cons < inlen) {
            tmp = 100 - prod;
            tmp2 = inlen - cons;
            if (tmp2 > 5)
                tmp2 = 5;
    
            printf("%ld %ld\n", cons, prod);
            ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
            cons += tmp2;
            prod += tmp;
            printf("%ld %ld\n", cons, prod);
        }
        output3[outlen] = 0;
        printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
               prod, output3);
        return (0);
    
    }
    #endif
    #endif /* NOT_USED_YET */
    #define bottom_xmlreader
    #include "elfgcchack.h"
    #endif /* LIBXML_READER_ENABLED */