Edit

kc3-lang/libxml2/xmlreader.c

Branch :

  • Show log

    Commit

  • Author : Daniel Veillard
    Date : 2003-02-18 21:12:46
    Hash : d431074c
    Message : float/double check bugfix exported a function for NMTOKEN validation add a * xmlschemastypes.c: float/double check bugfix * tree.c include/libxml/tree.h: exported a function for NMTOKEN validation * xmlreader.c: add a TODO for Jody * relaxng.c: bugfix bugfix bugfix found 373 test schemas: 300 success 73 failures found 529 test instances: 507 success 10 failures * result/relaxng/*: updated the results Daniel

  • 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:
     *   - provide an API to expand part of the tree
     *   - provide an API to preserve part of the tree
     *   - Streaming XInclude support
     *   - validation against a provided DTD
     *   - XML Schemas validation
     *   - setting(s) for NoBlanks
     *   - performances and tuning ...
     */
    #define IN_LIBXML
    #include "libxml.h"
    
    #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>
    
    /* #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
    
    /************************************************************************
     *									*
     *	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_MODE_INITIAL = 0,
        XML_TEXTREADER_MODE_INTERACTIVE = 1,
        XML_TEXTREADER_MODE_ERROR = 2,
        XML_TEXTREADER_MODE_EOF =3,
        XML_TEXTREADER_MODE_CLOSED = 4,
        XML_TEXTREADER_MODE_READING = 5
    } xmlTextReaderMode;
    
    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
    } xmlTextReaderState;
    
    struct _xmlTextReader {
        int				mode;	/* the parsing mode */
        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 */
        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 */
    
        /* 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 */
    };
    
    static const char *xmlTextReaderIsEmpty = "This element is empty";
    
    #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 (0);
        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] = 0;
        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;
        xmlParserCtxtPtr origctxt;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderStartElement(%s)\n", fullname);
    #endif
        if ((reader != NULL) && (reader->startElement != NULL)) {
    	/*
    	 * when processing an entity, the context may have been changed
    	 */
    	origctxt = reader->ctxt;
    	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->_private = (void *) xmlTextReaderIsEmpty;
        }
        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;
        xmlParserCtxtPtr origctxt;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderEndElement(%s)\n", fullname);
    #endif
        if ((reader != NULL) && (reader->endElement != NULL)) {
    	/*
    	 * when processing an entity, the context may have been changed
    	 */
    	origctxt = reader->ctxt;
    
    	reader->endElement(ctx, fullname);
        }
    }
    
    /**
     * 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;
        xmlParserCtxtPtr origctxt;
        xmlTextReaderPtr reader = ctxt->_private;
    
    #ifdef DEBUG_CALLBACKS
        printf("xmlTextReaderCharacters()\n");
    #endif
        if ((reader != NULL) && (reader->characters != NULL)) {
    	reader->characters(ctx, ch, len);
    	/*
    	 * when processing an entity, the context may have been changed
    	 */
    	origctxt = reader->ctxt;
        }
    }
    
    /**
     * 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) {
        unsigned int cur = reader->cur;
        xmlBufferPtr inbuf;
        int val;
        int 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 (cur >= inbuf->use) {
    	    /*
    	     * 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) {
    		    reader->mode = XML_TEXTREADER_MODE_EOF;
    		    reader->state = oldstate;
    		    if ((oldstate != XML_TEXTREADER_START) ||
    			(reader->ctxt->myDoc != NULL))
    			return(val);
    		}
    	    } else 
    		break;
    	}
    	/*
    	 * parse by block of 512 bytes
    	 */
    	if ((cur >= reader->cur + 512) || (cur >= inbuf->use)) {
    	    if (cur < inbuf->use)
    		cur = cur + 1;
    	    val = xmlParseChunk(reader->ctxt,
    		          (const char *) &inbuf->content[reader->cur],
    			  cur - reader->cur, 0);
    	    if (val != 0)
    		return(-1);
    	    reader->cur = cur;
    	    break;
    	} else {
    	    cur = cur + 1;
    
    	    /*
    	     * One may have to force a flush at some point when parsing really
    	     * large CDATA sections
    	     */
    	    if ((cur - reader->cur > 4096) && (reader->base == 0) &&
    		(reader->mode == XML_TEXTREADER_MODE_INTERACTIVE)) {
    		cur = cur + 1;
    		val = xmlParseChunk(reader->ctxt,
    			      (const char *) &inbuf->content[reader->cur],
    			      cur - reader->cur, 0);
    		if (val != 0)
    		    return(-1);
    		reader->cur = cur;
    	    }
    	}
        }
        /*
         * Discard the consumed input when needed and possible
         */
        if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
    	if ((reader->cur >= 4096) && (reader->base == 0)) {
    	    val = xmlBufferShrink(inbuf, cur);
    	    if (val >= 0) {
    		reader->cur -= val;
    	    }
    	}
        }
    
        /*
         * At the end of the stream signal that the work is done to the Push
         * parser.
         */
        if (reader->mode == XML_TEXTREADER_MODE_EOF) {
    	if (reader->mode != XML_TEXTREADER_DONE) {
    	    val = xmlParseChunk(reader->ctxt,
    		    (const char *) &inbuf->content[reader->cur], 
    		    cur - reader->cur, 1);
    	    reader->cur = cur;
    	    reader->mode = XML_TEXTREADER_DONE;
    	}
        }
        reader->state = oldstate;
        return(0);
    }
    
    /**
     * xmlTextReaderValidatePush:
     * @reader:  the xmlTextReaderPtr used
     *
     * Push the current node for validation
     */
    static void
    xmlTextReaderValidatePush(xmlTextReaderPtr reader) {
    #ifdef LIBXML_REGEXP_ENABLED
        xmlNodePtr node = reader->node;
    
        if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
    	reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
    				reader->ctxt->myDoc, node, node->name);
        } else {
    	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_REGEXP_ENABLED */
    }
    /**
     * xmlTextReaderValidatePop:
     * @reader:  the xmlTextReaderPtr used
     *
     * Pop the current node from validation
     */
    static void
    xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
    #ifdef LIBXML_REGEXP_ENABLED
        xmlNodePtr node = reader->node;
    
        if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
    	reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
    				reader->ctxt->myDoc, node, node->name);
        } else {
    	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_REGEXP_ENABLED */
    }
    /**
     * 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) {
    #ifdef LIBXML_REGEXP_ENABLED
        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;
    	    }
    	} 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)) {
    	    ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
    			      node->content, xmlStrlen(node->content));
    	}
    
    	/*
    	 * go to next node
    	 */
    	if (node->children != NULL) {
    	    node = node->children;
    	    continue;
    	}
    	if (node->next != NULL) {
    	    node = node->next;
    	    continue;
    	}
    	do {
    	    node = node->parent;
    	    if (node->type == XML_ELEMENT_NODE) {
    		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 */
    }
    
    
    /**
     * 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 = 0;
        xmlNodePtr oldnode = NULL;
    
        if ((reader == NULL) || (reader->ctxt == NULL))
    	return(-1);
        if (reader->ctxt->wellFormed != 1)
    	return(-1);
    
    #ifdef DEBUG_READER
        fprintf(stderr, "\nREAD ");
        DUMP_READER
    #endif
        reader->curnode = NULL;
        if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
    	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
    	/*
    	 * Initial state
    	 */
    	do {
    	    val = xmlTextReaderPushData(reader);
    	    if (val < 0)
    		return(-1);
    	} while ((reader->ctxt->node == NULL) &&
    		 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
    		  (reader->mode != XML_TEXTREADER_DONE)));
    	if (reader->ctxt->node == NULL) {
    	    if (reader->ctxt->myDoc != NULL) {
    		reader->node = reader->ctxt->myDoc->children;
    	    }
    	    if (reader->node == NULL)
    		return(-1);
    	    reader->state = XML_TEXTREADER_ELEMENT;
    	} else {
    	    reader->node = reader->ctxt->nodeTab[0];
    	    reader->state = XML_TEXTREADER_ELEMENT;
    	}
    	reader->depth = 0;
    	goto node_found;
        }
        oldstate = reader->state;
        olddepth = reader->ctxt->nodeNr;
        oldnode = reader->node;
    
    get_next_node:
        /*
         * 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 (((oldstate == XML_TEXTREADER_BACKTRACK) ||
                (reader->node->children == NULL) ||
    	    (reader->node->type == XML_ENTITY_REF_NODE) ||
    	    (reader->node->type == XML_DTD_NODE) ||
    	    (reader->node->type == XML_DOCUMENT_NODE) ||
    	    (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
    	   (reader->node->next == NULL) &&
    	   ((reader->ctxt->node == NULL) ||
    	    (reader->ctxt->node == reader->node) ||
    	    (reader->ctxt->node == reader->node->parent)) &&
    	   (reader->ctxt->nodeNr == olddepth) &&
    	   (reader->ctxt->instate != XML_PARSER_EOF)) {
    	val = xmlTextReaderPushData(reader);
    	if (val < 0)
    	    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_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->_private != (void *)xmlTextReaderIsEmpty)) {
    	    reader->state = XML_TEXTREADER_END;
    	    goto node_found;
    	}
    	if ((reader->ctxt->validate) &&
    	    (reader->node->type == XML_ELEMENT_NODE))
    	    xmlTextReaderValidatePop(reader);
    	reader->node = reader->node->next;
    	reader->state = XML_TEXTREADER_ELEMENT;
    
    	/*
    	 * Cleanup of the old node
    	 */
    	if ((reader->node->prev != NULL) &&
                (reader->node->prev->type != XML_DTD_NODE)) {
    	    xmlNodePtr tmp = reader->node->prev;
    	    xmlUnlinkNode(tmp);
    	    xmlFreeNode(tmp);
    	}
    
    	goto node_found;
        }
        if ((oldstate == XML_TEXTREADER_ELEMENT) &&
    	(reader->node->type == XML_ELEMENT_NODE) &&
    	(reader->node->children == NULL) &&
    	(reader->node->_private != (void *)xmlTextReaderIsEmpty)) {
    	reader->state = XML_TEXTREADER_END;
    	goto node_found;
        }
        if ((reader->ctxt->validate) && (reader->node->type == XML_ELEMENT_NODE))
    	xmlTextReaderValidatePop(reader);
        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_DONE) {
    	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
    	    reader->mode = XML_TEXTREADER_DONE;
    	}
    	reader->node = NULL;
    	reader->depth = -1;
    
    	/*
    	 * Cleanup of the old node
    	 */
    	if (oldnode->type != XML_DTD_NODE) {
    	    xmlUnlinkNode(oldnode);
    	    xmlFreeNode(oldnode);
    	}
    
    	goto node_end;
        }
        reader->depth--;
        reader->state = XML_TEXTREADER_BACKTRACK;
    
    node_found:
        DUMP_READER
    
        /*
         * 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;
    	}
        } else if ((reader->node != NULL) &&
    	       (reader->node->type == XML_ENTITY_REF_NODE) &&
    	       (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
    	xmlTextReaderValidateEntity(reader);
        }
        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->ctxt->validate) && (reader->node != NULL)) {
    	xmlNodePtr node = reader->node;
    	xmlParserCtxtPtr ctxt = reader->ctxt;
    
    	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)) {
    	    ctxt->valid &= xmlValidatePushCData(&ctxt->vctxt,
    			      node->content, xmlStrlen(node->content));
    	}
        }
    #endif /* LIBXML_REGEXP_ENABLED */
        return(1);
    node_end:
        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);
    }
    
    /**
     * 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) {
        TODO
        return(NULL);
    }
    
    /**
     * 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) {
        TODO
        return(NULL);
    }
    
    /**
     * 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) {
        TODO
        return(NULL);
    }
    
    /**
     * 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,
    	                int offset, int len) {
        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,
    	                int offset, int len) {
        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);
    }
    
    /************************************************************************
     *									*
     *			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;
        int val;
    
        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->entTab = NULL;
        ret->entMax = 0;
        ret->entNr = 0;
        ret->input = input;
        ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
        if (ret->sax == NULL) {
    	xmlFree(ret);
            xmlGenericError(xmlGenericErrorContext,
    		"xmlNewTextReader : malloc failed\n");
    	return(NULL);
        }
        memcpy(ret->sax, &xmlDefaultSAXHandler, sizeof(xmlSAXHandler));
        ret->startElement = ret->sax->startElement;
        ret->sax->startElement = xmlTextReaderStartElement;
        ret->endElement = ret->sax->endElement;
        ret->sax->endElement = xmlTextReaderEndElement;
        ret->characters = ret->sax->characters;
        ret->sax->characters = xmlTextReaderCharacters;
        ret->cdataBlock = ret->sax->cdataBlock;
        ret->sax->cdataBlock = xmlTextReaderCDataBlock;
    
        ret->mode = XML_TEXTREADER_MODE_INITIAL;
        ret->node = NULL;
        ret->curnode = NULL;
        val = xmlParserInputBufferRead(input, 4);
        if (val >= 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;
        }
        ret->ctxt->_private = ret;
        ret->ctxt->linenumbers = 1;
        ret->allocs = XML_TEXTREADER_CTXT;
        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;
        if (reader->ctxt != NULL) {
    	if (reader->ctxt->myDoc != NULL) {
    	    xmlFreeDoc(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 = 0;
    	    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->faketext != NULL) {
    	xmlFreeNode(reader->faketext);
        }
        if (reader->entTab != NULL)
    	xmlFree(reader->entTab);
        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) {
    	if (reader->ctxt->myDoc != NULL) {
    	    xmlFreeDoc(reader->ctxt->myDoc);
    	    reader->ctxt->myDoc = NULL;
    	}
    	if (reader->allocs & XML_TEXTREADER_CTXT) {
    	    xmlFreeParserCtxt(reader->ctxt);
    	    reader->allocs -= XML_TEXTREADER_CTXT;
    	}
        }
        if (reader->sax != NULL) {
            xmlFree(reader->sax);
    	reader->sax = 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)
    	return(xmlGetProp(reader->node, name));
        
        ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
        if (ns != NULL)
            ret = xmlGetNsProp(reader->node, localname, ns->href);
    
        if (localname != NULL)
            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) {
        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);
    
        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.
     *
     * 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) {
    	if (reader->ctxt->myDoc != NULL) {
    	    xmlFreeDoc(reader->ctxt->myDoc);
    	    reader->ctxt->myDoc = NULL;
    	}
    	if (reader->allocs & XML_TEXTREADER_CTXT) {
    	    xmlFreeParserCtxt(reader->ctxt);
    	    reader->allocs -= XML_TEXTREADER_CTXT;
    	}
        }
        if (reader->sax != NULL) {
            xmlFree(reader->sax);
    	reader->sax = NULL;
        }
        if (reader->allocs & XML_TEXTREADER_INPUT) {
    	ret = reader->input;
    	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;
    
        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;
    
        /*
         * A priori reading http://www.w3.org/TR/REC-xml-names/ there is no
         * namespace name associated to "xmlns"
         */
        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)
    		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);
    }
    
    /************************************************************************
     *									*
     *			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://dotgnu.org/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(0);
        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(15);
    	    return(1);
            case XML_NAMESPACE_DECL:
            case XML_ATTRIBUTE_NODE:
    	    return(2);
            case XML_TEXT_NODE:
    	    return(3); /* TODO: SignificantWhitespace == 14 Whitespace == 13 */
            case XML_CDATA_SECTION_NODE:
    	    return(4);
            case XML_ENTITY_REF_NODE:
    	    return(5);
            case XML_ENTITY_NODE:
    	    return(6);
            case XML_PI_NODE:
    	    return(7);
            case XML_COMMENT_NODE:
    	    return(8);
            case XML_DOCUMENT_NODE:
            case XML_HTML_DOCUMENT_NODE:
    #ifdef LIBXML_DOCB_ENABLED
            case XML_DOCB_DOCUMENT_NODE:
    #endif
    	    return(9);
            case XML_DOCUMENT_FRAG_NODE:
    	    return(11);
            case XML_NOTATION_NODE:
    	    return(12);
            case XML_DOCUMENT_TYPE_NODE:
            case XML_DTD_NODE:
    	    return(10);
    
            case XML_ELEMENT_DECL:
            case XML_ATTRIBUTE_DECL:
            case XML_ENTITY_DECL:
            case XML_XINCLUDE_START:
            case XML_XINCLUDE_END:
    	    return(0);
        }
        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);
        return(reader->node->_private == (void *)xmlTextReaderIsEmpty);
    }
    
    /**
     * xmlTextReaderLocalName:
     * @reader:  the xmlTextReaderPtr used
     *
     * The local name of the node.
     *
     * Returns the local name or NULL if not available
     */
    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));
    }
    
    /**
     * xmlTextReaderName:
     * @reader:  the xmlTextReaderPtr used
     *
     * The qualified name of the node, equal to Prefix :LocalName.
     *
     * Returns the local name or NULL if not available
     */
    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);
    }
    
    /**
     * xmlTextReaderPrefix:
     * @reader:  the xmlTextReaderPtr used
     *
     * A shorthand reference to the namespace associated with the node.
     *
     * Returns the prefix or NULL if not available
     */
    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);
    }
    
    /**
     * xmlTextReaderNamespaceUri:
     * @reader:  the xmlTextReaderPtr used
     *
     * The URI defining the namespace associated with the node.
     *
     * Returns the namespace URI or NULL if not available
     */
    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);
    }
    
    /**
     * xmlTextReaderBaseUri:
     * @reader:  the xmlTextReaderPtr used
     *
     * The base URI of the node.
     *
     * Returns the base URI or NULL if not available
     */
    xmlChar *
    xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->node == NULL))
    	return(NULL);
        return(xmlNodeGetBase(NULL, reader->node));
    }
    
    /**
     * 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))
    	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:
    	    return(1);
    	default:
    	    return(0);
        }
        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 retsult 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:
    	    return(NULL);
        }
        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.
     */
    xmlChar *
    xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
        if (reader == NULL)
    	return(NULL);
        if (reader->node == NULL)
    	return(NULL);
        return(xmlNodeGetLang(reader->node));
    }
    
    /**
     * 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;
    	    } 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(ctxt->validate);
    	case XML_PARSER_SUBST_ENTITIES:
    	    return(ctxt->replaceEntities);
        }
        return(-1);
    }
    
    /**
     * 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);
    }
    
    /**
     * xmlTextReaderCurrentDoc:
     * @reader:  the xmlTextReaderPtr used
     *
     * Hacking interface allowing to get the xmlDocPtr correponding to the
     * current document being accessed by the xmlTextReader. This is dangerous
     * because the associated node may be destroyed on the next Reads.
     *
     * Returns the xmlDocPtr or NULL in case of error.
     */
    xmlDocPtr
    xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
        if ((reader == NULL) || (reader->ctxt == NULL))
    	return(NULL);
        
        return(reader->ctxt->myDoc);
    }
    
    /************************************************************************
     *									*
     *			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;
        int chars;
        char *larger;
        char *str;
    
        str = (char *) xmlMalloc(150);
        if (str == NULL) {
    	xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
            return NULL;
        }
    
        size = 150;
    
        while (1) {
            chars = vsnprintf(str, size, msg, ap);
            if ((chars > -1) && (chars < size))
                break;
            if (chars > -1)
                size += chars + 1;
            else
                size += 100;
            if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
    	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
                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 (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.
     */
    xmlChar *
    xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
        /* we know that locator is a xmlParserCtxtPtr */
        xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
        xmlChar *ret = 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(input->filename);
    	} 
    	else {
    	    ret = NULL;
    	}
        }
    
        return ret;
    }
    
    static void
    xmlTextReaderGenericError(void *ctxt, int severity, char *str) {
        xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
        xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
    
        if (str != NULL) {
    	reader->errorFunc(reader->errorFuncArg,
    			  str,
    			  severity,
    			  (xmlTextReaderLocatorPtr)ctx);
    	xmlFree(str);
        }
    }
    
    static void 
    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 
    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 
    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 
    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->vctxt.error = xmlTextReaderValidityError;
    	reader->ctxt->sax->warning = xmlTextReaderWarning;
    	reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
    	reader->errorFunc = f;
    	reader->errorFuncArg = arg;
        }
        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->errorFuncArg = NULL;
        }
    }
    
    /**
     * 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) {
        *f = reader->errorFunc;
        *arg = reader->errorFuncArg;
    }
    
    /************************************************************************
     *									*
     *			Utilities					*
     *									*
     ************************************************************************/
    /**
     * 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[3], 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);
        
        /*
         * 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