root/third_party/libxml/src/xmlreader.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xmlFreeID
  2. xmlTextReaderRemoveID
  3. xmlTextReaderFreeProp
  4. xmlTextReaderFreePropList
  5. xmlTextReaderFreeNodeList
  6. xmlTextReaderFreeNode
  7. xmlTextReaderFreeIDTable
  8. xmlTextReaderFreeDoc
  9. xmlTextReaderDebug
  10. xmlTextReaderEntPush
  11. xmlTextReaderEntPop
  12. xmlTextReaderStartElement
  13. xmlTextReaderEndElement
  14. xmlTextReaderStartElementNs
  15. xmlTextReaderEndElementNs
  16. xmlTextReaderCharacters
  17. xmlTextReaderCDataBlock
  18. xmlTextReaderPushData
  19. xmlTextReaderValidatePush
  20. xmlTextReaderValidateCData
  21. xmlTextReaderValidatePop
  22. xmlTextReaderValidateEntity
  23. xmlTextReaderGetSuccessor
  24. xmlTextReaderDoExpand
  25. xmlTextReaderCollectSiblings
  26. xmlTextReaderRead
  27. xmlTextReaderReadState
  28. xmlTextReaderExpand
  29. xmlTextReaderNext
  30. xmlTextReaderReadInnerXml
  31. xmlTextReaderReadOuterXml
  32. xmlTextReaderReadString
  33. xmlTextReaderReadBase64
  34. xmlTextReaderReadBinHex
  35. xmlTextReaderNextTree
  36. xmlTextReaderReadTree
  37. xmlTextReaderNextSibling
  38. xmlNewTextReader
  39. xmlNewTextReaderFilename
  40. xmlFreeTextReader
  41. xmlTextReaderClose
  42. xmlTextReaderGetAttributeNo
  43. xmlTextReaderGetAttribute
  44. xmlTextReaderGetAttributeNs
  45. xmlTextReaderGetRemainder
  46. xmlTextReaderLookupNamespace
  47. xmlTextReaderMoveToAttributeNo
  48. xmlTextReaderMoveToAttribute
  49. xmlTextReaderMoveToAttributeNs
  50. xmlTextReaderMoveToFirstAttribute
  51. xmlTextReaderMoveToNextAttribute
  52. xmlTextReaderMoveToElement
  53. xmlTextReaderReadAttributeValue
  54. xmlTextReaderConstEncoding
  55. xmlTextReaderAttributeCount
  56. xmlTextReaderNodeType
  57. xmlTextReaderIsEmptyElement
  58. xmlTextReaderLocalName
  59. xmlTextReaderConstLocalName
  60. xmlTextReaderName
  61. xmlTextReaderConstName
  62. xmlTextReaderPrefix
  63. xmlTextReaderConstPrefix
  64. xmlTextReaderNamespaceUri
  65. xmlTextReaderConstNamespaceUri
  66. xmlTextReaderBaseUri
  67. xmlTextReaderConstBaseUri
  68. xmlTextReaderDepth
  69. xmlTextReaderHasAttributes
  70. xmlTextReaderHasValue
  71. xmlTextReaderValue
  72. xmlTextReaderConstValue
  73. xmlTextReaderIsDefault
  74. xmlTextReaderQuoteChar
  75. xmlTextReaderXmlLang
  76. xmlTextReaderConstXmlLang
  77. xmlTextReaderConstString
  78. xmlTextReaderNormalization
  79. xmlTextReaderSetParserProp
  80. xmlTextReaderGetParserProp
  81. xmlTextReaderGetParserLineNumber
  82. xmlTextReaderGetParserColumnNumber
  83. xmlTextReaderCurrentNode
  84. xmlTextReaderPreserve
  85. xmlTextReaderPreservePattern
  86. xmlTextReaderCurrentDoc
  87. xmlTextReaderValidityErrorRelay
  88. xmlTextReaderValidityWarningRelay
  89. xmlTextReaderValidityStructuredRelay
  90. xmlTextReaderRelaxNGSetSchema
  91. xmlTextReaderSetSchema
  92. xmlTextReaderRelaxNGValidate
  93. xmlTextReaderSchemaValidateInternal
  94. xmlTextReaderSchemaValidateCtxt
  95. xmlTextReaderSchemaValidate
  96. xmlTextReaderIsNamespaceDecl
  97. xmlTextReaderConstXmlVersion
  98. xmlTextReaderStandalone
  99. xmlTextReaderBuildMessage
  100. xmlTextReaderLocatorLineNumber
  101. xmlTextReaderLocatorBaseURI
  102. xmlTextReaderGenericError
  103. xmlTextReaderStructuredError
  104. xmlTextReaderError
  105. xmlTextReaderWarning
  106. xmlTextReaderValidityError
  107. xmlTextReaderValidityWarning
  108. xmlTextReaderSetErrorHandler
  109. xmlTextReaderSetStructuredErrorHandler
  110. xmlTextReaderIsValid
  111. xmlTextReaderGetErrorHandler
  112. xmlTextReaderSetup
  113. xmlTextReaderByteConsumed
  114. xmlReaderWalker
  115. xmlReaderForDoc
  116. xmlReaderForFile
  117. xmlReaderForMemory
  118. xmlReaderForFd
  119. xmlReaderForIO
  120. xmlReaderNewWalker
  121. xmlReaderNewDoc
  122. xmlReaderNewFile
  123. xmlReaderNewMemory
  124. xmlReaderNewFd
  125. xmlReaderNewIO
  126. xmlBase64Decode
  127. main

/*
 * xmlreader.c: implements the xmlTextReader streaming node API
 *
 * NOTE:
 *   XmlTextReader.Normalization Property won't be supported, since
 *     it makes the parser non compliant to the XML recommendation
 *
 * See Copyright for the status of this software.
 *
 * daniel@veillard.com
 */

/*
 * TODOs:
 *   - XML Schemas validation
 */
#define IN_LIBXML
#include "libxml.h"

#ifdef LIBXML_READER_ENABLED
#include <string.h> /* for memset() only ! */
#include <stdarg.h>

#ifdef HAVE_CTYPE_H
#include <ctype.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#include <libxml/xmlmemory.h>
#include <libxml/xmlIO.h>
#include <libxml/xmlreader.h>
#include <libxml/parserInternals.h>
#ifdef LIBXML_SCHEMAS_ENABLED
#include <libxml/relaxng.h>
#include <libxml/xmlschemas.h>
#endif
#include <libxml/uri.h>
#ifdef LIBXML_XINCLUDE_ENABLED
#include <libxml/xinclude.h>
#endif
#ifdef LIBXML_PATTERN_ENABLED
#include <libxml/pattern.h>
#endif

#define MAX_ERR_MSG_SIZE 64000

/*
 * The following VA_COPY was coded following an example in
 * the Samba project.  It may not be sufficient for some
 * esoteric implementations of va_list (i.e. it may need
 * something involving a memcpy) but (hopefully) will be
 * sufficient for libxml2.
 */
#ifndef VA_COPY
  #ifdef HAVE_VA_COPY
    #define VA_COPY(dest, src) va_copy(dest, src)
  #else
    #ifdef HAVE___VA_COPY
      #define VA_COPY(dest,src) __va_copy(dest, src)
    #else
      #define VA_COPY(dest,src) (dest) = (src)
    #endif
  #endif
#endif

/* #define DEBUG_CALLBACKS */
/* #define DEBUG_READER */

/**
 * TODO:
 *
 * macro to flag unimplemented blocks
 */
#define TODO                                                            \
    xmlGenericError(xmlGenericErrorContext,                             \
            "Unimplemented block at %s:%d\n",                           \
            __FILE__, __LINE__);

#ifdef DEBUG_READER
#define DUMP_READER xmlTextReaderDebug(reader);
#else
#define DUMP_READER
#endif

#define CHUNK_SIZE 512
/************************************************************************
 *                                                                      *
 *      The parser: maps the Text Reader API on top of the existing     *
 *              parsing routines building a tree                        *
 *                                                                      *
 ************************************************************************/

#define XML_TEXTREADER_INPUT    1
#define XML_TEXTREADER_CTXT     2

typedef enum {
    XML_TEXTREADER_NONE = -1,
    XML_TEXTREADER_START= 0,
    XML_TEXTREADER_ELEMENT= 1,
    XML_TEXTREADER_END= 2,
    XML_TEXTREADER_EMPTY= 3,
    XML_TEXTREADER_BACKTRACK= 4,
    XML_TEXTREADER_DONE= 5,
    XML_TEXTREADER_ERROR= 6
} xmlTextReaderState;

typedef enum {
    XML_TEXTREADER_NOT_VALIDATE = 0,
    XML_TEXTREADER_VALIDATE_DTD = 1,
    XML_TEXTREADER_VALIDATE_RNG = 2,
    XML_TEXTREADER_VALIDATE_XSD = 4
} xmlTextReaderValidate;

struct _xmlTextReader {
    int                         mode;   /* the parsing mode */
    xmlDocPtr                   doc;    /* when walking an existing doc */
    xmlTextReaderValidate       validate;/* is there any validation */
    int                         allocs; /* what structure were deallocated */
    xmlTextReaderState          state;
    xmlParserCtxtPtr            ctxt;   /* the parser context */
    xmlSAXHandlerPtr            sax;    /* the parser SAX callbacks */
    xmlParserInputBufferPtr     input;  /* the input */
    startElementSAXFunc         startElement;/* initial SAX callbacks */
    endElementSAXFunc           endElement;  /* idem */
    startElementNsSAX2Func      startElementNs;/* idem */
    endElementNsSAX2Func        endElementNs;  /* idem */
    charactersSAXFunc           characters;
    cdataBlockSAXFunc           cdataBlock;
    unsigned int                base;   /* base of the segment in the input */
    unsigned int                cur;    /* current position in the input */
    xmlNodePtr                  node;   /* current node */
    xmlNodePtr                  curnode;/* current attribute node */
    int                         depth;  /* depth of the current node */
    xmlNodePtr                  faketext;/* fake xmlNs chld */
    int                         preserve;/* preserve the resulting document */
    xmlBufferPtr                buffer; /* used to return const xmlChar * */
    xmlDictPtr                  dict;   /* the context dictionnary */

    /* entity stack when traversing entities content */
    xmlNodePtr         ent;          /* Current Entity Ref Node */
    int                entNr;        /* Depth of the entities stack */
    int                entMax;       /* Max depth of the entities stack */
    xmlNodePtr        *entTab;       /* array of entities */

    /* error handling */
    xmlTextReaderErrorFunc errorFunc;    /* callback function */
    void                  *errorFuncArg; /* callback function user argument */

#ifdef LIBXML_SCHEMAS_ENABLED
    /* Handling of RelaxNG validation */
    xmlRelaxNGPtr          rngSchemas;  /* The Relax NG schemas */
    xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */
    int                    rngValidErrors;/* The number of errors detected */
    xmlNodePtr             rngFullNode; /* the node if RNG not progressive */
    /* Handling of Schemas validation */
    xmlSchemaPtr          xsdSchemas;   /* The Schemas schemas */
    xmlSchemaValidCtxtPtr xsdValidCtxt;/* The Schemas validation context */
    int                   xsdPreserveCtxt; /* 1 if the context was provided by the user */
    int                   xsdValidErrors;/* The number of errors detected */
    xmlSchemaSAXPlugPtr   xsdPlug;      /* the schemas plug in SAX pipeline */
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
    /* Handling of XInclude processing */
    int                xinclude;        /* is xinclude asked for */
    const xmlChar *    xinclude_name;   /* the xinclude name from dict */
    xmlXIncludeCtxtPtr xincctxt;        /* the xinclude context */
    int                in_xinclude;     /* counts for xinclude */
#endif
#ifdef LIBXML_PATTERN_ENABLED
    int                patternNr;       /* number of preserve patterns */
    int                patternMax;      /* max preserve patterns */
    xmlPatternPtr     *patternTab;      /* array of preserve patterns */
#endif
    int                preserves;       /* level of preserves */
    int                parserFlags;     /* the set of options set */
    /* Structured error handling */
    xmlStructuredErrorFunc sErrorFunc;  /* callback function */
};

#define NODE_IS_EMPTY           0x1
#define NODE_IS_PRESERVED       0x2
#define NODE_IS_SPRESERVED      0x4

/**
 * CONSTSTR:
 *
 * Macro used to return an interned string
 */
#define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1)
#define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str))

static int xmlTextReaderReadTree(xmlTextReaderPtr reader);
static int xmlTextReaderNextTree(xmlTextReaderPtr reader);

/************************************************************************
 *                                                                      *
 *      Our own version of the freeing routines as we recycle nodes     *
 *                                                                      *
 ************************************************************************/
/**
 * DICT_FREE:
 * @str:  a string
 *
 * Free a string if it is not owned by the "dict" dictionnary in the
 * current scope
 */
#define DICT_FREE(str)                                          \
        if ((str) && ((!dict) ||                                \
            (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))  \
            xmlFree((char *)(str));

static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);

/**
 * xmlFreeID:
 * @not:  A id
 *
 * Deallocate the memory used by an id definition
 */
static void
xmlFreeID(xmlIDPtr id) {
    xmlDictPtr dict = NULL;

    if (id == NULL) return;

    if (id->doc != NULL)
        dict = id->doc->dict;

    if (id->value != NULL)
        DICT_FREE(id->value)
    xmlFree(id);
}

/**
 * xmlTextReaderRemoveID:
 * @doc:  the document
 * @attr:  the attribute
 *
 * Remove the given attribute from the ID table maintained internally.
 *
 * Returns -1 if the lookup failed and 0 otherwise
 */
static int
xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
    xmlIDTablePtr table;
    xmlIDPtr id;
    xmlChar *ID;

    if (doc == NULL) return(-1);
    if (attr == NULL) return(-1);
    table = (xmlIDTablePtr) doc->ids;
    if (table == NULL)
        return(-1);

    ID = xmlNodeListGetString(doc, attr->children, 1);
    if (ID == NULL)
        return(-1);
    id = xmlHashLookup(table, ID);
    xmlFree(ID);
    if (id == NULL || id->attr != attr) {
        return(-1);
    }
    id->name = attr->name;
    id->attr = NULL;
    return(0);
}

/**
 * xmlTextReaderFreeProp:
 * @reader:  the xmlTextReaderPtr used
 * @cur:  the node
 *
 * Free a node.
 */
static void
xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
    xmlDictPtr dict;

    dict = reader->ctxt->dict;
    if (cur == NULL) return;

    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
        xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);

    /* Check for ID removal -> leading to invalid references ! */
    if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
        ((cur->parent->doc->intSubset != NULL) ||
         (cur->parent->doc->extSubset != NULL))) {
        if (xmlIsID(cur->parent->doc, cur->parent, cur))
            xmlTextReaderRemoveID(cur->parent->doc, cur);
    }
    if (cur->children != NULL)
        xmlTextReaderFreeNodeList(reader, cur->children);

    DICT_FREE(cur->name);
    if ((reader != NULL) && (reader->ctxt != NULL) &&
        (reader->ctxt->freeAttrsNr < 100)) {
        cur->next = reader->ctxt->freeAttrs;
        reader->ctxt->freeAttrs = cur;
        reader->ctxt->freeAttrsNr++;
    } else {
        xmlFree(cur);
    }
}

/**
 * xmlTextReaderFreePropList:
 * @reader:  the xmlTextReaderPtr used
 * @cur:  the first property in the list
 *
 * Free a property and all its siblings, all the children are freed too.
 */
static void
xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
    xmlAttrPtr next;
    if (cur == NULL) return;
    while (cur != NULL) {
        next = cur->next;
        xmlTextReaderFreeProp(reader, cur);
        cur = next;
    }
}

/**
 * xmlTextReaderFreeNodeList:
 * @reader:  the xmlTextReaderPtr used
 * @cur:  the first node in the list
 *
 * Free a node and all its siblings, this is a recursive behaviour, all
 * the children are freed too.
 */
static void
xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
    xmlNodePtr next;
    xmlDictPtr dict;

    dict = reader->ctxt->dict;
    if (cur == NULL) return;
    if (cur->type == XML_NAMESPACE_DECL) {
        xmlFreeNsList((xmlNsPtr) cur);
        return;
    }
    if ((cur->type == XML_DOCUMENT_NODE) ||
        (cur->type == XML_HTML_DOCUMENT_NODE)) {
        xmlFreeDoc((xmlDocPtr) cur);
        return;
    }
    while (cur != NULL) {
        next = cur->next;
        /* unroll to speed up freeing the document */
        if (cur->type != XML_DTD_NODE) {

            if ((cur->children != NULL) &&
                (cur->type != XML_ENTITY_REF_NODE)) {
                if (cur->children->parent == cur)
                    xmlTextReaderFreeNodeList(reader, cur->children);
                cur->children = NULL;
            }

            if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
                xmlDeregisterNodeDefaultValue(cur);

            if (((cur->type == XML_ELEMENT_NODE) ||
                 (cur->type == XML_XINCLUDE_START) ||
                 (cur->type == XML_XINCLUDE_END)) &&
                (cur->properties != NULL))
                xmlTextReaderFreePropList(reader, cur->properties);
            if ((cur->content != (xmlChar *) &(cur->properties)) &&
                (cur->type != XML_ELEMENT_NODE) &&
                (cur->type != XML_XINCLUDE_START) &&
                (cur->type != XML_XINCLUDE_END) &&
                (cur->type != XML_ENTITY_REF_NODE)) {
                DICT_FREE(cur->content);
            }
            if (((cur->type == XML_ELEMENT_NODE) ||
                 (cur->type == XML_XINCLUDE_START) ||
                 (cur->type == XML_XINCLUDE_END)) &&
                (cur->nsDef != NULL))
                xmlFreeNsList(cur->nsDef);

            /*
             * we don't free element names here they are interned now
             */
            if ((cur->type != XML_TEXT_NODE) &&
                (cur->type != XML_COMMENT_NODE))
                DICT_FREE(cur->name);
            if (((cur->type == XML_ELEMENT_NODE) ||
                 (cur->type == XML_TEXT_NODE)) &&
                (reader != NULL) && (reader->ctxt != NULL) &&
                (reader->ctxt->freeElemsNr < 100)) {
                cur->next = reader->ctxt->freeElems;
                reader->ctxt->freeElems = cur;
                reader->ctxt->freeElemsNr++;
            } else {
                xmlFree(cur);
            }
        }
        cur = next;
    }
}

/**
 * xmlTextReaderFreeNode:
 * @reader:  the xmlTextReaderPtr used
 * @cur:  the node
 *
 * Free a node, this is a recursive behaviour, all the children are freed too.
 * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
 */
static void
xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
    xmlDictPtr dict;

    dict = reader->ctxt->dict;
    if (cur->type == XML_DTD_NODE) {
        xmlFreeDtd((xmlDtdPtr) cur);
        return;
    }
    if (cur->type == XML_NAMESPACE_DECL) {
        xmlFreeNs((xmlNsPtr) cur);
        return;
    }
    if (cur->type == XML_ATTRIBUTE_NODE) {
        xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
        return;
    }

    if ((cur->children != NULL) &&
        (cur->type != XML_ENTITY_REF_NODE)) {
        if (cur->children->parent == cur)
            xmlTextReaderFreeNodeList(reader, cur->children);
        cur->children = NULL;
    }

    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
        xmlDeregisterNodeDefaultValue(cur);

    if (((cur->type == XML_ELEMENT_NODE) ||
         (cur->type == XML_XINCLUDE_START) ||
         (cur->type == XML_XINCLUDE_END)) &&
        (cur->properties != NULL))
        xmlTextReaderFreePropList(reader, cur->properties);
    if ((cur->content != (xmlChar *) &(cur->properties)) &&
        (cur->type != XML_ELEMENT_NODE) &&
        (cur->type != XML_XINCLUDE_START) &&
        (cur->type != XML_XINCLUDE_END) &&
        (cur->type != XML_ENTITY_REF_NODE)) {
        DICT_FREE(cur->content);
    }
    if (((cur->type == XML_ELEMENT_NODE) ||
         (cur->type == XML_XINCLUDE_START) ||
         (cur->type == XML_XINCLUDE_END)) &&
        (cur->nsDef != NULL))
        xmlFreeNsList(cur->nsDef);

    /*
     * we don't free names here they are interned now
     */
    if ((cur->type != XML_TEXT_NODE) &&
        (cur->type != XML_COMMENT_NODE))
        DICT_FREE(cur->name);

    if (((cur->type == XML_ELEMENT_NODE) ||
         (cur->type == XML_TEXT_NODE)) &&
        (reader != NULL) && (reader->ctxt != NULL) &&
        (reader->ctxt->freeElemsNr < 100)) {
        cur->next = reader->ctxt->freeElems;
        reader->ctxt->freeElems = cur;
        reader->ctxt->freeElemsNr++;
    } else {
        xmlFree(cur);
    }
}

/**
 * xmlTextReaderFreeIDTable:
 * @table:  An id table
 *
 * Deallocate the memory used by an ID hash table.
 */
static void
xmlTextReaderFreeIDTable(xmlIDTablePtr table) {
    xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
}

/**
 * xmlTextReaderFreeDoc:
 * @reader:  the xmlTextReaderPtr used
 * @cur:  pointer to the document
 *
 * Free up all the structures used by a document, tree included.
 */
static void
xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
    xmlDtdPtr extSubset, intSubset;

    if (cur == NULL) return;

    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
        xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);

    /*
     * Do this before freeing the children list to avoid ID lookups
     */
    if (cur->ids != NULL) xmlTextReaderFreeIDTable((xmlIDTablePtr) cur->ids);
    cur->ids = NULL;
    if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
    cur->refs = NULL;
    extSubset = cur->extSubset;
    intSubset = cur->intSubset;
    if (intSubset == extSubset)
        extSubset = NULL;
    if (extSubset != NULL) {
        xmlUnlinkNode((xmlNodePtr) cur->extSubset);
        cur->extSubset = NULL;
        xmlFreeDtd(extSubset);
    }
    if (intSubset != NULL) {
        xmlUnlinkNode((xmlNodePtr) cur->intSubset);
        cur->intSubset = NULL;
        xmlFreeDtd(intSubset);
    }

    if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);

    if (cur->version != NULL) xmlFree((char *) cur->version);
    if (cur->name != NULL) xmlFree((char *) cur->name);
    if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
    if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
    if (cur->URL != NULL) xmlFree((char *) cur->URL);
    if (cur->dict != NULL) xmlDictFree(cur->dict);

    xmlFree(cur);
}

/************************************************************************
 *                                                                      *
 *                      The reader core parser                          *
 *                                                                      *
 ************************************************************************/
#ifdef DEBUG_READER
static void
xmlTextReaderDebug(xmlTextReaderPtr reader) {
    if ((reader == NULL) || (reader->ctxt == NULL)) {
        fprintf(stderr, "xmlTextReader NULL\n");
        return;
    }
    fprintf(stderr, "xmlTextReader: state %d depth %d ",
            reader->state, reader->depth);
    if (reader->node == NULL) {
        fprintf(stderr, "node = NULL\n");
    } else {
        fprintf(stderr, "node %s\n", reader->node->name);
    }
    fprintf(stderr, "  input: base %d, cur %d, depth %d: ",
            reader->base, reader->cur, reader->ctxt->nodeNr);
    if (reader->input->buffer == NULL) {
        fprintf(stderr, "buffer is NULL\n");
    } else {
#ifdef LIBXML_DEBUG_ENABLED
        xmlDebugDumpString(stderr,
                &reader->input->buffer->content[reader->cur]);
#endif
        fprintf(stderr, "\n");
    }
}
#endif

/**
 * xmlTextReaderEntPush:
 * @reader:  the xmlTextReaderPtr used
 * @value:  the entity reference node
 *
 * Pushes a new entity reference node on top of the entities stack
 *
 * Returns 0 in case of error, the index in the stack otherwise
 */
static int
xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
{
    if (reader->entMax <= 0) {
        reader->entMax = 10;
        reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
                                                  sizeof(reader->entTab[0]));
        if (reader->entTab == NULL) {
            xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
            return (0);
        }
    }
    if (reader->entNr >= reader->entMax) {
        reader->entMax *= 2;
        reader->entTab =
            (xmlNodePtr *) xmlRealloc(reader->entTab,
                                      reader->entMax *
                                      sizeof(reader->entTab[0]));
        if (reader->entTab == NULL) {
            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
            return (0);
        }
    }
    reader->entTab[reader->entNr] = value;
    reader->ent = value;
    return (reader->entNr++);
}

/**
 * xmlTextReaderEntPop:
 * @reader:  the xmlTextReaderPtr used
 *
 * Pops the top element entity from the entities stack
 *
 * Returns the entity just removed
 */
static xmlNodePtr
xmlTextReaderEntPop(xmlTextReaderPtr reader)
{
    xmlNodePtr ret;

    if (reader->entNr <= 0)
        return (NULL);
    reader->entNr--;
    if (reader->entNr > 0)
        reader->ent = reader->entTab[reader->entNr - 1];
    else
        reader->ent = NULL;
    ret = reader->entTab[reader->entNr];
    reader->entTab[reader->entNr] = NULL;
    return (ret);
}

/**
 * xmlTextReaderStartElement:
 * @ctx: the user data (XML parser context)
 * @fullname:  The element name, including namespace prefix
 * @atts:  An array of name/value attributes pairs, NULL terminated
 *
 * called when an opening tag has been processed.
 */
static void
xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
                          const xmlChar **atts) {
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlTextReaderPtr reader = ctxt->_private;

#ifdef DEBUG_CALLBACKS
    printf("xmlTextReaderStartElement(%s)\n", fullname);
#endif
    if ((reader != NULL) && (reader->startElement != NULL)) {
        reader->startElement(ctx, fullname, atts);
        if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
            (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
            (ctxt->input->cur[1] == '>'))
            ctxt->node->extra = NODE_IS_EMPTY;
    }
    if (reader != NULL)
        reader->state = XML_TEXTREADER_ELEMENT;
}

/**
 * xmlTextReaderEndElement:
 * @ctx: the user data (XML parser context)
 * @fullname:  The element name, including namespace prefix
 *
 * called when an ending tag has been processed.
 */
static void
xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlTextReaderPtr reader = ctxt->_private;

#ifdef DEBUG_CALLBACKS
    printf("xmlTextReaderEndElement(%s)\n", fullname);
#endif
    if ((reader != NULL) && (reader->endElement != NULL)) {
        reader->endElement(ctx, fullname);
    }
}

/**
 * xmlTextReaderStartElementNs:
 * @ctx: the user data (XML parser context)
 * @localname:  the local name of the element
 * @prefix:  the element namespace prefix if available
 * @URI:  the element namespace name if available
 * @nb_namespaces:  number of namespace definitions on that node
 * @namespaces:  pointer to the array of prefix/URI pairs namespace definitions
 * @nb_attributes:  the number of attributes on that node
 * nb_defaulted:  the number of defaulted attributes.
 * @attributes:  pointer to the array of (localname/prefix/URI/value/end)
 *               attribute values.
 *
 * called when an opening tag has been processed.
 */
static void
xmlTextReaderStartElementNs(void *ctx,
                      const xmlChar *localname,
                      const xmlChar *prefix,
                      const xmlChar *URI,
                      int nb_namespaces,
                      const xmlChar **namespaces,
                      int nb_attributes,
                      int nb_defaulted,
                      const xmlChar **attributes)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlTextReaderPtr reader = ctxt->_private;

#ifdef DEBUG_CALLBACKS
    printf("xmlTextReaderStartElementNs(%s)\n", localname);
#endif
    if ((reader != NULL) && (reader->startElementNs != NULL)) {
        reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
                               namespaces, nb_attributes, nb_defaulted,
                               attributes);
        if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
            (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
            (ctxt->input->cur[1] == '>'))
            ctxt->node->extra = NODE_IS_EMPTY;
    }
    if (reader != NULL)
        reader->state = XML_TEXTREADER_ELEMENT;
}

/**
 * xmlTextReaderEndElementNs:
 * @ctx: the user data (XML parser context)
 * @localname:  the local name of the element
 * @prefix:  the element namespace prefix if available
 * @URI:  the element namespace name if available
 *
 * called when an ending tag has been processed.
 */
static void
xmlTextReaderEndElementNs(void *ctx,
                          const xmlChar * localname,
                          const xmlChar * prefix,
                          const xmlChar * URI)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlTextReaderPtr reader = ctxt->_private;

#ifdef DEBUG_CALLBACKS
    printf("xmlTextReaderEndElementNs(%s)\n", localname);
#endif
    if ((reader != NULL) && (reader->endElementNs != NULL)) {
        reader->endElementNs(ctx, localname, prefix, URI);
    }
}


/**
 * xmlTextReaderCharacters:
 * @ctx: the user data (XML parser context)
 * @ch:  a xmlChar string
 * @len: the number of xmlChar
 *
 * receiving some chars from the parser.
 */
static void
xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlTextReaderPtr reader = ctxt->_private;

#ifdef DEBUG_CALLBACKS
    printf("xmlTextReaderCharacters()\n");
#endif
    if ((reader != NULL) && (reader->characters != NULL)) {
        reader->characters(ctx, ch, len);
    }
}

/**
 * xmlTextReaderCDataBlock:
 * @ctx: the user data (XML parser context)
 * @value:  The pcdata content
 * @len:  the block length
 *
 * called when a pcdata block has been parsed
 */
static void
xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
{
    xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    xmlTextReaderPtr reader = ctxt->_private;

#ifdef DEBUG_CALLBACKS
    printf("xmlTextReaderCDataBlock()\n");
#endif
    if ((reader != NULL) && (reader->cdataBlock != NULL)) {
        reader->cdataBlock(ctx, ch, len);
    }
}

/**
 * xmlTextReaderPushData:
 * @reader:  the xmlTextReaderPtr used
 *
 * Push data down the progressive parser until a significant callback
 * got raised.
 *
 * Returns -1 in case of failure, 0 otherwise
 */
static int
xmlTextReaderPushData(xmlTextReaderPtr reader) {
    xmlBufferPtr inbuf;
    int val, s;
    xmlTextReaderState oldstate;

    if ((reader->input == NULL) || (reader->input->buffer == NULL))
        return(-1);

    oldstate = reader->state;
    reader->state = XML_TEXTREADER_NONE;
    inbuf = reader->input->buffer;

    while (reader->state == XML_TEXTREADER_NONE) {
        if (inbuf->use < reader->cur + CHUNK_SIZE) {
            /*
             * Refill the buffer unless we are at the end of the stream
             */
            if (reader->mode != XML_TEXTREADER_MODE_EOF) {
                val = xmlParserInputBufferRead(reader->input, 4096);
                if ((val == 0) &&
                    (inbuf->alloc == XML_BUFFER_ALLOC_IMMUTABLE)) {
                    if (inbuf->use == reader->cur) {
                        reader->mode = XML_TEXTREADER_MODE_EOF;
                        reader->state = oldstate;
                    }
                } else if (val < 0) {
                    reader->mode = XML_TEXTREADER_MODE_EOF;
                    reader->state = oldstate;
                    if ((oldstate != XML_TEXTREADER_START) ||
                        (reader->ctxt->myDoc != NULL))
                        return(val);
                } else if (val == 0) {
                    /* mark the end of the stream and process the remains */
                    reader->mode = XML_TEXTREADER_MODE_EOF;
                    break;
                }

            } else
                break;
        }
        /*
         * parse by block of CHUNK_SIZE bytes, various tests show that
         * it's the best tradeoff at least on a 1.2GH Duron
         */
        if (inbuf->use >= reader->cur + CHUNK_SIZE) {
            val = xmlParseChunk(reader->ctxt,
                          (const char *) &inbuf->content[reader->cur],
                          CHUNK_SIZE, 0);
            reader->cur += CHUNK_SIZE;
            if ((val != 0) || (reader->ctxt->wellFormed == 0))
                return(-1);
        } else {
            s = inbuf->use - reader->cur;
            val = xmlParseChunk(reader->ctxt,
                          (const char *) &inbuf->content[reader->cur],
                          s, 0);
            reader->cur += s;
            if ((val != 0) || (reader->ctxt->wellFormed == 0))
                return(-1);
            break;
        }
    }

    /*
     * Discard the consumed input when needed and possible
     */
    if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
        if (inbuf->alloc != XML_BUFFER_ALLOC_IMMUTABLE) {
            if ((reader->cur >= 4096) &&
                (inbuf->use - reader->cur <= CHUNK_SIZE)) {
                val = xmlBufferShrink(inbuf, reader->cur);
                if (val >= 0) {
                    reader->cur -= val;
                }
            }
        }
    }

    /*
     * At the end of the stream signal that the work is done to the Push
     * parser.
     */
    else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
        if (reader->state != XML_TEXTREADER_DONE) {
            s = inbuf->use - reader->cur;
            val = xmlParseChunk(reader->ctxt,
                    (const char *) &inbuf->content[reader->cur],
                    s, 1);
            reader->cur = inbuf->use;
            reader->state  = XML_TEXTREADER_DONE;
            if ((val != 0) || (reader->ctxt->wellFormed == 0))
                return(-1);
        }
    }
    reader->state = oldstate;
    return(0);
}

#ifdef LIBXML_REGEXP_ENABLED
/**
 * xmlTextReaderValidatePush:
 * @reader:  the xmlTextReaderPtr used
 *
 * Push the current node for validation
 */
static void
xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
    xmlNodePtr node = reader->node;

#ifdef LIBXML_VALID_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
        (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
        if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
            reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
                                    reader->ctxt->myDoc, node, node->name);
        } else {
            /* TODO use the BuildQName interface */
            xmlChar *qname;

            qname = xmlStrdup(node->ns->prefix);
            qname = xmlStrcat(qname, BAD_CAST ":");
            qname = xmlStrcat(qname, node->name);
            reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
                                    reader->ctxt->myDoc, node, qname);
            if (qname != NULL)
                xmlFree(qname);
        }
    }
#endif /* LIBXML_VALID_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
               (reader->rngValidCtxt != NULL)) {
        int ret;

        if (reader->rngFullNode != NULL) return;
        ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
                                            reader->ctxt->myDoc,
                                            node);
        if (ret == 0) {
            /*
             * this element requires a full tree
             */
            node = xmlTextReaderExpand(reader);
            if (node == NULL) {
printf("Expand failed !\n");
                ret = -1;
            } else {
                ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
                                                    reader->ctxt->myDoc,
                                                    node);
                reader->rngFullNode = node;
            }
        }
        if (ret != 1)
            reader->rngValidErrors++;
    }
#endif
}

/**
 * xmlTextReaderValidateCData:
 * @reader:  the xmlTextReaderPtr used
 * @data:  pointer to the CData
 * @len:  lenght of the CData block in bytes.
 *
 * Push some CData for validation
 */
static void
xmlTextReaderValidateCData(xmlTextReaderPtr reader,
                           const xmlChar *data, int len) {
#ifdef LIBXML_VALID_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
        (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
        reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
                                                    data, len);
    }
#endif /* LIBXML_VALID_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
               (reader->rngValidCtxt != NULL)) {
        int ret;

        if (reader->rngFullNode != NULL) return;
        ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
        if (ret != 1)
            reader->rngValidErrors++;
    }
#endif
}

/**
 * xmlTextReaderValidatePop:
 * @reader:  the xmlTextReaderPtr used
 *
 * Pop the current node from validation
 */
static void
xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
    xmlNodePtr node = reader->node;

#ifdef LIBXML_VALID_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
        (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
        if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
            reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
                                    reader->ctxt->myDoc, node, node->name);
        } else {
            /* TODO use the BuildQName interface */
            xmlChar *qname;

            qname = xmlStrdup(node->ns->prefix);
            qname = xmlStrcat(qname, BAD_CAST ":");
            qname = xmlStrcat(qname, node->name);
            reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
                                    reader->ctxt->myDoc, node, qname);
            if (qname != NULL)
                xmlFree(qname);
        }
    }
#endif /* LIBXML_VALID_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
               (reader->rngValidCtxt != NULL)) {
        int ret;

        if (reader->rngFullNode != NULL) {
            if (node == reader->rngFullNode)
                reader->rngFullNode = NULL;
            return;
        }
        ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
                                           reader->ctxt->myDoc,
                                           node);
        if (ret != 1)
            reader->rngValidErrors++;
    }
#endif
}

/**
 * xmlTextReaderValidateEntity:
 * @reader:  the xmlTextReaderPtr used
 *
 * Handle the validation when an entity reference is encountered and
 * entity substitution is not activated. As a result the parser interface
 * must walk through the entity and do the validation calls
 */
static void
xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
    xmlNodePtr oldnode = reader->node;
    xmlNodePtr node = reader->node;
    xmlParserCtxtPtr ctxt = reader->ctxt;

    do {
        if (node->type == XML_ENTITY_REF_NODE) {
            /*
             * Case where the underlying tree is not availble, lookup the entity
             * and walk it.
             */
            if ((node->children == NULL) && (ctxt->sax != NULL) &&
                (ctxt->sax->getEntity != NULL)) {
                node->children = (xmlNodePtr)
                    ctxt->sax->getEntity(ctxt, node->name);
            }

            if ((node->children != NULL) &&
                (node->children->type == XML_ENTITY_DECL) &&
                (node->children->children != NULL)) {
                xmlTextReaderEntPush(reader, node);
                node = node->children->children;
                continue;
            } else {
                /*
                 * The error has probably be raised already.
                 */
                if (node == oldnode)
                    break;
                node = node->next;
            }
#ifdef LIBXML_REGEXP_ENABLED
        } else if (node->type == XML_ELEMENT_NODE) {
            reader->node = node;
            xmlTextReaderValidatePush(reader);
        } else if ((node->type == XML_TEXT_NODE) ||
                   (node->type == XML_CDATA_SECTION_NODE)) {
            xmlTextReaderValidateCData(reader, node->content,
                                       xmlStrlen(node->content));
#endif
        }

        /*
         * go to next node
         */
        if (node->children != NULL) {
            node = node->children;
            continue;
        } else if (node->type == XML_ELEMENT_NODE) {
            xmlTextReaderValidatePop(reader);
        }
        if (node->next != NULL) {
            node = node->next;
            continue;
        }
        do {
            node = node->parent;
            if (node->type == XML_ELEMENT_NODE) {
                xmlNodePtr tmp;
                if (reader->entNr == 0) {
                    while ((tmp = node->last) != NULL) {
                        if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
                            xmlUnlinkNode(tmp);
                            xmlTextReaderFreeNode(reader, tmp);
                        } else
                            break;
                    }
                }
                reader->node = node;
                xmlTextReaderValidatePop(reader);
            }
            if ((node->type == XML_ENTITY_DECL) &&
                (reader->ent != NULL) && (reader->ent->children == node)) {
                node = xmlTextReaderEntPop(reader);
            }
            if (node == oldnode)
                break;
            if (node->next != NULL) {
                node = node->next;
                break;
            }
        } while ((node != NULL) && (node != oldnode));
    } while ((node != NULL) && (node != oldnode));
    reader->node = oldnode;
}
#endif /* LIBXML_REGEXP_ENABLED */


/**
 * xmlTextReaderGetSuccessor:
 * @cur:  the current node
 *
 * Get the successor of a node if available.
 *
 * Returns the successor node or NULL
 */
static xmlNodePtr
xmlTextReaderGetSuccessor(xmlNodePtr cur) {
    if (cur == NULL) return(NULL) ; /* ERROR */
    if (cur->next != NULL) return(cur->next) ;
    do {
        cur = cur->parent;
        if (cur == NULL) break;
        if (cur->next != NULL) return(cur->next);
    } while (cur != NULL);
    return(cur);
}

/**
 * xmlTextReaderDoExpand:
 * @reader:  the xmlTextReaderPtr used
 *
 * Makes sure that the current node is fully read as well as all its
 * descendant. It means the full DOM subtree must be available at the
 * end of the call.
 *
 * Returns 1 if the node was expanded successfully, 0 if there is no more
 *          nodes to read, or -1 in case of error
 */
static int
xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
    int val;

    if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
        return(-1);
    do {
        if (reader->ctxt->instate == XML_PARSER_EOF) return(1);

        if (xmlTextReaderGetSuccessor(reader->node) != NULL)
            return(1);
        if (reader->ctxt->nodeNr < reader->depth)
            return(1);
        if (reader->mode == XML_TEXTREADER_MODE_EOF)
            return(1);
        val = xmlTextReaderPushData(reader);
        if (val < 0){
            reader->mode = XML_TEXTREADER_MODE_ERROR;
            return(-1);
        }
    } while(reader->mode != XML_TEXTREADER_MODE_EOF);
    return(1);
}

/**
 * xmlTextReaderCollectSiblings:
 * @node:    the first child
 *
 *  Traverse depth-first through all sibling nodes and their children
 *  nodes and concatenate their content. This is an auxiliary function
 *  to xmlTextReaderReadString.
 *
 *  Returns a string containing the content, or NULL in case of error.
 */
static xmlChar *
xmlTextReaderCollectSiblings(xmlNodePtr node)
{
    xmlBufferPtr buffer;
    xmlChar *ret;

    buffer = xmlBufferCreate();
    if (buffer == NULL)
       return NULL;

    for ( ; node != NULL; node = node->next) {
       switch (node->type) {
       case XML_TEXT_NODE:
       case XML_CDATA_SECTION_NODE:
           xmlBufferCat(buffer, node->content);
           break;
       case XML_ELEMENT_NODE: {
           xmlChar *tmp;

           tmp = xmlTextReaderCollectSiblings(node->children);
           xmlBufferCat(buffer, tmp);
           xmlFree(tmp);
           break;
       }
       default:
           break;
       }
    }
    ret = buffer->content;
    buffer->content = NULL;
    xmlBufferFree(buffer);
    return(ret);
}

/**
 * xmlTextReaderRead:
 * @reader:  the xmlTextReaderPtr used
 *
 *  Moves the position of the current instance to the next node in
 *  the stream, exposing its properties.
 *
 *  Returns 1 if the node was read successfully, 0 if there is no more
 *          nodes to read, or -1 in case of error
 */
int
xmlTextReaderRead(xmlTextReaderPtr reader) {
    int val, olddepth = 0;
    xmlTextReaderState oldstate = XML_TEXTREADER_START;
    xmlNodePtr oldnode = NULL;


    if (reader == NULL)
        return(-1);
    reader->curnode = NULL;
    if (reader->doc != NULL)
        return(xmlTextReaderReadTree(reader));
    if (reader->ctxt == NULL)
        return(-1);
    if (reader->ctxt->wellFormed != 1)
        return(-1);

#ifdef DEBUG_READER
    fprintf(stderr, "\nREAD ");
    DUMP_READER
#endif
    if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
        reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
        /*
         * Initial state
         */
        do {
            val = xmlTextReaderPushData(reader);
                if (val < 0){
                        reader->mode = XML_TEXTREADER_MODE_ERROR;
                        reader->state = XML_TEXTREADER_ERROR;
                return(-1);
                }
        } while ((reader->ctxt->node == NULL) &&
                 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
                  (reader->state != XML_TEXTREADER_DONE)));
        if (reader->ctxt->node == NULL) {
            if (reader->ctxt->myDoc != NULL) {
                reader->node = reader->ctxt->myDoc->children;
            }
            if (reader->node == NULL){
                        reader->mode = XML_TEXTREADER_MODE_ERROR;
                        reader->state = XML_TEXTREADER_ERROR;
                return(-1);
                }
            reader->state = XML_TEXTREADER_ELEMENT;
        } else {
            if (reader->ctxt->myDoc != NULL) {
                reader->node = reader->ctxt->myDoc->children;
            }
            if (reader->node == NULL)
                reader->node = reader->ctxt->nodeTab[0];
            reader->state = XML_TEXTREADER_ELEMENT;
        }
        reader->depth = 0;
        reader->ctxt->parseMode = XML_PARSE_READER;
        goto node_found;
    }
    oldstate = reader->state;
    olddepth = reader->ctxt->nodeNr;
    oldnode = reader->node;

get_next_node:
    if (reader->node == NULL) {
        if (reader->mode == XML_TEXTREADER_MODE_EOF)
            return(0);
        else
            return(-1);
    }

    /*
     * If we are not backtracking on ancestors or examined nodes,
     * that the parser didn't finished or that we arent at the end
     * of stream, continue processing.
     */
    while ((reader->node != NULL) && (reader->node->next == NULL) &&
           (reader->ctxt->nodeNr == olddepth) &&
           ((oldstate == XML_TEXTREADER_BACKTRACK) ||
            (reader->node->children == NULL) ||
            (reader->node->type == XML_ENTITY_REF_NODE) ||
            ((reader->node->children != NULL) &&
             (reader->node->children->type == XML_TEXT_NODE) &&
             (reader->node->children->next == NULL)) ||
            (reader->node->type == XML_DTD_NODE) ||
            (reader->node->type == XML_DOCUMENT_NODE) ||
            (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
           ((reader->ctxt->node == NULL) ||
            (reader->ctxt->node == reader->node) ||
            (reader->ctxt->node == reader->node->parent)) &&
           (reader->ctxt->instate != XML_PARSER_EOF)) {
        val = xmlTextReaderPushData(reader);
        if (val < 0){
                reader->mode = XML_TEXTREADER_MODE_ERROR;
                reader->state = XML_TEXTREADER_ERROR;
            return(-1);
        }
        if (reader->node == NULL)
            goto node_end;
    }
    if (oldstate != XML_TEXTREADER_BACKTRACK) {
        if ((reader->node->children != NULL) &&
            (reader->node->type != XML_ENTITY_REF_NODE) &&
            (reader->node->type != XML_XINCLUDE_START) &&
            (reader->node->type != XML_DTD_NODE)) {
            reader->node = reader->node->children;
            reader->depth++;
            reader->state = XML_TEXTREADER_ELEMENT;
            goto node_found;
        }
    }
    if (reader->node->next != NULL) {
        if ((oldstate == XML_TEXTREADER_ELEMENT) &&
            (reader->node->type == XML_ELEMENT_NODE) &&
            (reader->node->children == NULL) &&
            ((reader->node->extra & NODE_IS_EMPTY) == 0)
#ifdef LIBXML_XINCLUDE_ENABLED
            && (reader->in_xinclude <= 0)
#endif
            ) {
            reader->state = XML_TEXTREADER_END;
            goto node_found;
        }
#ifdef LIBXML_REGEXP_ENABLED
        if ((reader->validate) &&
            (reader->node->type == XML_ELEMENT_NODE))
            xmlTextReaderValidatePop(reader);
#endif /* LIBXML_REGEXP_ENABLED */
        if ((reader->preserves > 0) &&
            (reader->node->extra & NODE_IS_SPRESERVED))
            reader->preserves--;
        reader->node = reader->node->next;
        reader->state = XML_TEXTREADER_ELEMENT;

        /*
         * Cleanup of the old node
         */
        if ((reader->preserves == 0) &&
#ifdef LIBXML_XINCLUDE_ENABLED
            (reader->in_xinclude == 0) &&
#endif
            (reader->entNr == 0) &&
            (reader->node->prev != NULL) &&
            (reader->node->prev->type != XML_DTD_NODE)) {
            xmlNodePtr tmp = reader->node->prev;
            if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
                xmlUnlinkNode(tmp);
                xmlTextReaderFreeNode(reader, tmp);
            }
        }

        goto node_found;
    }
    if ((oldstate == XML_TEXTREADER_ELEMENT) &&
        (reader->node->type == XML_ELEMENT_NODE) &&
        (reader->node->children == NULL) &&
        ((reader->node->extra & NODE_IS_EMPTY) == 0)) {;
        reader->state = XML_TEXTREADER_END;
        goto node_found;
    }
#ifdef LIBXML_REGEXP_ENABLED
    if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
        xmlTextReaderValidatePop(reader);
#endif /* LIBXML_REGEXP_ENABLED */
    if ((reader->preserves > 0) &&
        (reader->node->extra & NODE_IS_SPRESERVED))
        reader->preserves--;
    reader->node = reader->node->parent;
    if ((reader->node == NULL) ||
        (reader->node->type == XML_DOCUMENT_NODE) ||
#ifdef LIBXML_DOCB_ENABLED
        (reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
#endif
        (reader->node->type == XML_HTML_DOCUMENT_NODE)) {
        if (reader->mode != XML_TEXTREADER_MODE_EOF) {
            val = xmlParseChunk(reader->ctxt, "", 0, 1);
            reader->state = XML_TEXTREADER_DONE;
            if (val != 0)
                return(-1);
        }
        reader->node = NULL;
        reader->depth = -1;

        /*
         * Cleanup of the old node
         */
        if ((oldnode != NULL) && (reader->preserves == 0) &&
#ifdef LIBXML_XINCLUDE_ENABLED
            (reader->in_xinclude == 0) &&
#endif
            (reader->entNr == 0) &&
            (oldnode->type != XML_DTD_NODE) &&
            ((oldnode->extra & NODE_IS_PRESERVED) == 0)) {
            xmlUnlinkNode(oldnode);
            xmlTextReaderFreeNode(reader, oldnode);
        }

        goto node_end;
    }
    if ((reader->preserves == 0) &&
#ifdef LIBXML_XINCLUDE_ENABLED
        (reader->in_xinclude == 0) &&
#endif
        (reader->entNr == 0) &&
        (reader->node->last != NULL) &&
        ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) {
        xmlNodePtr tmp = reader->node->last;
        xmlUnlinkNode(tmp);
        xmlTextReaderFreeNode(reader, tmp);
    }
    reader->depth--;
    reader->state = XML_TEXTREADER_BACKTRACK;

node_found:
    DUMP_READER

    /*
     * If we are in the middle of a piece of CDATA make sure it's finished
     */
    if ((reader->node != NULL) &&
        (reader->node->next == NULL) &&
        ((reader->node->type == XML_TEXT_NODE) ||
         (reader->node->type == XML_CDATA_SECTION_NODE))) {
            if (xmlTextReaderExpand(reader) == NULL)
                return -1;
    }

#ifdef LIBXML_XINCLUDE_ENABLED
    /*
     * Handle XInclude if asked for
     */
    if ((reader->xinclude) && (reader->node != NULL) &&
        (reader->node->type == XML_ELEMENT_NODE) &&
        (reader->node->ns != NULL) &&
        ((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
         (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
        if (reader->xincctxt == NULL) {
            reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
            xmlXIncludeSetFlags(reader->xincctxt,
                                reader->parserFlags & (~XML_PARSE_NOXINCNODE));
        }
        /*
         * expand that node and process it
         */
        if (xmlTextReaderExpand(reader) == NULL)
            return -1;
        xmlXIncludeProcessNode(reader->xincctxt, reader->node);
    }
    if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
        reader->in_xinclude++;
        goto get_next_node;
    }
    if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) {
        reader->in_xinclude--;
        goto get_next_node;
    }
#endif
    /*
     * Handle entities enter and exit when in entity replacement mode
     */
    if ((reader->node != NULL) &&
        (reader->node->type == XML_ENTITY_REF_NODE) &&
        (reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
        /*
         * Case where the underlying tree is not availble, lookup the entity
         * and walk it.
         */
        if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
            (reader->ctxt->sax->getEntity != NULL)) {
            reader->node->children = (xmlNodePtr)
                reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
        }

        if ((reader->node->children != NULL) &&
            (reader->node->children->type == XML_ENTITY_DECL) &&
            (reader->node->children->children != NULL)) {
            xmlTextReaderEntPush(reader, reader->node);
            reader->node = reader->node->children->children;
        }
#ifdef LIBXML_REGEXP_ENABLED
    } else if ((reader->node != NULL) &&
               (reader->node->type == XML_ENTITY_REF_NODE) &&
               (reader->ctxt != NULL) && (reader->validate)) {
        xmlTextReaderValidateEntity(reader);
#endif /* LIBXML_REGEXP_ENABLED */
    }
    if ((reader->node != NULL) &&
        (reader->node->type == XML_ENTITY_DECL) &&
        (reader->ent != NULL) && (reader->ent->children == reader->node)) {
        reader->node = xmlTextReaderEntPop(reader);
        reader->depth++;
        goto get_next_node;
    }
#ifdef LIBXML_REGEXP_ENABLED
    if ((reader->validate) && (reader->node != NULL)) {
        xmlNodePtr node = reader->node;

        if ((node->type == XML_ELEMENT_NODE) &&
            ((reader->state != XML_TEXTREADER_END) &&
             (reader->state != XML_TEXTREADER_BACKTRACK))) {
            xmlTextReaderValidatePush(reader);
        } else if ((node->type == XML_TEXT_NODE) ||
                   (node->type == XML_CDATA_SECTION_NODE)) {
            xmlTextReaderValidateCData(reader, node->content,
                                       xmlStrlen(node->content));
        }
    }
#endif /* LIBXML_REGEXP_ENABLED */
#ifdef LIBXML_PATTERN_ENABLED
    if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
        (reader->state != XML_TEXTREADER_BACKTRACK)) {
        int i;
        for (i = 0;i < reader->patternNr;i++) {
             if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
                 xmlTextReaderPreserve(reader);
                 break;
             }
        }
    }
#endif /* LIBXML_PATTERN_ENABLED */
#ifdef LIBXML_SCHEMAS_ENABLED
    if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) &&
        (reader->xsdValidErrors == 0) &&
        (reader->xsdValidCtxt != NULL)) {
        reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt);
    }
#endif /* LIBXML_PATTERN_ENABLED */
    return(1);
node_end:
    reader->state = XML_TEXTREADER_DONE;
    return(0);
}

/**
 * xmlTextReaderReadState:
 * @reader:  the xmlTextReaderPtr used
 *
 * Gets the read state of the reader.
 *
 * Returns the state value, or -1 in case of error
 */
int
xmlTextReaderReadState(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    return(reader->mode);
}

/**
 * xmlTextReaderExpand:
 * @reader:  the xmlTextReaderPtr used
 *
 * Reads the contents of the current node and the full subtree. It then makes
 * the subtree available until the next xmlTextReaderRead() call
 *
 * Returns a node pointer valid until the next xmlTextReaderRead() call
 *         or NULL in case of error.
 */
xmlNodePtr
xmlTextReaderExpand(xmlTextReaderPtr reader) {
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->doc != NULL)
        return(reader->node);
    if (reader->ctxt == NULL)
        return(NULL);
    if (xmlTextReaderDoExpand(reader) < 0)
        return(NULL);
    return(reader->node);
}

/**
 * xmlTextReaderNext:
 * @reader:  the xmlTextReaderPtr used
 *
 * Skip to the node following the current one in document order while
 * avoiding the subtree if any.
 *
 * Returns 1 if the node was read successfully, 0 if there is no more
 *          nodes to read, or -1 in case of error
 */
int
xmlTextReaderNext(xmlTextReaderPtr reader) {
    int ret;
    xmlNodePtr cur;

    if (reader == NULL)
        return(-1);
    if (reader->doc != NULL)
        return(xmlTextReaderNextTree(reader));
    cur = reader->node;
    if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
        return(xmlTextReaderRead(reader));
    if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK)
        return(xmlTextReaderRead(reader));
    if (cur->extra & NODE_IS_EMPTY)
        return(xmlTextReaderRead(reader));
    do {
        ret = xmlTextReaderRead(reader);
        if (ret != 1)
            return(ret);
    } while (reader->node != cur);
    return(xmlTextReaderRead(reader));
}

#ifdef LIBXML_WRITER_ENABLED
/**
 * xmlTextReaderReadInnerXml:
 * @reader:  the xmlTextReaderPtr used
 *
 * Reads the contents of the current node, including child nodes and markup.
 *
 * Returns a string containing the XML content, or NULL if the current node
 *         is neither an element nor attribute, or has no child nodes. The
 *         string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
{
    xmlChar *resbuf;
    xmlNodePtr node, cur_node;
    xmlBufferPtr buff, buff2;
    xmlDocPtr doc;

    if (xmlTextReaderExpand(reader) == NULL) {
        return NULL;
    }
    doc = reader->doc;
    buff = xmlBufferCreate();
    for (cur_node = reader->node->children; cur_node != NULL;
         cur_node = cur_node->next) {
        node = xmlDocCopyNode(cur_node, doc, 1);
        buff2 = xmlBufferCreate();
        if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) {
            xmlFreeNode(node);
            xmlBufferFree(buff2);
            xmlBufferFree(buff);
            return NULL;
        }
        xmlBufferCat(buff, buff2->content);
        xmlFreeNode(node);
        xmlBufferFree(buff2);
    }
    resbuf = buff->content;
    buff->content = NULL;

    xmlBufferFree(buff);
    return resbuf;
}
#endif

#ifdef LIBXML_WRITER_ENABLED
/**
 * xmlTextReaderReadOuterXml:
 * @reader:  the xmlTextReaderPtr used
 *
 * Reads the contents of the current node, including child nodes and markup.
 *
 * Returns a string containing the XML content, or NULL if the current node
 *         is neither an element nor attribute, or has no child nodes. The
 *         string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
{
    xmlChar *resbuf;
    xmlNodePtr node;
    xmlBufferPtr buff;
    xmlDocPtr doc;

    node = reader->node;
    doc = reader->doc;
    if (xmlTextReaderExpand(reader) == NULL) {
        return NULL;
    }
    node = xmlDocCopyNode(node, doc, 1);
    buff = xmlBufferCreate();
    if (xmlNodeDump(buff, doc, node, 0, 0) == -1) {
        xmlFreeNode(node);
        xmlBufferFree(buff);
        return NULL;
    }

    resbuf = buff->content;
    buff->content = NULL;

    xmlFreeNode(node);
    xmlBufferFree(buff);
    return resbuf;
}
#endif

/**
 * xmlTextReaderReadString:
 * @reader:  the xmlTextReaderPtr used
 *
 * Reads the contents of an element or a text node as a string.
 *
 * Returns a string containing the contents of the Element or Text node,
 *         or NULL if the reader is positioned on any other type of node.
 *         The string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderReadString(xmlTextReaderPtr reader)
{
    xmlNodePtr node;

    if ((reader == NULL) || (reader->node == NULL))
       return(NULL);

    node = (reader->curnode != NULL) ? reader->curnode : reader->node;
    switch (node->type) {
    case XML_TEXT_NODE:
       if (node->content != NULL)
           return(xmlStrdup(node->content));
       break;
    case XML_ELEMENT_NODE:
        if (xmlTextReaderDoExpand(reader) != -1) {
            return xmlTextReaderCollectSiblings(node->children);
        }
    case XML_ATTRIBUTE_NODE:
        TODO
        break;
    default:
       break;
    }
    return(NULL);
}

#if 0
/**
 * xmlTextReaderReadBase64:
 * @reader:  the xmlTextReaderPtr used
 * @array:  a byte array to store the content.
 * @offset:  the zero-based index into array where the method should
 *           begin to write.
 * @len:  the number of bytes to write.
 *
 * Reads and decodes the Base64 encoded contents of an element and
 * stores the result in a byte buffer.
 *
 * Returns the number of bytes written to array, or zero if the current
 *         instance is not positioned on an element or -1 in case of error.
 */
int
xmlTextReaderReadBase64(xmlTextReaderPtr reader,
                        unsigned char *array ATTRIBUTE_UNUSED,
                        int offset ATTRIBUTE_UNUSED,
                        int len ATTRIBUTE_UNUSED) {
    if ((reader == NULL) || (reader->ctxt == NULL))
        return(-1);
    if (reader->ctxt->wellFormed != 1)
        return(-1);

    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
        return(0);
    TODO
    return(0);
}

/**
 * xmlTextReaderReadBinHex:
 * @reader:  the xmlTextReaderPtr used
 * @array:  a byte array to store the content.
 * @offset:  the zero-based index into array where the method should
 *           begin to write.
 * @len:  the number of bytes to write.
 *
 * Reads and decodes the BinHex encoded contents of an element and
 * stores the result in a byte buffer.
 *
 * Returns the number of bytes written to array, or zero if the current
 *         instance is not positioned on an element or -1 in case of error.
 */
int
xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
                        unsigned char *array ATTRIBUTE_UNUSED,
                        int offset ATTRIBUTE_UNUSED,
                        int len ATTRIBUTE_UNUSED) {
    if ((reader == NULL) || (reader->ctxt == NULL))
        return(-1);
    if (reader->ctxt->wellFormed != 1)
        return(-1);

    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
        return(0);
    TODO
    return(0);
}
#endif

/************************************************************************
 *                                                                      *
 *                      Operating on a preparsed tree                   *
 *                                                                      *
 ************************************************************************/
static int
xmlTextReaderNextTree(xmlTextReaderPtr reader)
{
    if (reader == NULL)
        return(-1);

    if (reader->state == XML_TEXTREADER_END)
        return(0);

    if (reader->node == NULL) {
        if (reader->doc->children == NULL) {
            reader->state = XML_TEXTREADER_END;
            return(0);
        }

        reader->node = reader->doc->children;
        reader->state = XML_TEXTREADER_START;
        return(1);
    }

    if (reader->state != XML_TEXTREADER_BACKTRACK) {
        /* Here removed traversal to child, because we want to skip the subtree,
        replace with traversal to sibling to skip subtree */
        if (reader->node->next != 0) {
            /* Move to sibling if present,skipping sub-tree */
            reader->node = reader->node->next;
            reader->state = XML_TEXTREADER_START;
            return(1);
        }

        /* if reader->node->next is NULL mean no subtree for current node,
        so need to move to sibling of parent node if present */
        if ((reader->node->type == XML_ELEMENT_NODE) ||
            (reader->node->type == XML_ATTRIBUTE_NODE)) {
            reader->state = XML_TEXTREADER_BACKTRACK;
            /* This will move to parent if present */
            xmlTextReaderRead(reader);
        }
    }

    if (reader->node->next != 0) {
        reader->node = reader->node->next;
        reader->state = XML_TEXTREADER_START;
        return(1);
    }

    if (reader->node->parent != 0) {
        if (reader->node->parent->type == XML_DOCUMENT_NODE) {
            reader->state = XML_TEXTREADER_END;
            return(0);
        }

        reader->node = reader->node->parent;
        reader->depth--;
        reader->state = XML_TEXTREADER_BACKTRACK;
        /* Repeat process to move to sibling of parent node if present */
        xmlTextReaderNextTree(reader);
    }

    reader->state = XML_TEXTREADER_END;

    return(1);
}

/**
 * xmlTextReaderReadTree:
 * @reader:  the xmlTextReaderPtr used
 *
 *  Moves the position of the current instance to the next node in
 *  the stream, exposing its properties.
 *
 *  Returns 1 if the node was read successfully, 0 if there is no more
 *          nodes to read, or -1 in case of error
 */
static int
xmlTextReaderReadTree(xmlTextReaderPtr reader) {
    if (reader->state == XML_TEXTREADER_END)
        return(0);

next_node:
    if (reader->node == NULL) {
        if (reader->doc->children == NULL) {
            reader->state = XML_TEXTREADER_END;
            return(0);
        }

        reader->node = reader->doc->children;
        reader->state = XML_TEXTREADER_START;
        goto found_node;
    }

    if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
        (reader->node->type != XML_DTD_NODE) &&
        (reader->node->type != XML_XINCLUDE_START) &&
        (reader->node->type != XML_ENTITY_REF_NODE)) {
        if (reader->node->children != NULL) {
            reader->node = reader->node->children;
            reader->depth++;
            reader->state = XML_TEXTREADER_START;
            goto found_node;
        }

        if (reader->node->type == XML_ATTRIBUTE_NODE) {
            reader->state = XML_TEXTREADER_BACKTRACK;
            goto found_node;
        }
    }

    if (reader->node->next != NULL) {
        reader->node = reader->node->next;
        reader->state = XML_TEXTREADER_START;
        goto found_node;
    }

    if (reader->node->parent != NULL) {
        if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
            (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
            reader->state = XML_TEXTREADER_END;
            return(0);
        }

        reader->node = reader->node->parent;
        reader->depth--;
        reader->state = XML_TEXTREADER_BACKTRACK;
        goto found_node;
    }

    reader->state = XML_TEXTREADER_END;

found_node:
    if ((reader->node->type == XML_XINCLUDE_START) ||
        (reader->node->type == XML_XINCLUDE_END))
        goto next_node;

    return(1);
}

/**
 * xmlTextReaderNextSibling:
 * @reader:  the xmlTextReaderPtr used
 *
 * Skip to the node following the current one in document order while
 * avoiding the subtree if any.
 * Currently implemented only for Readers built on a document
 *
 * Returns 1 if the node was read successfully, 0 if there is no more
 *          nodes to read, or -1 in case of error
 */
int
xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    if (reader->doc == NULL) {
        /* TODO */
        return(-1);
    }

    if (reader->state == XML_TEXTREADER_END)
        return(0);

    if (reader->node == NULL)
        return(xmlTextReaderNextTree(reader));

    if (reader->node->next != NULL) {
        reader->node = reader->node->next;
        reader->state = XML_TEXTREADER_START;
        return(1);
    }

    return(0);
}

/************************************************************************
 *                                                                      *
 *                      Constructor and destructors                     *
 *                                                                      *
 ************************************************************************/
/**
 * xmlNewTextReader:
 * @input: the xmlParserInputBufferPtr used to read data
 * @URI: the URI information for the source if available
 *
 * Create an xmlTextReader structure fed with @input
 *
 * Returns the new xmlTextReaderPtr or NULL in case of error
 */
xmlTextReaderPtr
xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
    xmlTextReaderPtr ret;

    if (input == NULL)
        return(NULL);
    ret = xmlMalloc(sizeof(xmlTextReader));
    if (ret == NULL) {
        xmlGenericError(xmlGenericErrorContext,
                "xmlNewTextReader : malloc failed\n");
        return(NULL);
    }
    memset(ret, 0, sizeof(xmlTextReader));
    ret->doc = NULL;
    ret->entTab = NULL;
    ret->entMax = 0;
    ret->entNr = 0;
    ret->input = input;
    ret->buffer = xmlBufferCreateSize(100);
    if (ret->buffer == NULL) {
        xmlFree(ret);
        xmlGenericError(xmlGenericErrorContext,
                "xmlNewTextReader : malloc failed\n");
        return(NULL);
    }
    ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
    if (ret->sax == NULL) {
        xmlBufferFree(ret->buffer);
        xmlFree(ret);
        xmlGenericError(xmlGenericErrorContext,
                "xmlNewTextReader : malloc failed\n");
        return(NULL);
    }
    xmlSAXVersion(ret->sax, 2);
    ret->startElement = ret->sax->startElement;
    ret->sax->startElement = xmlTextReaderStartElement;
    ret->endElement = ret->sax->endElement;
    ret->sax->endElement = xmlTextReaderEndElement;
#ifdef LIBXML_SAX1_ENABLED
    if (ret->sax->initialized == XML_SAX2_MAGIC) {
#endif /* LIBXML_SAX1_ENABLED */
        ret->startElementNs = ret->sax->startElementNs;
        ret->sax->startElementNs = xmlTextReaderStartElementNs;
        ret->endElementNs = ret->sax->endElementNs;
        ret->sax->endElementNs = xmlTextReaderEndElementNs;
#ifdef LIBXML_SAX1_ENABLED
    } else {
        ret->startElementNs = NULL;
        ret->endElementNs = NULL;
    }
#endif /* LIBXML_SAX1_ENABLED */
    ret->characters = ret->sax->characters;
    ret->sax->characters = xmlTextReaderCharacters;
    ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
    ret->cdataBlock = ret->sax->cdataBlock;
    ret->sax->cdataBlock = xmlTextReaderCDataBlock;

    ret->mode = XML_TEXTREADER_MODE_INITIAL;
    ret->node = NULL;
    ret->curnode = NULL;
    if (ret->input->buffer->use < 4) {
        xmlParserInputBufferRead(input, 4);
    }
    if (ret->input->buffer->use >= 4) {
        ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
                        (const char *) ret->input->buffer->content, 4, URI);
        ret->base = 0;
        ret->cur = 4;
    } else {
        ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
        ret->base = 0;
        ret->cur = 0;
    }

    if (ret->ctxt == NULL) {
        xmlGenericError(xmlGenericErrorContext,
                "xmlNewTextReader : malloc failed\n");
        xmlBufferFree(ret->buffer);
        xmlFree(ret->sax);
        xmlFree(ret);
        return(NULL);
    }
    ret->ctxt->parseMode = XML_PARSE_READER;
    ret->ctxt->_private = ret;
    ret->ctxt->linenumbers = 1;
    ret->ctxt->dictNames = 1;
    ret->allocs = XML_TEXTREADER_CTXT;
    /*
     * use the parser dictionnary to allocate all elements and attributes names
     */
    ret->ctxt->docdict = 1;
    ret->dict = ret->ctxt->dict;
#ifdef LIBXML_XINCLUDE_ENABLED
    ret->xinclude = 0;
#endif
#ifdef LIBXML_PATTERN_ENABLED
    ret->patternMax = 0;
    ret->patternTab = NULL;
#endif
    return(ret);
}

/**
 * xmlNewTextReaderFilename:
 * @URI: the URI of the resource to process
 *
 * Create an xmlTextReader structure fed with the resource at @URI
 *
 * Returns the new xmlTextReaderPtr or NULL in case of error
 */
xmlTextReaderPtr
xmlNewTextReaderFilename(const char *URI) {
    xmlParserInputBufferPtr input;
    xmlTextReaderPtr ret;
    char *directory = NULL;

    input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
    if (input == NULL)
        return(NULL);
    ret = xmlNewTextReader(input, URI);
    if (ret == NULL) {
        xmlFreeParserInputBuffer(input);
        return(NULL);
    }
    ret->allocs |= XML_TEXTREADER_INPUT;
    if (ret->ctxt->directory == NULL)
        directory = xmlParserGetDirectory(URI);
    if ((ret->ctxt->directory == NULL) && (directory != NULL))
        ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
    if (directory != NULL)
        xmlFree(directory);
    return(ret);
}

/**
 * xmlFreeTextReader:
 * @reader:  the xmlTextReaderPtr
 *
 * Deallocate all the resources associated to the reader
 */
void
xmlFreeTextReader(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return;
#ifdef LIBXML_SCHEMAS_ENABLED
    if (reader->rngSchemas != NULL) {
        xmlRelaxNGFree(reader->rngSchemas);
        reader->rngSchemas = NULL;
    }
    if (reader->rngValidCtxt != NULL) {
        xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
        reader->rngValidCtxt = NULL;
    }
    if (reader->xsdPlug != NULL) {
        xmlSchemaSAXUnplug(reader->xsdPlug);
        reader->xsdPlug = NULL;
    }
    if (reader->xsdValidCtxt != NULL) {
        if (! reader->xsdPreserveCtxt)
            xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
        reader->xsdValidCtxt = NULL;
    }
    if (reader->xsdSchemas != NULL) {
        xmlSchemaFree(reader->xsdSchemas);
        reader->xsdSchemas = NULL;
    }
#endif
#ifdef LIBXML_XINCLUDE_ENABLED
    if (reader->xincctxt != NULL)
        xmlXIncludeFreeContext(reader->xincctxt);
#endif
#ifdef LIBXML_PATTERN_ENABLED
    if (reader->patternTab != NULL) {
        int i;
        for (i = 0;i < reader->patternNr;i++) {
            if (reader->patternTab[i] != NULL)
                xmlFreePattern(reader->patternTab[i]);
        }
        xmlFree(reader->patternTab);
    }
#endif
    if (reader->faketext != NULL) {
        xmlFreeNode(reader->faketext);
    }
    if (reader->ctxt != NULL) {
        if (reader->dict == reader->ctxt->dict)
            reader->dict = NULL;
        if (reader->ctxt->myDoc != NULL) {
            if (reader->preserve == 0)
                xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
            reader->ctxt->myDoc = NULL;
        }
        if ((reader->ctxt->vctxt.vstateTab != NULL) &&
            (reader->ctxt->vctxt.vstateMax > 0)){
            xmlFree(reader->ctxt->vctxt.vstateTab);
            reader->ctxt->vctxt.vstateTab = NULL;
            reader->ctxt->vctxt.vstateMax = 0;
        }
        if (reader->allocs & XML_TEXTREADER_CTXT)
            xmlFreeParserCtxt(reader->ctxt);
    }
    if (reader->sax != NULL)
        xmlFree(reader->sax);
    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
        xmlFreeParserInputBuffer(reader->input);
    if (reader->buffer != NULL)
        xmlBufferFree(reader->buffer);
    if (reader->entTab != NULL)
        xmlFree(reader->entTab);
    if (reader->dict != NULL)
        xmlDictFree(reader->dict);
    xmlFree(reader);
}

/************************************************************************
 *                                                                      *
 *                      Methods for XmlTextReader                       *
 *                                                                      *
 ************************************************************************/
/**
 * xmlTextReaderClose:
 * @reader:  the xmlTextReaderPtr used
 *
 * This method releases any resources allocated by the current instance
 * changes the state to Closed and close any underlying input.
 *
 * Returns 0 or -1 in case of error
 */
int
xmlTextReaderClose(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    reader->node = NULL;
    reader->curnode = NULL;
    reader->mode = XML_TEXTREADER_MODE_CLOSED;
    if (reader->ctxt != NULL) {
        xmlStopParser(reader->ctxt);
        if (reader->ctxt->myDoc != NULL) {
            if (reader->preserve == 0)
                xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
            reader->ctxt->myDoc = NULL;
        }
    }
    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
        xmlFreeParserInputBuffer(reader->input);
        reader->allocs -= XML_TEXTREADER_INPUT;
    }
    return(0);
}

/**
 * xmlTextReaderGetAttributeNo:
 * @reader:  the xmlTextReaderPtr used
 * @no: the zero-based index of the attribute relative to the containing element
 *
 * Provides the value of the attribute with the specified index relative
 * to the containing element.
 *
 * Returns a string containing the value of the specified attribute, or NULL
 *    in case of error. The string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
    xmlChar *ret;
    int i;
    xmlAttrPtr cur;
    xmlNsPtr ns;

    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    if (reader->curnode != NULL)
        return(NULL);
    /* TODO: handle the xmlDecl */
    if (reader->node->type != XML_ELEMENT_NODE)
        return(NULL);

    ns = reader->node->nsDef;
    for (i = 0;(i < no) && (ns != NULL);i++) {
        ns = ns->next;
    }
    if (ns != NULL)
        return(xmlStrdup(ns->href));

    cur = reader->node->properties;
    if (cur == NULL)
        return(NULL);
    for (;i < no;i++) {
        cur = cur->next;
        if (cur == NULL)
            return(NULL);
    }
    /* TODO walk the DTD if present */

    ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
    return(ret);
}

/**
 * xmlTextReaderGetAttribute:
 * @reader:  the xmlTextReaderPtr used
 * @name: the qualified name of the attribute.
 *
 * Provides the value of the attribute with the specified qualified name.
 *
 * Returns a string containing the value of the specified attribute, or NULL
 *    in case of error. The string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
    xmlChar *prefix = NULL;
    xmlChar *localname;
    xmlNsPtr ns;
    xmlChar *ret = NULL;

    if ((reader == NULL) || (name == NULL))
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    if (reader->curnode != NULL)
        return(NULL);

    /* TODO: handle the xmlDecl */
    if (reader->node->type != XML_ELEMENT_NODE)
        return(NULL);

    localname = xmlSplitQName2(name, &prefix);
    if (localname == NULL) {
                /*
                 * Namespace default decl
                 */
                if (xmlStrEqual(name, BAD_CAST "xmlns")) {
                        ns = reader->node->nsDef;
                        while (ns != NULL) {
                                if (ns->prefix == NULL) {
                                        return(xmlStrdup(ns->href));
                                }
                                ns = ns->next;
                        }
                        return NULL;
                }
                return(xmlGetNoNsProp(reader->node, name));
        }

    /*
     * Namespace default decl
     */
    if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
                ns = reader->node->nsDef;
                while (ns != NULL) {
                        if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
                                ret = xmlStrdup(ns->href);
                                break;
                        }
                        ns = ns->next;
                }
    } else {
                ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
                if (ns != NULL)
                        ret = xmlGetNsProp(reader->node, localname, ns->href);
        }

    xmlFree(localname);
    if (prefix != NULL)
        xmlFree(prefix);
    return(ret);
}


/**
 * xmlTextReaderGetAttributeNs:
 * @reader:  the xmlTextReaderPtr used
 * @localName: the local name of the attribute.
 * @namespaceURI: the namespace URI of the attribute.
 *
 * Provides the value of the specified attribute
 *
 * Returns a string containing the value of the specified attribute, or NULL
 *    in case of error. The string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
                            const xmlChar *namespaceURI) {
    xmlChar *prefix = NULL;
    xmlNsPtr ns;

    if ((reader == NULL) || (localName == NULL))
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    if (reader->curnode != NULL)
        return(NULL);

    /* TODO: handle the xmlDecl */
    if (reader->node->type != XML_ELEMENT_NODE)
        return(NULL);

    if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
                if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
                        prefix = BAD_CAST localName;
                }
                ns = reader->node->nsDef;
                while (ns != NULL) {
                        if ((prefix == NULL && ns->prefix == NULL) ||
                                ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
                                return xmlStrdup(ns->href);
                        }
                        ns = ns->next;
                }
                return NULL;
    }

    return(xmlGetNsProp(reader->node, localName, namespaceURI));
}

/**
 * xmlTextReaderGetRemainder:
 * @reader:  the xmlTextReaderPtr used
 *
 * Method to get the remainder of the buffered XML. this method stops the
 * parser, set its state to End Of File and return the input stream with
 * what is left that the parser did not use.
 *
 * The implementation is not good, the parser certainly procgressed past
 * what's left in reader->input, and there is an allocation problem. Best
 * would be to rewrite it differently.
 *
 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
 *    in case of error.
 */
xmlParserInputBufferPtr
xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
    xmlParserInputBufferPtr ret = NULL;

    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);

    reader->node = NULL;
    reader->curnode = NULL;
    reader->mode = XML_TEXTREADER_MODE_EOF;
    if (reader->ctxt != NULL) {
        xmlStopParser(reader->ctxt);
        if (reader->ctxt->myDoc != NULL) {
            if (reader->preserve == 0)
                xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
            reader->ctxt->myDoc = NULL;
        }
    }
    if (reader->allocs & XML_TEXTREADER_INPUT) {
        ret = reader->input;
        reader->input = NULL;
        reader->allocs -= XML_TEXTREADER_INPUT;
    } else {
        /*
         * Hum, one may need to duplicate the data structure because
         * without reference counting the input may be freed twice:
         *   - by the layer which allocated it.
         *   - by the layer to which would have been returned to.
         */
        TODO
        return(NULL);
    }
    return(ret);
}

/**
 * xmlTextReaderLookupNamespace:
 * @reader:  the xmlTextReaderPtr used
 * @prefix: the prefix whose namespace URI is to be resolved. To return
 *          the default namespace, specify NULL
 *
 * Resolves a namespace prefix in the scope of the current element.
 *
 * Returns a string containing the namespace URI to which the prefix maps
 *    or NULL in case of error. The string must be deallocated by the caller.
 */
xmlChar *
xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
    xmlNsPtr ns;

    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);

    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
    if (ns == NULL)
        return(NULL);
    return(xmlStrdup(ns->href));
}

/**
 * xmlTextReaderMoveToAttributeNo:
 * @reader:  the xmlTextReaderPtr used
 * @no: the zero-based index of the attribute relative to the containing
 *      element.
 *
 * Moves the position of the current instance to the attribute with
 * the specified index relative to the containing element.
 *
 * Returns 1 in case of success, -1 in case of error, 0 if not found
 */
int
xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
    int i;
    xmlAttrPtr cur;
    xmlNsPtr ns;

    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(-1);
    /* TODO: handle the xmlDecl */
    if (reader->node->type != XML_ELEMENT_NODE)
        return(-1);

    reader->curnode = NULL;

    ns = reader->node->nsDef;
    for (i = 0;(i < no) && (ns != NULL);i++) {
        ns = ns->next;
    }
    if (ns != NULL) {
        reader->curnode = (xmlNodePtr) ns;
        return(1);
    }

    cur = reader->node->properties;
    if (cur == NULL)
        return(0);
    for (;i < no;i++) {
        cur = cur->next;
        if (cur == NULL)
            return(0);
    }
    /* TODO walk the DTD if present */

    reader->curnode = (xmlNodePtr) cur;
    return(1);
}

/**
 * xmlTextReaderMoveToAttribute:
 * @reader:  the xmlTextReaderPtr used
 * @name: the qualified name of the attribute.
 *
 * Moves the position of the current instance to the attribute with
 * the specified qualified name.
 *
 * Returns 1 in case of success, -1 in case of error, 0 if not found
 */
int
xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
    xmlChar *prefix = NULL;
    xmlChar *localname;
    xmlNsPtr ns;
    xmlAttrPtr prop;

    if ((reader == NULL) || (name == NULL))
        return(-1);
    if (reader->node == NULL)
        return(-1);

    /* TODO: handle the xmlDecl */
    if (reader->node->type != XML_ELEMENT_NODE)
        return(0);

    localname = xmlSplitQName2(name, &prefix);
    if (localname == NULL) {
        /*
         * Namespace default decl
         */
        if (xmlStrEqual(name, BAD_CAST "xmlns")) {
            ns = reader->node->nsDef;
            while (ns != NULL) {
                if (ns->prefix == NULL) {
                    reader->curnode = (xmlNodePtr) ns;
                    return(1);
                }
                ns = ns->next;
            }
            return(0);
        }

        prop = reader->node->properties;
        while (prop != NULL) {
            /*
             * One need to have
             *   - same attribute names
             *   - and the attribute carrying that namespace
             */
            if ((xmlStrEqual(prop->name, name)) &&
                ((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
                reader->curnode = (xmlNodePtr) prop;
                return(1);
            }
            prop = prop->next;
        }
        return(0);
    }

    /*
     * Namespace default decl
     */
    if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
        ns = reader->node->nsDef;
        while (ns != NULL) {
            if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
                reader->curnode = (xmlNodePtr) ns;
                goto found;
            }
            ns = ns->next;
        }
        goto not_found;
    }
    prop = reader->node->properties;
    while (prop != NULL) {
        /*
         * One need to have
         *   - same attribute names
         *   - and the attribute carrying that namespace
         */
        if ((xmlStrEqual(prop->name, localname)) &&
            (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
            reader->curnode = (xmlNodePtr) prop;
            goto found;
        }
        prop = prop->next;
    }
not_found:
    if (localname != NULL)
        xmlFree(localname);
    if (prefix != NULL)
        xmlFree(prefix);
    return(0);

found:
    if (localname != NULL)
        xmlFree(localname);
    if (prefix != NULL)
        xmlFree(prefix);
    return(1);
}

/**
 * xmlTextReaderMoveToAttributeNs:
 * @reader:  the xmlTextReaderPtr used
 * @localName:  the local name of the attribute.
 * @namespaceURI:  the namespace URI of the attribute.
 *
 * Moves the position of the current instance to the attribute with the
 * specified local name and namespace URI.
 *
 * Returns 1 in case of success, -1 in case of error, 0 if not found
 */
int
xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
        const xmlChar *localName, const xmlChar *namespaceURI) {
    xmlAttrPtr prop;
    xmlNodePtr node;
    xmlNsPtr ns;
    xmlChar *prefix = NULL;

    if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
        return(-1);
    if (reader->node == NULL)
        return(-1);
    if (reader->node->type != XML_ELEMENT_NODE)
        return(0);
    node = reader->node;

    if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
                if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
                        prefix = BAD_CAST localName;
                }
                ns = reader->node->nsDef;
                while (ns != NULL) {
                        if ((prefix == NULL && ns->prefix == NULL) ||
                                ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
                                reader->curnode = (xmlNodePtr) ns;
                                return(1);
                        }
                        ns = ns->next;
                }
                return(0);
    }

    prop = node->properties;
    while (prop != NULL) {
        /*
         * One need to have
         *   - same attribute names
         *   - and the attribute carrying that namespace
         */
        if (xmlStrEqual(prop->name, localName) &&
            ((prop->ns != NULL) &&
             (xmlStrEqual(prop->ns->href, namespaceURI)))) {
            reader->curnode = (xmlNodePtr) prop;
            return(1);
        }
        prop = prop->next;
    }
    return(0);
}

/**
 * xmlTextReaderMoveToFirstAttribute:
 * @reader:  the xmlTextReaderPtr used
 *
 * Moves the position of the current instance to the first attribute
 * associated with the current node.
 *
 * Returns 1 in case of success, -1 in case of error, 0 if not found
 */
int
xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(-1);
    if (reader->node->type != XML_ELEMENT_NODE)
        return(0);

    if (reader->node->nsDef != NULL) {
        reader->curnode = (xmlNodePtr) reader->node->nsDef;
        return(1);
    }
    if (reader->node->properties != NULL) {
        reader->curnode = (xmlNodePtr) reader->node->properties;
        return(1);
    }
    return(0);
}

/**
 * xmlTextReaderMoveToNextAttribute:
 * @reader:  the xmlTextReaderPtr used
 *
 * Moves the position of the current instance to the next attribute
 * associated with the current node.
 *
 * Returns 1 in case of success, -1 in case of error, 0 if not found
 */
int
xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(-1);
    if (reader->node->type != XML_ELEMENT_NODE)
        return(0);
    if (reader->curnode == NULL)
        return(xmlTextReaderMoveToFirstAttribute(reader));

    if (reader->curnode->type == XML_NAMESPACE_DECL) {
        xmlNsPtr ns = (xmlNsPtr) reader->curnode;
        if (ns->next != NULL) {
            reader->curnode = (xmlNodePtr) ns->next;
            return(1);
        }
        if (reader->node->properties != NULL) {
            reader->curnode = (xmlNodePtr) reader->node->properties;
            return(1);
        }
        return(0);
    } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
               (reader->curnode->next != NULL)) {
        reader->curnode = reader->curnode->next;
        return(1);
    }
    return(0);
}

/**
 * xmlTextReaderMoveToElement:
 * @reader:  the xmlTextReaderPtr used
 *
 * Moves the position of the current instance to the node that
 * contains the current Attribute  node.
 *
 * Returns 1 in case of success, -1 in case of error, 0 if not moved
 */
int
xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(-1);
    if (reader->node->type != XML_ELEMENT_NODE)
        return(0);
    if (reader->curnode != NULL) {
        reader->curnode = NULL;
        return(1);
    }
    return(0);
}

/**
 * xmlTextReaderReadAttributeValue:
 * @reader:  the xmlTextReaderPtr used
 *
 * Parses an attribute value into one or more Text and EntityReference nodes.
 *
 * Returns 1 in case of success, 0 if the reader was not positionned on an
 *         ttribute node or all the attribute values have been read, or -1
 *         in case of error.
 */
int
xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(-1);
    if (reader->curnode == NULL)
        return(0);
    if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
        if (reader->curnode->children == NULL)
            return(0);
        reader->curnode = reader->curnode->children;
    } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
        xmlNsPtr ns = (xmlNsPtr) reader->curnode;

        if (reader->faketext == NULL) {
            reader->faketext = xmlNewDocText(reader->node->doc,
                                             ns->href);
        } else {
            if ((reader->faketext->content != NULL) &&
                (reader->faketext->content !=
                 (xmlChar *) &(reader->faketext->properties)))
                xmlFree(reader->faketext->content);
            reader->faketext->content = xmlStrdup(ns->href);
        }
        reader->curnode = reader->faketext;
    } else {
        if (reader->curnode->next == NULL)
            return(0);
        reader->curnode = reader->curnode->next;
    }
    return(1);
}

/**
 * xmlTextReaderConstEncoding:
 * @reader:  the xmlTextReaderPtr used
 *
 * Determine the encoding of the document being read.
 *
 * Returns a string containing the encoding of the document or NULL in
 * case of error.  The string is deallocated with the reader.
 */
const xmlChar *
xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
    xmlDocPtr doc = NULL;
    if (reader == NULL)
        return(NULL);
    if (reader->doc != NULL)
        doc = reader->doc;
    else if (reader->ctxt != NULL)
        doc = reader->ctxt->myDoc;
    if (doc == NULL)
        return(NULL);

    if (doc->encoding == NULL)
        return(NULL);
    else
      return(CONSTSTR(doc->encoding));
}


/************************************************************************
 *                                                                      *
 *                      Acces API to the current node                   *
 *                                                                      *
 ************************************************************************/
/**
 * xmlTextReaderAttributeCount:
 * @reader:  the xmlTextReaderPtr used
 *
 * Provides the number of attributes of the current node
 *
 * Returns 0 i no attributes, -1 in case of error or the attribute count
 */
int
xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
    int ret;
    xmlAttrPtr attr;
    xmlNsPtr ns;
    xmlNodePtr node;

    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(0);

    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;

    if (node->type != XML_ELEMENT_NODE)
        return(0);
    if ((reader->state == XML_TEXTREADER_END) ||
        (reader->state == XML_TEXTREADER_BACKTRACK))
        return(0);
    ret = 0;
    attr = node->properties;
    while (attr != NULL) {
        ret++;
        attr = attr->next;
    }
    ns = node->nsDef;
    while (ns != NULL) {
        ret++;
        ns = ns->next;
    }
    return(ret);
}

/**
 * xmlTextReaderNodeType:
 * @reader:  the xmlTextReaderPtr used
 *
 * Get the node type of the current node
 * Reference:
 * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html
 *
 * Returns the xmlNodeType of the current node or -1 in case of error
 */
int
xmlTextReaderNodeType(xmlTextReaderPtr reader) {
    xmlNodePtr node;

    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(XML_READER_TYPE_NONE);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    switch (node->type) {
        case XML_ELEMENT_NODE:
            if ((reader->state == XML_TEXTREADER_END) ||
                (reader->state == XML_TEXTREADER_BACKTRACK))
                return(XML_READER_TYPE_END_ELEMENT);
            return(XML_READER_TYPE_ELEMENT);
        case XML_NAMESPACE_DECL:
        case XML_ATTRIBUTE_NODE:
            return(XML_READER_TYPE_ATTRIBUTE);
        case XML_TEXT_NODE:
            if (xmlIsBlankNode(reader->node)) {
                if (xmlNodeGetSpacePreserve(reader->node))
                    return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
                else
                    return(XML_READER_TYPE_WHITESPACE);
            } else {
                return(XML_READER_TYPE_TEXT);
            }
        case XML_CDATA_SECTION_NODE:
            return(XML_READER_TYPE_CDATA);
        case XML_ENTITY_REF_NODE:
            return(XML_READER_TYPE_ENTITY_REFERENCE);
        case XML_ENTITY_NODE:
            return(XML_READER_TYPE_ENTITY);
        case XML_PI_NODE:
            return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
        case XML_COMMENT_NODE:
            return(XML_READER_TYPE_COMMENT);
        case XML_DOCUMENT_NODE:
        case XML_HTML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
        case XML_DOCB_DOCUMENT_NODE:
#endif
            return(XML_READER_TYPE_DOCUMENT);
        case XML_DOCUMENT_FRAG_NODE:
            return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
        case XML_NOTATION_NODE:
            return(XML_READER_TYPE_NOTATION);
        case XML_DOCUMENT_TYPE_NODE:
        case XML_DTD_NODE:
            return(XML_READER_TYPE_DOCUMENT_TYPE);

        case XML_ELEMENT_DECL:
        case XML_ATTRIBUTE_DECL:
        case XML_ENTITY_DECL:
        case XML_XINCLUDE_START:
        case XML_XINCLUDE_END:
            return(XML_READER_TYPE_NONE);
    }
    return(-1);
}

/**
 * xmlTextReaderIsEmptyElement:
 * @reader:  the xmlTextReaderPtr used
 *
 * Check if the current node is empty
 *
 * Returns 1 if empty, 0 if not and -1 in case of error
 */
int
xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
    if ((reader == NULL) || (reader->node == NULL))
        return(-1);
    if (reader->node->type != XML_ELEMENT_NODE)
        return(0);
    if (reader->curnode != NULL)
        return(0);
    if (reader->node->children != NULL)
        return(0);
    if (reader->state == XML_TEXTREADER_END)
        return(0);
    if (reader->doc != NULL)
        return(1);
#ifdef LIBXML_XINCLUDE_ENABLED
    if (reader->in_xinclude > 0)
        return(1);
#endif
    return((reader->node->extra & NODE_IS_EMPTY) != 0);
}

/**
 * xmlTextReaderLocalName:
 * @reader:  the xmlTextReaderPtr used
 *
 * The local name of the node.
 *
 * Returns the local name or NULL if not available,
 *   if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderLocalName(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    if (node->type == XML_NAMESPACE_DECL) {
        xmlNsPtr ns = (xmlNsPtr) node;
        if (ns->prefix == NULL)
            return(xmlStrdup(BAD_CAST "xmlns"));
        else
            return(xmlStrdup(ns->prefix));
    }
    if ((node->type != XML_ELEMENT_NODE) &&
        (node->type != XML_ATTRIBUTE_NODE))
        return(xmlTextReaderName(reader));
    return(xmlStrdup(node->name));
}

/**
 * xmlTextReaderConstLocalName:
 * @reader:  the xmlTextReaderPtr used
 *
 * The local name of the node.
 *
 * Returns the local name or NULL if not available, the
 *         string will be deallocated with the reader.
 */
const xmlChar *
xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    if (node->type == XML_NAMESPACE_DECL) {
        xmlNsPtr ns = (xmlNsPtr) node;
        if (ns->prefix == NULL)
            return(CONSTSTR(BAD_CAST "xmlns"));
        else
            return(ns->prefix);
    }
    if ((node->type != XML_ELEMENT_NODE) &&
        (node->type != XML_ATTRIBUTE_NODE))
        return(xmlTextReaderConstName(reader));
    return(node->name);
}

/**
 * xmlTextReaderName:
 * @reader:  the xmlTextReaderPtr used
 *
 * The qualified name of the node, equal to Prefix :LocalName.
 *
 * Returns the local name or NULL if not available,
 *   if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderName(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    xmlChar *ret;

    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    switch (node->type) {
        case XML_ELEMENT_NODE:
        case XML_ATTRIBUTE_NODE:
            if ((node->ns == NULL) ||
                (node->ns->prefix == NULL))
                return(xmlStrdup(node->name));

            ret = xmlStrdup(node->ns->prefix);
            ret = xmlStrcat(ret, BAD_CAST ":");
            ret = xmlStrcat(ret, node->name);
            return(ret);
        case XML_TEXT_NODE:
            return(xmlStrdup(BAD_CAST "#text"));
        case XML_CDATA_SECTION_NODE:
            return(xmlStrdup(BAD_CAST "#cdata-section"));
        case XML_ENTITY_NODE:
        case XML_ENTITY_REF_NODE:
            return(xmlStrdup(node->name));
        case XML_PI_NODE:
            return(xmlStrdup(node->name));
        case XML_COMMENT_NODE:
            return(xmlStrdup(BAD_CAST "#comment"));
        case XML_DOCUMENT_NODE:
        case XML_HTML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
        case XML_DOCB_DOCUMENT_NODE:
#endif
            return(xmlStrdup(BAD_CAST "#document"));
        case XML_DOCUMENT_FRAG_NODE:
            return(xmlStrdup(BAD_CAST "#document-fragment"));
        case XML_NOTATION_NODE:
            return(xmlStrdup(node->name));
        case XML_DOCUMENT_TYPE_NODE:
        case XML_DTD_NODE:
            return(xmlStrdup(node->name));
        case XML_NAMESPACE_DECL: {
            xmlNsPtr ns = (xmlNsPtr) node;

            ret = xmlStrdup(BAD_CAST "xmlns");
            if (ns->prefix == NULL)
                return(ret);
            ret = xmlStrcat(ret, BAD_CAST ":");
            ret = xmlStrcat(ret, ns->prefix);
            return(ret);
        }

        case XML_ELEMENT_DECL:
        case XML_ATTRIBUTE_DECL:
        case XML_ENTITY_DECL:
        case XML_XINCLUDE_START:
        case XML_XINCLUDE_END:
            return(NULL);
    }
    return(NULL);
}

/**
 * xmlTextReaderConstName:
 * @reader:  the xmlTextReaderPtr used
 *
 * The qualified name of the node, equal to Prefix :LocalName.
 *
 * Returns the local name or NULL if not available, the string is
 *         deallocated with the reader.
 */
const xmlChar *
xmlTextReaderConstName(xmlTextReaderPtr reader) {
    xmlNodePtr node;

    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    switch (node->type) {
        case XML_ELEMENT_NODE:
        case XML_ATTRIBUTE_NODE:
            if ((node->ns == NULL) ||
                (node->ns->prefix == NULL))
                return(node->name);
            return(CONSTQSTR(node->ns->prefix, node->name));
        case XML_TEXT_NODE:
            return(CONSTSTR(BAD_CAST "#text"));
        case XML_CDATA_SECTION_NODE:
            return(CONSTSTR(BAD_CAST "#cdata-section"));
        case XML_ENTITY_NODE:
        case XML_ENTITY_REF_NODE:
            return(CONSTSTR(node->name));
        case XML_PI_NODE:
            return(CONSTSTR(node->name));
        case XML_COMMENT_NODE:
            return(CONSTSTR(BAD_CAST "#comment"));
        case XML_DOCUMENT_NODE:
        case XML_HTML_DOCUMENT_NODE:
#ifdef LIBXML_DOCB_ENABLED
        case XML_DOCB_DOCUMENT_NODE:
#endif
            return(CONSTSTR(BAD_CAST "#document"));
        case XML_DOCUMENT_FRAG_NODE:
            return(CONSTSTR(BAD_CAST "#document-fragment"));
        case XML_NOTATION_NODE:
            return(CONSTSTR(node->name));
        case XML_DOCUMENT_TYPE_NODE:
        case XML_DTD_NODE:
            return(CONSTSTR(node->name));
        case XML_NAMESPACE_DECL: {
            xmlNsPtr ns = (xmlNsPtr) node;

            if (ns->prefix == NULL)
                return(CONSTSTR(BAD_CAST "xmlns"));
            return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
        }

        case XML_ELEMENT_DECL:
        case XML_ATTRIBUTE_DECL:
        case XML_ENTITY_DECL:
        case XML_XINCLUDE_START:
        case XML_XINCLUDE_END:
            return(NULL);
    }
    return(NULL);
}

/**
 * xmlTextReaderPrefix:
 * @reader:  the xmlTextReaderPtr used
 *
 * A shorthand reference to the namespace associated with the node.
 *
 * Returns the prefix or NULL if not available,
 *    if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderPrefix(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    if (node->type == XML_NAMESPACE_DECL) {
        xmlNsPtr ns = (xmlNsPtr) node;
        if (ns->prefix == NULL)
            return(NULL);
        return(xmlStrdup(BAD_CAST "xmlns"));
    }
    if ((node->type != XML_ELEMENT_NODE) &&
        (node->type != XML_ATTRIBUTE_NODE))
        return(NULL);
    if ((node->ns != NULL) && (node->ns->prefix != NULL))
        return(xmlStrdup(node->ns->prefix));
    return(NULL);
}

/**
 * xmlTextReaderConstPrefix:
 * @reader:  the xmlTextReaderPtr used
 *
 * A shorthand reference to the namespace associated with the node.
 *
 * Returns the prefix or NULL if not available, the string is deallocated
 *         with the reader.
 */
const xmlChar *
xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    if (node->type == XML_NAMESPACE_DECL) {
        xmlNsPtr ns = (xmlNsPtr) node;
        if (ns->prefix == NULL)
            return(NULL);
        return(CONSTSTR(BAD_CAST "xmlns"));
    }
    if ((node->type != XML_ELEMENT_NODE) &&
        (node->type != XML_ATTRIBUTE_NODE))
        return(NULL);
    if ((node->ns != NULL) && (node->ns->prefix != NULL))
        return(CONSTSTR(node->ns->prefix));
    return(NULL);
}

/**
 * xmlTextReaderNamespaceUri:
 * @reader:  the xmlTextReaderPtr used
 *
 * The URI defining the namespace associated with the node.
 *
 * Returns the namespace URI or NULL if not available,
 *    if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    if (node->type == XML_NAMESPACE_DECL)
        return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
    if ((node->type != XML_ELEMENT_NODE) &&
        (node->type != XML_ATTRIBUTE_NODE))
        return(NULL);
    if (node->ns != NULL)
        return(xmlStrdup(node->ns->href));
    return(NULL);
}

/**
 * xmlTextReaderConstNamespaceUri:
 * @reader:  the xmlTextReaderPtr used
 *
 * The URI defining the namespace associated with the node.
 *
 * Returns the namespace URI or NULL if not available, the string
 *         will be deallocated with the reader
 */
const xmlChar *
xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;
    if (node->type == XML_NAMESPACE_DECL)
        return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
    if ((node->type != XML_ELEMENT_NODE) &&
        (node->type != XML_ATTRIBUTE_NODE))
        return(NULL);
    if (node->ns != NULL)
        return(CONSTSTR(node->ns->href));
    return(NULL);
}

/**
 * xmlTextReaderBaseUri:
 * @reader:  the xmlTextReaderPtr used
 *
 * The base URI of the node.
 *
 * Returns the base URI or NULL if not available,
 *    if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    return(xmlNodeGetBase(NULL, reader->node));
}

/**
 * xmlTextReaderConstBaseUri:
 * @reader:  the xmlTextReaderPtr used
 *
 * The base URI of the node.
 *
 * Returns the base URI or NULL if not available, the string
 *         will be deallocated with the reader
 */
const xmlChar *
xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
    xmlChar *tmp;
    const xmlChar *ret;

    if ((reader == NULL) || (reader->node == NULL))
        return(NULL);
    tmp = xmlNodeGetBase(NULL, reader->node);
    if (tmp == NULL)
        return(NULL);
    ret = CONSTSTR(tmp);
    xmlFree(tmp);
    return(ret);
}

/**
 * xmlTextReaderDepth:
 * @reader:  the xmlTextReaderPtr used
 *
 * The depth of the node in the tree.
 *
 * Returns the depth or -1 in case of error
 */
int
xmlTextReaderDepth(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(0);

    if (reader->curnode != NULL) {
        if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
            (reader->curnode->type == XML_NAMESPACE_DECL))
            return(reader->depth + 1);
        return(reader->depth + 2);
    }
    return(reader->depth);
}

/**
 * xmlTextReaderHasAttributes:
 * @reader:  the xmlTextReaderPtr used
 *
 * Whether the node has attributes.
 *
 * Returns 1 if true, 0 if false, and -1 in case or error
 */
int
xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(0);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;

    if ((node->type == XML_ELEMENT_NODE) &&
        ((node->properties != NULL) || (node->nsDef != NULL)))
        return(1);
    /* TODO: handle the xmlDecl */
    return(0);
}

/**
 * xmlTextReaderHasValue:
 * @reader:  the xmlTextReaderPtr used
 *
 * Whether the node can have a text value.
 *
 * Returns 1 if true, 0 if false, and -1 in case or error
 */
int
xmlTextReaderHasValue(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(0);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;

    switch (node->type) {
        case XML_ATTRIBUTE_NODE:
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
        case XML_PI_NODE:
        case XML_COMMENT_NODE:
        case XML_NAMESPACE_DECL:
            return(1);
        default:
            break;
    }
    return(0);
}

/**
 * xmlTextReaderValue:
 * @reader:  the xmlTextReaderPtr used
 *
 * Provides the text value of the node if present
 *
 * Returns the string or NULL if not available. The result must be deallocated
 *     with xmlFree()
 */
xmlChar *
xmlTextReaderValue(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;

    switch (node->type) {
        case XML_NAMESPACE_DECL:
            return(xmlStrdup(((xmlNsPtr) node)->href));
        case XML_ATTRIBUTE_NODE:{
            xmlAttrPtr attr = (xmlAttrPtr) node;

            if (attr->parent != NULL)
                return (xmlNodeListGetString
                        (attr->parent->doc, attr->children, 1));
            else
                return (xmlNodeListGetString(NULL, attr->children, 1));
            break;
        }
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
        case XML_PI_NODE:
        case XML_COMMENT_NODE:
            if (node->content != NULL)
                return (xmlStrdup(node->content));
        default:
            break;
    }
    return(NULL);
}

/**
 * xmlTextReaderConstValue:
 * @reader:  the xmlTextReaderPtr used
 *
 * Provides the text value of the node if present
 *
 * Returns the string or NULL if not available. The result will be
 *     deallocated on the next Read() operation.
 */
const xmlChar *
xmlTextReaderConstValue(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;

    switch (node->type) {
        case XML_NAMESPACE_DECL:
            return(((xmlNsPtr) node)->href);
        case XML_ATTRIBUTE_NODE:{
            xmlAttrPtr attr = (xmlAttrPtr) node;

            if ((attr->children != NULL) &&
                (attr->children->type == XML_TEXT_NODE) &&
                (attr->children->next == NULL))
                return(attr->children->content);
            else {
                if (reader->buffer == NULL)
                    reader->buffer = xmlBufferCreateSize(100);
                if (reader->buffer == NULL) {
                    xmlGenericError(xmlGenericErrorContext,
                                    "xmlTextReaderSetup : malloc failed\n");
                    return (NULL);
                }
                reader->buffer->use = 0;
                xmlNodeBufGetContent(reader->buffer, node);
                return(reader->buffer->content);
            }
            break;
        }
        case XML_TEXT_NODE:
        case XML_CDATA_SECTION_NODE:
        case XML_PI_NODE:
        case XML_COMMENT_NODE:
            return(node->content);
        default:
            break;
    }
    return(NULL);
}

/**
 * xmlTextReaderIsDefault:
 * @reader:  the xmlTextReaderPtr used
 *
 * Whether an Attribute  node was generated from the default value
 * defined in the DTD or schema.
 *
 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
 */
int
xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    return(0);
}

/**
 * xmlTextReaderQuoteChar:
 * @reader:  the xmlTextReaderPtr used
 *
 * The quotation mark character used to enclose the value of an attribute.
 *
 * Returns " or ' and -1 in case of error
 */
int
xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    /* TODO maybe lookup the attribute value for " first */
    return((int) '"');
}

/**
 * xmlTextReaderXmlLang:
 * @reader:  the xmlTextReaderPtr used
 *
 * The xml:lang scope within which the node resides.
 *
 * Returns the xml:lang value or NULL if none exists.,
 *    if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    return(xmlNodeGetLang(reader->node));
}

/**
 * xmlTextReaderConstXmlLang:
 * @reader:  the xmlTextReaderPtr used
 *
 * The xml:lang scope within which the node resides.
 *
 * Returns the xml:lang value or NULL if none exists.
 */
const xmlChar *
xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
    xmlChar *tmp;
    const xmlChar *ret;

    if (reader == NULL)
        return(NULL);
    if (reader->node == NULL)
        return(NULL);
    tmp = xmlNodeGetLang(reader->node);
    if (tmp == NULL)
        return(NULL);
    ret = CONSTSTR(tmp);
    xmlFree(tmp);
    return(ret);
}

/**
 * xmlTextReaderConstString:
 * @reader:  the xmlTextReaderPtr used
 * @str:  the string to intern.
 *
 * Get an interned string from the reader, allows for example to
 * speedup string name comparisons
 *
 * Returns an interned copy of the string or NULL in case of error. The
 *         string will be deallocated with the reader.
 */
const xmlChar *
xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
    if (reader == NULL)
        return(NULL);
    return(CONSTSTR(str));
}

/**
 * xmlTextReaderNormalization:
 * @reader:  the xmlTextReaderPtr used
 *
 * The value indicating whether to normalize white space and attribute values.
 * Since attribute value and end of line normalizations are a MUST in the XML
 * specification only the value true is accepted. The broken bahaviour of
 * accepting out of range character entities like &#0; is of course not
 * supported either.
 *
 * Returns 1 or -1 in case of error.
 */
int
xmlTextReaderNormalization(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(-1);
    return(1);
}

/************************************************************************
 *                                                                      *
 *                      Extensions to the base APIs                     *
 *                                                                      *
 ************************************************************************/

/**
 * xmlTextReaderSetParserProp:
 * @reader:  the xmlTextReaderPtr used
 * @prop:  the xmlParserProperties to set
 * @value:  usually 0 or 1 to (de)activate it
 *
 * Change the parser processing behaviour by changing some of its internal
 * properties. Note that some properties can only be changed before any
 * read has been done.
 *
 * Returns 0 if the call was successful, or -1 in case of error
 */
int
xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
    xmlParserProperties p = (xmlParserProperties) prop;
    xmlParserCtxtPtr ctxt;

    if ((reader == NULL) || (reader->ctxt == NULL))
        return(-1);
    ctxt = reader->ctxt;

    switch (p) {
        case XML_PARSER_LOADDTD:
            if (value != 0) {
                if (ctxt->loadsubset == 0) {
                    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
                        return(-1);
                    ctxt->loadsubset = XML_DETECT_IDS;
                }
            } else {
                ctxt->loadsubset = 0;
            }
            return(0);
        case XML_PARSER_DEFAULTATTRS:
            if (value != 0) {
                ctxt->loadsubset |= XML_COMPLETE_ATTRS;
            } else {
                if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
                    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
            }
            return(0);
        case XML_PARSER_VALIDATE:
            if (value != 0) {
                ctxt->validate = 1;
                reader->validate = XML_TEXTREADER_VALIDATE_DTD;
            } else {
                ctxt->validate = 0;
            }
            return(0);
        case XML_PARSER_SUBST_ENTITIES:
            if (value != 0) {
                ctxt->replaceEntities = 1;
            } else {
                ctxt->replaceEntities = 0;
            }
            return(0);
    }
    return(-1);
}

/**
 * xmlTextReaderGetParserProp:
 * @reader:  the xmlTextReaderPtr used
 * @prop:  the xmlParserProperties to get
 *
 * Read the parser internal property.
 *
 * Returns the value, usually 0 or 1, or -1 in case of error.
 */
int
xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
    xmlParserProperties p = (xmlParserProperties) prop;
    xmlParserCtxtPtr ctxt;

    if ((reader == NULL) || (reader->ctxt == NULL))
        return(-1);
    ctxt = reader->ctxt;

    switch (p) {
        case XML_PARSER_LOADDTD:
            if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
                return(1);
            return(0);
        case XML_PARSER_DEFAULTATTRS:
            if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
                return(1);
            return(0);
        case XML_PARSER_VALIDATE:
            return(reader->validate);
        case XML_PARSER_SUBST_ENTITIES:
            return(ctxt->replaceEntities);
    }
    return(-1);
}


/**
 * xmlTextReaderGetParserLineNumber:
 * @reader: the user data (XML reader context)
 *
 * Provide the line number of the current parsing point.
 *
 * Returns an int or 0 if not available
 */
int
xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
{
    if ((reader == NULL) || (reader->ctxt == NULL) ||
        (reader->ctxt->input == NULL)) {
        return (0);
    }
    return (reader->ctxt->input->line);
}

/**
 * xmlTextReaderGetParserColumnNumber:
 * @reader: the user data (XML reader context)
 *
 * Provide the column number of the current parsing point.
 *
 * Returns an int or 0 if not available
 */
int
xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
{
    if ((reader == NULL) || (reader->ctxt == NULL) ||
        (reader->ctxt->input == NULL)) {
        return (0);
    }
    return (reader->ctxt->input->col);
}

/**
 * xmlTextReaderCurrentNode:
 * @reader:  the xmlTextReaderPtr used
 *
 * Hacking interface allowing to get the xmlNodePtr correponding to the
 * current node being accessed by the xmlTextReader. This is dangerous
 * because the underlying node may be destroyed on the next Reads.
 *
 * Returns the xmlNodePtr or NULL in case of error.
 */
xmlNodePtr
xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(NULL);

    if (reader->curnode != NULL)
        return(reader->curnode);
    return(reader->node);
}

/**
 * xmlTextReaderPreserve:
 * @reader:  the xmlTextReaderPtr used
 *
 * This tells the XML Reader to preserve the current node.
 * The caller must also use xmlTextReaderCurrentDoc() to
 * keep an handle on the resulting document once parsing has finished
 *
 * Returns the xmlNodePtr or NULL in case of error.
 */
xmlNodePtr
xmlTextReaderPreserve(xmlTextReaderPtr reader) {
    xmlNodePtr cur, parent;

    if (reader == NULL)
        return(NULL);

    if (reader->curnode != NULL)
        cur = reader->curnode;
    else
        cur = reader->node;
    if (cur == NULL)
        return(NULL);

    if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
        cur->extra |= NODE_IS_PRESERVED;
        cur->extra |= NODE_IS_SPRESERVED;
    }
    reader->preserves++;

    parent = cur->parent;;
    while (parent != NULL) {
        if (parent->type == XML_ELEMENT_NODE)
            parent->extra |= NODE_IS_PRESERVED;
        parent = parent->parent;
    }
    return(cur);
}

#ifdef LIBXML_PATTERN_ENABLED
/**
 * xmlTextReaderPreservePattern:
 * @reader:  the xmlTextReaderPtr used
 * @pattern:  an XPath subset pattern
 * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
 *
 * This tells the XML Reader to preserve all nodes matched by the
 * pattern. The caller must also use xmlTextReaderCurrentDoc() to
 * keep an handle on the resulting document once parsing has finished
 *
 * Returns a positive number in case of success and -1 in case of error
 */
int
xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
                             const xmlChar **namespaces)
{
    xmlPatternPtr comp;

    if ((reader == NULL) || (pattern == NULL))
        return(-1);

    comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
    if (comp == NULL)
        return(-1);

    if (reader->patternMax <= 0) {
        reader->patternMax = 4;
        reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
                                              sizeof(reader->patternTab[0]));
        if (reader->patternTab == NULL) {
            xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
            return (-1);
        }
    }
    if (reader->patternNr >= reader->patternMax) {
        xmlPatternPtr *tmp;
        reader->patternMax *= 2;
        tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
                                      reader->patternMax *
                                      sizeof(reader->patternTab[0]));
        if (tmp == NULL) {
            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
            reader->patternMax /= 2;
            return (-1);
        }
        reader->patternTab = tmp;
    }
    reader->patternTab[reader->patternNr] = comp;
    return(reader->patternNr++);
}
#endif

/**
 * xmlTextReaderCurrentDoc:
 * @reader:  the xmlTextReaderPtr used
 *
 * Hacking interface allowing to get the xmlDocPtr correponding to the
 * current document being accessed by the xmlTextReader.
 * NOTE: as a result of this call, the reader will not destroy the
 *       associated XML document and calling xmlFreeDoc() on the result
 *       is needed once the reader parsing has finished.
 *
 * Returns the xmlDocPtr or NULL in case of error.
 */
xmlDocPtr
xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
    if (reader == NULL)
        return(NULL);
    if (reader->doc != NULL)
        return(reader->doc);
    if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
        return(NULL);

    reader->preserve = 1;
    return(reader->ctxt->myDoc);
}

#ifdef LIBXML_SCHEMAS_ENABLED
static char *xmlTextReaderBuildMessage(const char *msg, va_list ap);

static void XMLCDECL
xmlTextReaderValidityError(void *ctxt, const char *msg, ...);

static void XMLCDECL
xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);

static void XMLCDECL
xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
{
    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;

    char *str;

    va_list ap;

    va_start(ap, msg);
    str = xmlTextReaderBuildMessage(msg, ap);
    if (!reader->errorFunc) {
        xmlTextReaderValidityError(ctx, "%s", str);
    } else {
        reader->errorFunc(reader->errorFuncArg, str,
                          XML_PARSER_SEVERITY_VALIDITY_ERROR,
                          NULL /* locator */ );
    }
    if (str != NULL)
        xmlFree(str);
    va_end(ap);
}

static void XMLCDECL
xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
{
    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;

    char *str;

    va_list ap;

    va_start(ap, msg);
    str = xmlTextReaderBuildMessage(msg, ap);
    if (!reader->errorFunc) {
        xmlTextReaderValidityWarning(ctx, "%s", str);
    } else {
        reader->errorFunc(reader->errorFuncArg, str,
                          XML_PARSER_SEVERITY_VALIDITY_WARNING,
                          NULL /* locator */ );
    }
    if (str != NULL)
        xmlFree(str);
    va_end(ap);
}

static void
  xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);

static void
xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error)
{
    xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;

    if (reader->sErrorFunc) {
        reader->sErrorFunc(reader->errorFuncArg, error);
    } else {
        xmlTextReaderStructuredError(reader, error);
    }
}
/**
 * xmlTextReaderRelaxNGSetSchema:
 * @reader:  the xmlTextReaderPtr used
 * @schema:  a precompiled RelaxNG schema
 *
 * Use RelaxNG to validate the document as it is processed.
 * Activation is only possible before the first Read().
 * if @schema is NULL, then RelaxNG validation is desactivated.
 @ The @schema should not be freed until the reader is deallocated
 * or its use has been deactivated.
 *
 * Returns 0 in case the RelaxNG validation could be (des)activated and
 *         -1 in case of error.
 */
int
xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
    if (reader == NULL)
        return(-1);
    if (schema == NULL) {
        if (reader->rngSchemas != NULL) {
            xmlRelaxNGFree(reader->rngSchemas);
            reader->rngSchemas = NULL;
        }
        if (reader->rngValidCtxt != NULL) {
            xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
            reader->rngValidCtxt = NULL;
        }
        return(0);
    }
    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
        return(-1);
    if (reader->rngSchemas != NULL) {
        xmlRelaxNGFree(reader->rngSchemas);
        reader->rngSchemas = NULL;
    }
    if (reader->rngValidCtxt != NULL) {
        xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
        reader->rngValidCtxt = NULL;
    }
    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
    if (reader->rngValidCtxt == NULL)
        return(-1);
    if (reader->errorFunc != NULL) {
        xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
                        xmlTextReaderValidityErrorRelay,
                        xmlTextReaderValidityWarningRelay,
                        reader);
    }
        if (reader->sErrorFunc != NULL) {
                xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
                        xmlTextReaderValidityStructuredRelay,
                        reader);
    }
    reader->rngValidErrors = 0;
    reader->rngFullNode = NULL;
    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
    return(0);
}

/**
 * xmlTextReaderSetSchema:
 * @reader:  the xmlTextReaderPtr used
 * @schema:  a precompiled Schema schema
 *
 * Use XSD Schema to validate the document as it is processed.
 * Activation is only possible before the first Read().
 * if @schema is NULL, then Schema validation is desactivated.
 @ The @schema should not be freed until the reader is deallocated
 * or its use has been deactivated.
 *
 * Returns 0 in case the Schema validation could be (des)activated and
 *         -1 in case of error.
 */
int
xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
    if (reader == NULL)
        return(-1);
    if (schema == NULL) {
        if (reader->xsdPlug != NULL) {
            xmlSchemaSAXUnplug(reader->xsdPlug);
            reader->xsdPlug = NULL;
        }
        if (reader->xsdValidCtxt != NULL) {
            if (! reader->xsdPreserveCtxt)
                xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
            reader->xsdValidCtxt = NULL;
        }
        reader->xsdPreserveCtxt = 0;
        if (reader->xsdSchemas != NULL) {
            xmlSchemaFree(reader->xsdSchemas);
            reader->xsdSchemas = NULL;
        }
        return(0);
    }
    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
        return(-1);
    if (reader->xsdPlug != NULL) {
        xmlSchemaSAXUnplug(reader->xsdPlug);
        reader->xsdPlug = NULL;
    }
    if (reader->xsdValidCtxt != NULL) {
        if (! reader->xsdPreserveCtxt)
            xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
        reader->xsdValidCtxt = NULL;
    }
    reader->xsdPreserveCtxt = 0;
    if (reader->xsdSchemas != NULL) {
        xmlSchemaFree(reader->xsdSchemas);
        reader->xsdSchemas = NULL;
    }
    reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
    if (reader->xsdValidCtxt == NULL) {
        xmlSchemaFree(reader->xsdSchemas);
        reader->xsdSchemas = NULL;
        return(-1);
    }
    reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
                                       &(reader->ctxt->sax),
                                       &(reader->ctxt->userData));
    if (reader->xsdPlug == NULL) {
        xmlSchemaFree(reader->xsdSchemas);
        reader->xsdSchemas = NULL;
        xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
        reader->xsdValidCtxt = NULL;
        return(-1);
    }
    if (reader->errorFunc != NULL) {
        xmlSchemaSetValidErrors(reader->xsdValidCtxt,
                        xmlTextReaderValidityErrorRelay,
                        xmlTextReaderValidityWarningRelay,
                        reader);
    }
        if (reader->sErrorFunc != NULL) {
                xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
                        xmlTextReaderValidityStructuredRelay,
                        reader);
    }
    reader->xsdValidErrors = 0;
    reader->validate = XML_TEXTREADER_VALIDATE_XSD;
    return(0);
}

/**
 * xmlTextReaderRelaxNGValidate:
 * @reader:  the xmlTextReaderPtr used
 * @rng:  the path to a RelaxNG schema or NULL
 *
 * Use RelaxNG to validate the document as it is processed.
 * Activation is only possible before the first Read().
 * if @rng is NULL, then RelaxNG validation is deactivated.
 *
 * Returns 0 in case the RelaxNG validation could be (de)activated and
 *         -1 in case of error.
 */
int
xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
    xmlRelaxNGParserCtxtPtr ctxt;

    if (reader == NULL)
        return(-1);

    if (rng == NULL) {
        if (reader->rngValidCtxt != NULL) {
            xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
            reader->rngValidCtxt = NULL;
        }
        if (reader->rngSchemas != NULL) {
            xmlRelaxNGFree(reader->rngSchemas);
            reader->rngSchemas = NULL;
        }
        return(0);
    }
    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
        return(-1);
    if (reader->rngSchemas != NULL) {
        xmlRelaxNGFree(reader->rngSchemas);
        reader->rngSchemas = NULL;
    }
    if (reader->rngValidCtxt != NULL) {
        xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
        reader->rngValidCtxt = NULL;
    }
    ctxt = xmlRelaxNGNewParserCtxt(rng);
    if (reader->errorFunc != NULL) {
        xmlRelaxNGSetParserErrors(ctxt,
                         xmlTextReaderValidityErrorRelay,
                         xmlTextReaderValidityWarningRelay,
                         reader);
    }
    if (reader->sErrorFunc != NULL) {
        xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
                        xmlTextReaderValidityStructuredRelay,
                        reader);
    }
    reader->rngSchemas = xmlRelaxNGParse(ctxt);
    xmlRelaxNGFreeParserCtxt(ctxt);
    if (reader->rngSchemas == NULL)
        return(-1);
    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
    if (reader->rngValidCtxt == NULL) {
        xmlRelaxNGFree(reader->rngSchemas);
        reader->rngSchemas = NULL;
        return(-1);
    }
    if (reader->errorFunc != NULL) {
        xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
                         xmlTextReaderValidityErrorRelay,
                         xmlTextReaderValidityWarningRelay,
                         reader);
    }
        if (reader->sErrorFunc != NULL) {
                xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
                        xmlTextReaderValidityStructuredRelay,
                        reader);
    }
    reader->rngValidErrors = 0;
    reader->rngFullNode = NULL;
    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
    return(0);
}

/**
 * xmlTextReaderSchemaValidateInternal:
 * @reader:  the xmlTextReaderPtr used
 * @xsd:  the path to a W3C XSD schema or NULL
 * @ctxt: the XML Schema validation context or NULL
 * @options: options (not used yet)
 *
 * Validate the document as it is processed using XML Schema.
 * Activation is only possible before the first Read().
 * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
 *
 * Returns 0 in case the schemas validation could be (de)activated and
 *         -1 in case of error.
 */
static int
xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
                                    const char *xsd,
                                    xmlSchemaValidCtxtPtr ctxt,
                                    int options ATTRIBUTE_UNUSED)
{
    if (reader == NULL)
        return(-1);

    if ((xsd != NULL) && (ctxt != NULL))
        return(-1);

    if (((xsd != NULL) || (ctxt != NULL)) &&
        ((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
        (reader->ctxt == NULL)))
        return(-1);

    /* Cleanup previous validation stuff. */
    if (reader->xsdPlug != NULL) {
        xmlSchemaSAXUnplug(reader->xsdPlug);
        reader->xsdPlug = NULL;
    }
    if (reader->xsdValidCtxt != NULL) {
        if (! reader->xsdPreserveCtxt)
            xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
        reader->xsdValidCtxt = NULL;
    }
    reader->xsdPreserveCtxt = 0;
    if (reader->xsdSchemas != NULL) {
        xmlSchemaFree(reader->xsdSchemas);
        reader->xsdSchemas = NULL;
    }

    if ((xsd == NULL) && (ctxt == NULL)) {
        /* We just want to deactivate the validation, so get out. */
        return(0);
    }

    if (xsd != NULL) {
        xmlSchemaParserCtxtPtr pctxt;
        /* Parse the schema and create validation environment. */
        pctxt = xmlSchemaNewParserCtxt(xsd);
        if (reader->errorFunc != NULL) {
            xmlSchemaSetParserErrors(pctxt,
                xmlTextReaderValidityErrorRelay,
                xmlTextReaderValidityWarningRelay,
                reader);
        }
        reader->xsdSchemas = xmlSchemaParse(pctxt);
        xmlSchemaFreeParserCtxt(pctxt);
        if (reader->xsdSchemas == NULL)
            return(-1);
        reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
        if (reader->xsdValidCtxt == NULL) {
            xmlSchemaFree(reader->xsdSchemas);
            reader->xsdSchemas = NULL;
            return(-1);
        }
        reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
            &(reader->ctxt->sax),
            &(reader->ctxt->userData));
        if (reader->xsdPlug == NULL) {
            xmlSchemaFree(reader->xsdSchemas);
            reader->xsdSchemas = NULL;
            xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
            reader->xsdValidCtxt = NULL;
            return(-1);
        }
    } else {
        /* Use the given validation context. */
        reader->xsdValidCtxt = ctxt;
        reader->xsdPreserveCtxt = 1;
        reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
            &(reader->ctxt->sax),
            &(reader->ctxt->userData));
        if (reader->xsdPlug == NULL) {
            reader->xsdValidCtxt = NULL;
            reader->xsdPreserveCtxt = 0;
            return(-1);
        }
    }
    /*
    * Redirect the validation context's error channels to use
    * the reader channels.
    * TODO: In case the user provides the validation context we
    *   could make this redirection optional.
    */
    if (reader->errorFunc != NULL) {
        xmlSchemaSetValidErrors(reader->xsdValidCtxt,
                         xmlTextReaderValidityErrorRelay,
                         xmlTextReaderValidityWarningRelay,
                         reader);
    }
        if (reader->sErrorFunc != NULL) {
                xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
                        xmlTextReaderValidityStructuredRelay,
                        reader);
    }
    reader->xsdValidErrors = 0;
    reader->validate = XML_TEXTREADER_VALIDATE_XSD;
    return(0);
}

/**
 * xmlTextReaderSchemaValidateCtxt:
 * @reader:  the xmlTextReaderPtr used
 * @ctxt: the XML Schema validation context or NULL
 * @options: options (not used yet)
 *
 * Use W3C XSD schema context to validate the document as it is processed.
 * Activation is only possible before the first Read().
 * If @ctxt is NULL, then XML Schema validation is deactivated.
 *
 * Returns 0 in case the schemas validation could be (de)activated and
 *         -1 in case of error.
 */
int
xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
                                    xmlSchemaValidCtxtPtr ctxt,
                                    int options)
{
    return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
}

/**
 * xmlTextReaderSchemaValidate:
 * @reader:  the xmlTextReaderPtr used
 * @xsd:  the path to a W3C XSD schema or NULL
 *
 * Use W3C XSD schema to validate the document as it is processed.
 * Activation is only possible before the first Read().
 * If @xsd is NULL, then XML Schema validation is deactivated.
 *
 * Returns 0 in case the schemas validation could be (de)activated and
 *         -1 in case of error.
 */
int
xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
{
    return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
}
#endif

/**
 * xmlTextReaderIsNamespaceDecl:
 * @reader: the xmlTextReaderPtr used
 *
 * Determine whether the current node is a namespace declaration
 * rather than a regular attribute.
 *
 * Returns 1 if the current node is a namespace declaration, 0 if it
 * is a regular attribute or other type of node, or -1 in case of
 * error.
 */
int
xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
    xmlNodePtr node;
    if (reader == NULL)
        return(-1);
    if (reader->node == NULL)
        return(-1);
    if (reader->curnode != NULL)
        node = reader->curnode;
    else
        node = reader->node;

    if (XML_NAMESPACE_DECL == node->type)
        return(1);
    else
        return(0);
}

/**
 * xmlTextReaderConstXmlVersion:
 * @reader:  the xmlTextReaderPtr used
 *
 * Determine the XML version of the document being read.
 *
 * Returns a string containing the XML version of the document or NULL
 * in case of error.  The string is deallocated with the reader.
 */
const xmlChar *
xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
    xmlDocPtr doc = NULL;
    if (reader == NULL)
        return(NULL);
    if (reader->doc != NULL)
        doc = reader->doc;
    else if (reader->ctxt != NULL)
        doc = reader->ctxt->myDoc;
    if (doc == NULL)
        return(NULL);

    if (doc->version == NULL)
        return(NULL);
    else
      return(CONSTSTR(doc->version));
}

/**
 * xmlTextReaderStandalone:
 * @reader:  the xmlTextReaderPtr used
 *
 * Determine the standalone status of the document being read.
 *
 * Returns 1 if the document was declared to be standalone, 0 if it
 * was declared to be not standalone, or -1 if the document did not
 * specify its standalone status or in case of error.
 */
int
xmlTextReaderStandalone(xmlTextReaderPtr reader) {
    xmlDocPtr doc = NULL;
    if (reader == NULL)
        return(-1);
    if (reader->doc != NULL)
        doc = reader->doc;
    else if (reader->ctxt != NULL)
        doc = reader->ctxt->myDoc;
    if (doc == NULL)
        return(-1);

    return(doc->standalone);
}

/************************************************************************
 *                                                                      *
 *                      Error Handling Extensions                       *
 *                                                                      *
 ************************************************************************/

/* helper to build a xmlMalloc'ed string from a format and va_list */
static char *
xmlTextReaderBuildMessage(const char *msg, va_list ap) {
    int size = 0;
    int chars;
    char *larger;
    char *str = NULL;
    va_list aq;

    while (1) {
        VA_COPY(aq, ap);
        chars = vsnprintf(str, size, msg, aq);
        va_end(aq);
        if (chars < 0) {
            xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
            if (str)
                xmlFree(str);
            return NULL;
        }
        if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
            break;
        if (chars < MAX_ERR_MSG_SIZE)
        size = chars + 1;
        else
                size = MAX_ERR_MSG_SIZE;
        if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
            if (str)
                xmlFree(str);
            return NULL;
        }
        str = larger;
    }

    return str;
}

/**
 * xmlTextReaderLocatorLineNumber:
 * @locator: the xmlTextReaderLocatorPtr used
 *
 * Obtain the line number for the given locator.
 *
 * Returns the line number or -1 in case of error.
 */
int
xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
    /* we know that locator is a xmlParserCtxtPtr */
    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
    int ret = -1;

    if (locator == NULL)
        return(-1);
    if (ctx->node != NULL) {
        ret = xmlGetLineNo(ctx->node);
    }
    else {
        /* inspired from error.c */
        xmlParserInputPtr input;
        input = ctx->input;
        if ((input->filename == NULL) && (ctx->inputNr > 1))
            input = ctx->inputTab[ctx->inputNr - 2];
        if (input != NULL) {
            ret = input->line;
        }
        else {
            ret = -1;
        }
    }

    return ret;
}

/**
 * xmlTextReaderLocatorBaseURI:
 * @locator: the xmlTextReaderLocatorPtr used
 *
 * Obtain the base URI for the given locator.
 *
 * Returns the base URI or NULL in case of error,
 *    if non NULL it need to be freed by the caller.
 */
xmlChar *
xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
    /* we know that locator is a xmlParserCtxtPtr */
    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
    xmlChar *ret = NULL;

    if (locator == NULL)
        return(NULL);
    if (ctx->node != NULL) {
        ret = xmlNodeGetBase(NULL,ctx->node);
    }
    else {
        /* inspired from error.c */
        xmlParserInputPtr input;
        input = ctx->input;
        if ((input->filename == NULL) && (ctx->inputNr > 1))
            input = ctx->inputTab[ctx->inputNr - 2];
        if (input != NULL) {
            ret = xmlStrdup(BAD_CAST input->filename);
        }
        else {
            ret = NULL;
        }
    }

    return ret;
}

static void
xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
                          char *str)
{
    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;

    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;

    if (str != NULL) {
        if (reader->errorFunc)
            reader->errorFunc(reader->errorFuncArg, str, severity,
                              (xmlTextReaderLocatorPtr) ctx);
        xmlFree(str);
    }
}

static void
xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error)
{
    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;

    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;

    if (error && reader->sErrorFunc) {
        reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
    }
}

static void XMLCDECL
xmlTextReaderError(void *ctxt, const char *msg, ...)
{
    va_list ap;

    va_start(ap, msg);
    xmlTextReaderGenericError(ctxt,
                              XML_PARSER_SEVERITY_ERROR,
                              xmlTextReaderBuildMessage(msg, ap));
    va_end(ap);

}

static void XMLCDECL
xmlTextReaderWarning(void *ctxt, const char *msg, ...)
{
    va_list ap;

    va_start(ap, msg);
    xmlTextReaderGenericError(ctxt,
                              XML_PARSER_SEVERITY_WARNING,
                              xmlTextReaderBuildMessage(msg, ap));
    va_end(ap);
}

static void XMLCDECL
xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
{
    va_list ap;

    int len = xmlStrlen((const xmlChar *) msg);

    if ((len > 1) && (msg[len - 2] != ':')) {
        /*
         * some callbacks only report locator information:
         * skip them (mimicking behaviour in error.c)
         */
        va_start(ap, msg);
        xmlTextReaderGenericError(ctxt,
                                  XML_PARSER_SEVERITY_VALIDITY_ERROR,
                                  xmlTextReaderBuildMessage(msg, ap));
        va_end(ap);
    }
}

static void XMLCDECL
xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
{
    va_list ap;

    int len = xmlStrlen((const xmlChar *) msg);

    if ((len != 0) && (msg[len - 1] != ':')) {
        /*
         * some callbacks only report locator information:
         * skip them (mimicking behaviour in error.c)
         */
        va_start(ap, msg);
        xmlTextReaderGenericError(ctxt,
                                  XML_PARSER_SEVERITY_VALIDITY_WARNING,
                                  xmlTextReaderBuildMessage(msg, ap));
        va_end(ap);
    }
}

/**
 * xmlTextReaderSetErrorHandler:
 * @reader:  the xmlTextReaderPtr used
 * @f:  the callback function to call on error and warnings
 * @arg:    a user argument to pass to the callback function
 *
 * Register a callback function that will be called on error and warnings.
 *
 * If @f is NULL, the default error and warning handlers are restored.
 */
void
xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
                             xmlTextReaderErrorFunc f, void *arg)
{
    if (f != NULL) {
        reader->ctxt->sax->error = xmlTextReaderError;
        reader->ctxt->sax->serror = NULL;
        reader->ctxt->vctxt.error = xmlTextReaderValidityError;
        reader->ctxt->sax->warning = xmlTextReaderWarning;
        reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
        reader->errorFunc = f;
        reader->sErrorFunc = NULL;
        reader->errorFuncArg = arg;
#ifdef LIBXML_SCHEMAS_ENABLED
        if (reader->rngValidCtxt) {
            xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
                                     xmlTextReaderValidityErrorRelay,
                                     xmlTextReaderValidityWarningRelay,
                                     reader);
            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
                                               reader);
        }
        if (reader->xsdValidCtxt) {
            xmlSchemaSetValidErrors(reader->xsdValidCtxt,
                                    xmlTextReaderValidityErrorRelay,
                                    xmlTextReaderValidityWarningRelay,
                                    reader);
            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
                                              reader);
        }
#endif
    } else {
        /* restore defaults */
        reader->ctxt->sax->error = xmlParserError;
        reader->ctxt->vctxt.error = xmlParserValidityError;
        reader->ctxt->sax->warning = xmlParserWarning;
        reader->ctxt->vctxt.warning = xmlParserValidityWarning;
        reader->errorFunc = NULL;
        reader->sErrorFunc = NULL;
        reader->errorFuncArg = NULL;
#ifdef LIBXML_SCHEMAS_ENABLED
        if (reader->rngValidCtxt) {
            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
                                     reader);
            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
                                               reader);
        }
        if (reader->xsdValidCtxt) {
            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
                                    reader);
            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
                                              reader);
        }
#endif
    }
}

/**
* xmlTextReaderSetStructuredErrorHandler:
 * @reader:  the xmlTextReaderPtr used
 * @f:  the callback function to call on error and warnings
 * @arg:    a user argument to pass to the callback function
 *
 * Register a callback function that will be called on error and warnings.
 *
 * If @f is NULL, the default error and warning handlers are restored.
 */
void
xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
                                       xmlStructuredErrorFunc f, void *arg)
{
    if (f != NULL) {
        reader->ctxt->sax->error = NULL;
        reader->ctxt->sax->serror = xmlTextReaderStructuredError;
        reader->ctxt->vctxt.error = xmlTextReaderValidityError;
        reader->ctxt->sax->warning = xmlTextReaderWarning;
        reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
        reader->sErrorFunc = f;
        reader->errorFunc = NULL;
        reader->errorFuncArg = arg;
#ifdef LIBXML_SCHEMAS_ENABLED
        if (reader->rngValidCtxt) {
            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
                                     reader);
            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
                                        xmlTextReaderValidityStructuredRelay,
                                               reader);
        }
        if (reader->xsdValidCtxt) {
            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
                                    reader);
            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
                                       xmlTextReaderValidityStructuredRelay,
                                              reader);
        }
#endif
    } else {
        /* restore defaults */
        reader->ctxt->sax->error = xmlParserError;
        reader->ctxt->sax->serror = NULL;
        reader->ctxt->vctxt.error = xmlParserValidityError;
        reader->ctxt->sax->warning = xmlParserWarning;
        reader->ctxt->vctxt.warning = xmlParserValidityWarning;
        reader->errorFunc = NULL;
        reader->sErrorFunc = NULL;
        reader->errorFuncArg = NULL;
#ifdef LIBXML_SCHEMAS_ENABLED
        if (reader->rngValidCtxt) {
            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
                                     reader);
            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
                                               reader);
        }
        if (reader->xsdValidCtxt) {
            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
                                    reader);
            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
                                              reader);
        }
#endif
    }
}

/**
 * xmlTextReaderIsValid:
 * @reader:  the xmlTextReaderPtr used
 *
 * Retrieve the validity status from the parser context
 *
 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
 */
int
xmlTextReaderIsValid(xmlTextReaderPtr reader)
{
    if (reader == NULL)
        return (-1);
#ifdef LIBXML_SCHEMAS_ENABLED
    if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
        return (reader->rngValidErrors == 0);
    if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
        return (reader->xsdValidErrors == 0);
#endif
    if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
        return (reader->ctxt->valid);
    return (0);
}

/**
 * xmlTextReaderGetErrorHandler:
 * @reader:  the xmlTextReaderPtr used
 * @f:  the callback function or NULL is no callback has been registered
 * @arg:    a user argument
 *
 * Retrieve the error callback function and user argument.
 */
void
xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
                             xmlTextReaderErrorFunc * f, void **arg)
{
    if (f != NULL)
        *f = reader->errorFunc;
    if (arg != NULL)
        *arg = reader->errorFuncArg;
}
/************************************************************************
 *                                                                      *
 *      New set (2.6.0) of simpler and more flexible APIs               *
 *                                                                      *
 ************************************************************************/

/**
 * xmlTextReaderSetup:
 * @reader:  an XML reader
 * @input: xmlParserInputBufferPtr used to feed the reader, will
 *         be destroyed with it.
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Setup an XML reader with new options
 *
 * Returns 0 in case of success and -1 in case of error.
 */
int
xmlTextReaderSetup(xmlTextReaderPtr reader,
                   xmlParserInputBufferPtr input, const char *URL,
                   const char *encoding, int options)
{
    if (reader == NULL) {
        if (input != NULL)
            xmlFreeParserInputBuffer(input);
        return (-1);
    }

    /*
     * we force the generation of compact text nodes on the reader
     * since usr applications should never modify the tree
     */
    options |= XML_PARSE_COMPACT;

    reader->doc = NULL;
    reader->entNr = 0;
    reader->parserFlags = options;
    reader->validate = XML_TEXTREADER_NOT_VALIDATE;
    if ((input != NULL) && (reader->input != NULL) &&
        (reader->allocs & XML_TEXTREADER_INPUT)) {
        xmlFreeParserInputBuffer(reader->input);
        reader->input = NULL;
        reader->allocs -= XML_TEXTREADER_INPUT;
    }
    if (input != NULL) {
        reader->input = input;
        reader->allocs |= XML_TEXTREADER_INPUT;
    }
    if (reader->buffer == NULL)
        reader->buffer = xmlBufferCreateSize(100);
    if (reader->buffer == NULL) {
        xmlGenericError(xmlGenericErrorContext,
                        "xmlTextReaderSetup : malloc failed\n");
        return (-1);
    }
    if (reader->sax == NULL)
        reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
    if (reader->sax == NULL) {
        xmlGenericError(xmlGenericErrorContext,
                        "xmlTextReaderSetup : malloc failed\n");
        return (-1);
    }
    xmlSAXVersion(reader->sax, 2);
    reader->startElement = reader->sax->startElement;
    reader->sax->startElement = xmlTextReaderStartElement;
    reader->endElement = reader->sax->endElement;
    reader->sax->endElement = xmlTextReaderEndElement;
#ifdef LIBXML_SAX1_ENABLED
    if (reader->sax->initialized == XML_SAX2_MAGIC) {
#endif /* LIBXML_SAX1_ENABLED */
        reader->startElementNs = reader->sax->startElementNs;
        reader->sax->startElementNs = xmlTextReaderStartElementNs;
        reader->endElementNs = reader->sax->endElementNs;
        reader->sax->endElementNs = xmlTextReaderEndElementNs;
#ifdef LIBXML_SAX1_ENABLED
    } else {
        reader->startElementNs = NULL;
        reader->endElementNs = NULL;
    }
#endif /* LIBXML_SAX1_ENABLED */
    reader->characters = reader->sax->characters;
    reader->sax->characters = xmlTextReaderCharacters;
    reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
    reader->cdataBlock = reader->sax->cdataBlock;
    reader->sax->cdataBlock = xmlTextReaderCDataBlock;

    reader->mode = XML_TEXTREADER_MODE_INITIAL;
    reader->node = NULL;
    reader->curnode = NULL;
    if (input != NULL) {
        if (reader->input->buffer->use < 4) {
            xmlParserInputBufferRead(input, 4);
        }
        if (reader->ctxt == NULL) {
            if (reader->input->buffer->use >= 4) {
                reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
                       (const char *) reader->input->buffer->content, 4, URL);
                reader->base = 0;
                reader->cur = 4;
            } else {
                reader->ctxt =
                    xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
                reader->base = 0;
                reader->cur = 0;
            }
        } else {
            xmlParserInputPtr inputStream;
            xmlParserInputBufferPtr buf;
            xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;

            xmlCtxtReset(reader->ctxt);
            buf = xmlAllocParserInputBuffer(enc);
            if (buf == NULL) return(-1);
            inputStream = xmlNewInputStream(reader->ctxt);
            if (inputStream == NULL) {
                xmlFreeParserInputBuffer(buf);
                return(-1);
            }

            if (URL == NULL)
                inputStream->filename = NULL;
            else
                inputStream->filename = (char *)
                    xmlCanonicPath((const xmlChar *) URL);
            inputStream->buf = buf;
            inputStream->base = inputStream->buf->buffer->content;
            inputStream->cur = inputStream->buf->buffer->content;
            inputStream->end =
            &inputStream->buf->buffer->content[inputStream->buf->buffer->use];

            inputPush(reader->ctxt, inputStream);
            reader->cur = 0;
        }
        if (reader->ctxt == NULL) {
            xmlGenericError(xmlGenericErrorContext,
                            "xmlTextReaderSetup : malloc failed\n");
            return (-1);
        }
    }
    if (reader->dict != NULL) {
        if (reader->ctxt->dict != NULL) {
            if (reader->dict != reader->ctxt->dict) {
                xmlDictFree(reader->dict);
                reader->dict = reader->ctxt->dict;
            }
        } else {
            reader->ctxt->dict = reader->dict;
        }
    } else {
        if (reader->ctxt->dict == NULL)
            reader->ctxt->dict = xmlDictCreate();
        reader->dict = reader->ctxt->dict;
    }
    reader->ctxt->_private = reader;
    reader->ctxt->linenumbers = 1;
    reader->ctxt->dictNames = 1;
    /*
     * use the parser dictionnary to allocate all elements and attributes names
     */
    reader->ctxt->docdict = 1;
    reader->ctxt->parseMode = XML_PARSE_READER;

#ifdef LIBXML_XINCLUDE_ENABLED
    if (reader->xincctxt != NULL) {
        xmlXIncludeFreeContext(reader->xincctxt);
        reader->xincctxt = NULL;
    }
    if (options & XML_PARSE_XINCLUDE) {
        reader->xinclude = 1;
        reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
        options -= XML_PARSE_XINCLUDE;
    } else
        reader->xinclude = 0;
    reader->in_xinclude = 0;
#endif
#ifdef LIBXML_PATTERN_ENABLED
    if (reader->patternTab == NULL) {
        reader->patternNr = 0;
        reader->patternMax = 0;
    }
    while (reader->patternNr > 0) {
        reader->patternNr--;
        if (reader->patternTab[reader->patternNr] != NULL) {
            xmlFreePattern(reader->patternTab[reader->patternNr]);
            reader->patternTab[reader->patternNr] = NULL;
        }
    }
#endif

    if (options & XML_PARSE_DTDVALID)
        reader->validate = XML_TEXTREADER_VALIDATE_DTD;

    xmlCtxtUseOptions(reader->ctxt, options);
    if (encoding != NULL) {
        xmlCharEncodingHandlerPtr hdlr;

        hdlr = xmlFindCharEncodingHandler(encoding);
        if (hdlr != NULL)
            xmlSwitchToEncoding(reader->ctxt, hdlr);
    }
    if ((URL != NULL) && (reader->ctxt->input != NULL) &&
        (reader->ctxt->input->filename == NULL))
        reader->ctxt->input->filename = (char *)
            xmlStrdup((const xmlChar *) URL);

    reader->doc = NULL;

    return (0);
}

/**
 * xmlTextReaderByteConsumed:
 * @reader: an XML reader
 *
 * This function provides the current index of the parser used
 * by the reader, relative to the start of the current entity.
 * This function actually just wraps a call to xmlBytesConsumed()
 * for the parser context associated with the reader.
 * See xmlBytesConsumed() for more information.
 *
 * Returns the index in bytes from the beginning of the entity or -1
 *         in case the index could not be computed.
 */
long
xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
    if ((reader == NULL) || (reader->ctxt == NULL))
        return(-1);
    return(xmlByteConsumed(reader->ctxt));
}


/**
 * xmlReaderWalker:
 * @doc:  a preparsed document
 *
 * Create an xmltextReader for a preparsed document.
 *
 * Returns the new reader or NULL in case of error.
 */
xmlTextReaderPtr
xmlReaderWalker(xmlDocPtr doc)
{
    xmlTextReaderPtr ret;

    if (doc == NULL)
        return(NULL);

    ret = xmlMalloc(sizeof(xmlTextReader));
    if (ret == NULL) {
        xmlGenericError(xmlGenericErrorContext,
                "xmlNewTextReader : malloc failed\n");
        return(NULL);
    }
    memset(ret, 0, sizeof(xmlTextReader));
    ret->entNr = 0;
    ret->input = NULL;
    ret->mode = XML_TEXTREADER_MODE_INITIAL;
    ret->node = NULL;
    ret->curnode = NULL;
    ret->base = 0;
    ret->cur = 0;
    ret->allocs = XML_TEXTREADER_CTXT;
    ret->doc = doc;
    ret->state = XML_TEXTREADER_START;
    ret->dict = xmlDictCreate();
    return(ret);
}

/**
 * xmlReaderForDoc:
 * @cur:  a pointer to a zero terminated string
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Create an xmltextReader for an XML in-memory document.
 * The parsing flags @options are a combination of xmlParserOption.
 *
 * Returns the new reader or NULL in case of error.
 */
xmlTextReaderPtr
xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
                int options)
{
    int len;

    if (cur == NULL)
        return (NULL);
    len = xmlStrlen(cur);

    return (xmlReaderForMemory
            ((const char *) cur, len, URL, encoding, options));
}

/**
 * xmlReaderForFile:
 * @filename:  a file or URL
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * parse an XML file from the filesystem or the network.
 * The parsing flags @options are a combination of xmlParserOption.
 *
 * Returns the new reader or NULL in case of error.
 */
xmlTextReaderPtr
xmlReaderForFile(const char *filename, const char *encoding, int options)
{
    xmlTextReaderPtr reader;

    reader = xmlNewTextReaderFilename(filename);
    if (reader == NULL)
        return (NULL);
    xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
    return (reader);
}

/**
 * xmlReaderForMemory:
 * @buffer:  a pointer to a char array
 * @size:  the size of the array
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Create an xmltextReader for an XML in-memory document.
 * The parsing flags @options are a combination of xmlParserOption.
 *
 * Returns the new reader or NULL in case of error.
 */
xmlTextReaderPtr
xmlReaderForMemory(const char *buffer, int size, const char *URL,
                   const char *encoding, int options)
{
    xmlTextReaderPtr reader;
    xmlParserInputBufferPtr buf;

    buf = xmlParserInputBufferCreateStatic(buffer, size,
                                      XML_CHAR_ENCODING_NONE);
    if (buf == NULL) {
        return (NULL);
    }
    reader = xmlNewTextReader(buf, URL);
    if (reader == NULL) {
        xmlFreeParserInputBuffer(buf);
        return (NULL);
    }
    reader->allocs |= XML_TEXTREADER_INPUT;
    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
    return (reader);
}

/**
 * xmlReaderForFd:
 * @fd:  an open file descriptor
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Create an xmltextReader for an XML from a file descriptor.
 * The parsing flags @options are a combination of xmlParserOption.
 * NOTE that the file descriptor will not be closed when the
 *      reader is closed or reset.
 *
 * Returns the new reader or NULL in case of error.
 */
xmlTextReaderPtr
xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
{
    xmlTextReaderPtr reader;
    xmlParserInputBufferPtr input;

    if (fd < 0)
        return (NULL);

    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
    if (input == NULL)
        return (NULL);
    input->closecallback = NULL;
    reader = xmlNewTextReader(input, URL);
    if (reader == NULL) {
        xmlFreeParserInputBuffer(input);
        return (NULL);
    }
    reader->allocs |= XML_TEXTREADER_INPUT;
    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
    return (reader);
}

/**
 * xmlReaderForIO:
 * @ioread:  an I/O read function
 * @ioclose:  an I/O close function
 * @ioctx:  an I/O handler
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Create an xmltextReader for an XML document from I/O functions and source.
 * The parsing flags @options are a combination of xmlParserOption.
 *
 * Returns the new reader or NULL in case of error.
 */
xmlTextReaderPtr
xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
               void *ioctx, const char *URL, const char *encoding,
               int options)
{
    xmlTextReaderPtr reader;
    xmlParserInputBufferPtr input;

    if (ioread == NULL)
        return (NULL);

    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
                                         XML_CHAR_ENCODING_NONE);
    if (input == NULL)
        return (NULL);
    reader = xmlNewTextReader(input, URL);
    if (reader == NULL) {
        xmlFreeParserInputBuffer(input);
        return (NULL);
    }
    reader->allocs |= XML_TEXTREADER_INPUT;
    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
    return (reader);
}

/**
 * xmlReaderNewWalker:
 * @reader:  an XML reader
 * @doc:  a preparsed document
 *
 * Setup an xmltextReader to parse a preparsed XML document.
 * This reuses the existing @reader xmlTextReader.
 *
 * Returns 0 in case of success and -1 in case of error
 */
int
xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
{
    if (doc == NULL)
        return (-1);
    if (reader == NULL)
        return (-1);

    if (reader->input != NULL) {
        xmlFreeParserInputBuffer(reader->input);
    }
    if (reader->ctxt != NULL) {
        xmlCtxtReset(reader->ctxt);
    }

    reader->entNr = 0;
    reader->input = NULL;
    reader->mode = XML_TEXTREADER_MODE_INITIAL;
    reader->node = NULL;
    reader->curnode = NULL;
    reader->base = 0;
    reader->cur = 0;
    reader->allocs = XML_TEXTREADER_CTXT;
    reader->doc = doc;
    reader->state = XML_TEXTREADER_START;
    if (reader->dict == NULL) {
        if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
            reader->dict = reader->ctxt->dict;
        else
            reader->dict = xmlDictCreate();
    }
    return(0);
}

/**
 * xmlReaderNewDoc:
 * @reader:  an XML reader
 * @cur:  a pointer to a zero terminated string
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Setup an xmltextReader to parse an XML in-memory document.
 * The parsing flags @options are a combination of xmlParserOption.
 * This reuses the existing @reader xmlTextReader.
 *
 * Returns 0 in case of success and -1 in case of error
 */
int
xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
                const char *URL, const char *encoding, int options)
{

    int len;

    if (cur == NULL)
        return (-1);
    if (reader == NULL)
        return (-1);

    len = xmlStrlen(cur);
    return (xmlReaderNewMemory(reader, (const char *)cur, len,
                               URL, encoding, options));
}

/**
 * xmlReaderNewFile:
 * @reader:  an XML reader
 * @filename:  a file or URL
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * parse an XML file from the filesystem or the network.
 * The parsing flags @options are a combination of xmlParserOption.
 * This reuses the existing @reader xmlTextReader.
 *
 * Returns 0 in case of success and -1 in case of error
 */
int
xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
                 const char *encoding, int options)
{
    xmlParserInputBufferPtr input;

    if (filename == NULL)
        return (-1);
    if (reader == NULL)
        return (-1);

    input =
        xmlParserInputBufferCreateFilename(filename,
                                           XML_CHAR_ENCODING_NONE);
    if (input == NULL)
        return (-1);
    return (xmlTextReaderSetup(reader, input, filename, encoding, options));
}

/**
 * xmlReaderNewMemory:
 * @reader:  an XML reader
 * @buffer:  a pointer to a char array
 * @size:  the size of the array
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Setup an xmltextReader to parse an XML in-memory document.
 * The parsing flags @options are a combination of xmlParserOption.
 * This reuses the existing @reader xmlTextReader.
 *
 * Returns 0 in case of success and -1 in case of error
 */
int
xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
                   const char *URL, const char *encoding, int options)
{
    xmlParserInputBufferPtr input;

    if (reader == NULL)
        return (-1);
    if (buffer == NULL)
        return (-1);

    input = xmlParserInputBufferCreateStatic(buffer, size,
                                      XML_CHAR_ENCODING_NONE);
    if (input == NULL) {
        return (-1);
    }
    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
}

/**
 * xmlReaderNewFd:
 * @reader:  an XML reader
 * @fd:  an open file descriptor
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Setup an xmltextReader to parse an XML from a file descriptor.
 * NOTE that the file descriptor will not be closed when the
 *      reader is closed or reset.
 * The parsing flags @options are a combination of xmlParserOption.
 * This reuses the existing @reader xmlTextReader.
 *
 * Returns 0 in case of success and -1 in case of error
 */
int
xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
               const char *URL, const char *encoding, int options)
{
    xmlParserInputBufferPtr input;

    if (fd < 0)
        return (-1);
    if (reader == NULL)
        return (-1);

    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
    if (input == NULL)
        return (-1);
    input->closecallback = NULL;
    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
}

/**
 * xmlReaderNewIO:
 * @reader:  an XML reader
 * @ioread:  an I/O read function
 * @ioclose:  an I/O close function
 * @ioctx:  an I/O handler
 * @URL:  the base URL to use for the document
 * @encoding:  the document encoding, or NULL
 * @options:  a combination of xmlParserOption
 *
 * Setup an xmltextReader to parse an XML document from I/O functions
 * and source.
 * The parsing flags @options are a combination of xmlParserOption.
 * This reuses the existing @reader xmlTextReader.
 *
 * Returns 0 in case of success and -1 in case of error
 */
int
xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
               xmlInputCloseCallback ioclose, void *ioctx,
               const char *URL, const char *encoding, int options)
{
    xmlParserInputBufferPtr input;

    if (ioread == NULL)
        return (-1);
    if (reader == NULL)
        return (-1);

    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
                                         XML_CHAR_ENCODING_NONE);
    if (input == NULL)
        return (-1);
    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
}
/************************************************************************
 *                                                                      *
 *                      Utilities                                       *
 *                                                                      *
 ************************************************************************/
#ifdef NOT_USED_YET

/**
 * xmlBase64Decode:
 * @in:  the input buffer
 * @inlen:  the size of the input (in), the size read from it (out)
 * @to:  the output buffer
 * @tolen:  the size of the output (in), the size written to (out)
 *
 * Base64 decoder, reads from @in and save in @to
 * TODO: tell jody when this is actually exported
 *
 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
 *         2 if there wasn't enough space on the output or -1 in case of error.
 */
static int
xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
                unsigned char *to, unsigned long *tolen)
{
    unsigned long incur;        /* current index in in[] */

    unsigned long inblk;        /* last block index in in[] */

    unsigned long outcur;       /* current index in out[] */

    unsigned long inmax;        /* size of in[] */

    unsigned long outmax;       /* size of out[] */

    unsigned char cur;          /* the current value read from in[] */

    unsigned char intmp[4], outtmp[4];  /* temporary buffers for the convert */

    int nbintmp;                /* number of byte in intmp[] */

    int is_ignore;              /* cur should be ignored */

    int is_end = 0;             /* the end of the base64 was found */

    int retval = 1;

    int i;

    if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
        return (-1);

    incur = 0;
    inblk = 0;
    outcur = 0;
    inmax = *inlen;
    outmax = *tolen;
    nbintmp = 0;

    while (1) {
        if (incur >= inmax)
            break;
        cur = in[incur++];
        is_ignore = 0;
        if ((cur >= 'A') && (cur <= 'Z'))
            cur = cur - 'A';
        else if ((cur >= 'a') && (cur <= 'z'))
            cur = cur - 'a' + 26;
        else if ((cur >= '0') && (cur <= '9'))
            cur = cur - '0' + 52;
        else if (cur == '+')
            cur = 62;
        else if (cur == '/')
            cur = 63;
        else if (cur == '.')
            cur = 0;
        else if (cur == '=')    /*no op , end of the base64 stream */
            is_end = 1;
        else {
            is_ignore = 1;
            if (nbintmp == 0)
                inblk = incur;
        }

        if (!is_ignore) {
            int nbouttmp = 3;

            int is_break = 0;

            if (is_end) {
                if (nbintmp == 0)
                    break;
                if ((nbintmp == 1) || (nbintmp == 2))
                    nbouttmp = 1;
                else
                    nbouttmp = 2;
                nbintmp = 3;
                is_break = 1;
            }
            intmp[nbintmp++] = cur;
            /*
             * if intmp is full, push the 4byte sequence as a 3 byte
             * sequence out
             */
            if (nbintmp == 4) {
                nbintmp = 0;
                outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
                outtmp[1] =
                    ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
                outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
                if (outcur + 3 >= outmax) {
                    retval = 2;
                    break;
                }

                for (i = 0; i < nbouttmp; i++)
                    to[outcur++] = outtmp[i];
                inblk = incur;
            }

            if (is_break) {
                retval = 0;
                break;
            }
        }
    }

    *tolen = outcur;
    *inlen = inblk;
    return (retval);
}

/*
 * Test routine for the xmlBase64Decode function
 */
#if 0
int
main(int argc, char **argv)
{
    char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";

    char output[100];

    char output2[100];

    char output3[100];

    unsigned long inlen = strlen(input);

    unsigned long outlen = 100;

    int ret;

    unsigned long cons, tmp, tmp2, prod;

    /*
     * Direct
     */
    ret = xmlBase64Decode(input, &inlen, output, &outlen);

    output[outlen] = 0;
    printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen,
           outlen, output)indent: Standard input:179: Error:Unmatched #endif
;

    /*
     * output chunking
     */
    cons = 0;
    prod = 0;
    while (cons < inlen) {
        tmp = 5;
        tmp2 = inlen - cons;

        printf("%ld %ld\n", cons, prod);
        ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
        cons += tmp2;
        prod += tmp;
        printf("%ld %ld\n", cons, prod);
    }
    output2[outlen] = 0;
    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
           prod, output2);

    /*
     * input chunking
     */
    cons = 0;
    prod = 0;
    while (cons < inlen) {
        tmp = 100 - prod;
        tmp2 = inlen - cons;
        if (tmp2 > 5)
            tmp2 = 5;

        printf("%ld %ld\n", cons, prod);
        ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
        cons += tmp2;
        prod += tmp;
        printf("%ld %ld\n", cons, prod);
    }
    output3[outlen] = 0;
    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
           prod, output3);
    return (0);

}
#endif
#endif /* NOT_USED_YET */
#define bottom_xmlreader
#include "elfgcchack.h"
#endif /* LIBXML_READER_ENABLED */

/* [<][>][^][v][top][bottom][index][help] */