Edit

kc3-lang/libxml2/xmlreader.c

Branch :

  • Show log

    Commit

  • Author : Daniel Veillard
    Date : 2002-12-16 22:04:11
    Hash : 67df809c
    Message : Vyacheslav Pindyura managed to trigger a bug in parseStartTag, fixing it. * parser.c: Vyacheslav Pindyura managed to trigger a bug in parseStartTag, fixing it. * test/att4 result/att4 result/noent/att4: adding the test * xmlreader.c include/libxml/xmlreader.h doc/libxml2-api.xml: added more methods to XmlTextReader. 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
     */
    
    #define IN_LIBXML
    #include "libxml.h"
    
    #include <string.h> /* for memset() only ! */
    
    #ifdef HAVE_CTYPE_H
    #include <ctype.h>
    #endif
    #ifdef HAVE_STDLIB_H
    #include <stdlib.h>
    #endif
    
    #include <libxml/xmlmemory.h>
    #include <libxml/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
    } 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 */
        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 */
    };
    
    #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
    
    /**
     * 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);
        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);
        if (reader->state == XML_TEXTREADER_ELEMENT)
    	reader->state = XML_TEXTREADER_EMPTY;
        else
    	reader->state = XML_TEXTREADER_END;
    }
    
    /**
     * 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;
    
        if ((reader->input == NULL) || (reader->input->buffer == NULL))
    	return(-1);
    
        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;
    		    return(val);
    		}
    	    } else 
    		break;
    	}
    	if ((inbuf->content[cur] == '>') || (inbuf->content[cur] == '&')) {
    	    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) && (cur >= inbuf->use)) {
    	val = xmlParseChunk(reader->ctxt,
    		(const char *) &inbuf->content[reader->cur], 0, 1);
        }
        return(0);
    }
    
    /**
     * 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;
        xmlTextReaderState oldstate;
        xmlNodePtr oldnode;
    
        if ((reader == NULL) || (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)
    		return(-1);
    	} while ((reader->ctxt->node == NULL) &&
    		 (reader->mode != XML_TEXTREADER_MODE_EOF));
    	if (reader->ctxt->node == NULL) {
    	    if (reader->ctxt->myDoc != NULL)
    		reader->node = reader->ctxt->myDoc->children;
    	    if (reader->node == NULL)
    		return(-1);
    	} else {
    	    reader->node = reader->ctxt->node;
    	}
    	reader->depth = 1;
    	return(1);
        }
        oldstate = reader->state;
        olddepth = reader->ctxt->nodeNr;
        oldnode = reader->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.
         */
        if (oldstate != XML_TEXTREADER_BACKTRACK) {
    	while (((reader->node->children == NULL) ||
    		(reader->node->type == XML_ENTITY_REF_NODE) ||
    		(reader->node->type == XML_DTD_NODE)) &&
    	       (reader->node->next == NULL) &&
    	       (reader->ctxt->nodeNr == olddepth) &&
    	       (reader->ctxt->instate != XML_PARSER_EOF)) {
    	    val = xmlTextReaderPushData(reader);
    	    if (val < 0)
    		return(-1);
    	    if (reader->node == NULL)
    		return(0);
    	}
    	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++;
    	    if ((reader->state != XML_TEXTREADER_ELEMENT) &&
    		(reader->state != XML_TEXTREADER_EMPTY))
    		reader->state = XML_TEXTREADER_ELEMENT;
    	    DUMP_READER
    	    return(1);
    	}
        }
        if (reader->node->next != NULL) {
    	if ((oldstate == XML_TEXTREADER_ELEMENT) &&
                (reader->node->type == XML_ELEMENT_NODE)) {
    	    reader->state = XML_TEXTREADER_END;
    	    DUMP_READER
    	    return(1);
    	}
    	reader->node = reader->node->next;
    	reader->state = XML_TEXTREADER_ELEMENT;
    	DUMP_READER
    	/*
    	 * Cleanup of the old node
    	 */
    	if (oldnode->type != XML_DTD_NODE) {
    	    xmlUnlinkNode(oldnode);
    	    xmlFreeNode(oldnode);
    	}
    
    	return(1);
        }
        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)) {
    	reader->node = NULL;
    	reader->depth = 0;
    
    	/*
    	 * Cleanup of the old node
    	 */
    	if (oldnode->type != XML_DTD_NODE) {
    	    xmlUnlinkNode(oldnode);
    	    xmlFreeNode(oldnode);
    	}
    
    	return(0);
        }
        reader->depth--;
        reader->state = XML_TEXTREADER_BACKTRACK;
        DUMP_READER
        return(1);
    }
    
    /**
     * 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);
    }
    
    /************************************************************************
     *									*
     *			Constructor and destructors			*
     *									*
     ************************************************************************/
    /**
     * xmlNewTextReader:
     * @input: the xmlParserInputBufferPtr used to read data
     *
     * Create an xmlTextReader structure fed with @input
     *
     * Returns the new xmlTextReaderPtr or NULL in case of error
     */
    xmlTextReaderPtr
    xmlNewTextReader(xmlParserInputBufferPtr input) {
        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->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->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, NULL);
    	ret->base = 0;
    	ret->cur = 4;
        } else {
    	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, NULL);
    	ret->base = 0;
    	ret->cur = 0;
        }
        ret->ctxt->_private = ret;
        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;
    
        input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
        if (input == NULL)
    	return(NULL);
        ret = xmlNewTextReader(input);
        if (ret == NULL) {
    	xmlFreeParserInputBuffer(input);
    	return(NULL);
        }
        ret->allocs |= XML_TEXTREADER_INPUT;
        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->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);
        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);
    }
    
    /************************************************************************
     *									*
     *			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_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_NAMESPACE_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->children != NULL)
    	return(0);
        if ((reader->state == XML_TEXTREADER_EMPTY) ||
    	(reader->state == XML_TEXTREADER_BACKTRACK))
    	return(1);
        return(0);
    }
    
    /**
     * 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) {
    	xmlNsPtr ns = (xmlNsPtr) node;
    	return(xmlStrdup(ns->href));
        }
        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);
    
        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);
    }