Home | History | Annotate | Download | only in libxml2
      1 /*
      2  * xmlreader.c: implements the xmlTextReader streaming node API
      3  *
      4  * NOTE:
      5  *   XmlTextReader.Normalization Property won't be supported, since
      6  *     it makes the parser non compliant to the XML recommendation
      7  *
      8  * See Copyright for the status of this software.
      9  *
     10  * daniel (at) veillard.com
     11  */
     12 
     13 /*
     14  * TODOs:
     15  *   - XML Schemas validation
     16  */
     17 #define IN_LIBXML
     18 #include "libxml.h"
     19 
     20 #ifdef LIBXML_READER_ENABLED
     21 #include <string.h> /* for memset() only ! */
     22 #include <stdarg.h>
     23 
     24 #ifdef HAVE_CTYPE_H
     25 #include <ctype.h>
     26 #endif
     27 #ifdef HAVE_STDLIB_H
     28 #include <stdlib.h>
     29 #endif
     30 
     31 #include <libxml/xmlmemory.h>
     32 #include <libxml/xmlIO.h>
     33 #include <libxml/xmlreader.h>
     34 #include <libxml/parserInternals.h>
     35 #ifdef LIBXML_SCHEMAS_ENABLED
     36 #include <libxml/relaxng.h>
     37 #include <libxml/xmlschemas.h>
     38 #endif
     39 #include <libxml/uri.h>
     40 #ifdef LIBXML_XINCLUDE_ENABLED
     41 #include <libxml/xinclude.h>
     42 #endif
     43 #ifdef LIBXML_PATTERN_ENABLED
     44 #include <libxml/pattern.h>
     45 #endif
     46 
     47 #include "buf.h"
     48 
     49 #define MAX_ERR_MSG_SIZE 64000
     50 
     51 /*
     52  * The following VA_COPY was coded following an example in
     53  * the Samba project.  It may not be sufficient for some
     54  * esoteric implementations of va_list but (hopefully) will
     55  * be sufficient for libxml2.
     56  */
     57 #ifndef VA_COPY
     58   #ifdef HAVE_VA_COPY
     59     #define VA_COPY(dest, src) va_copy(dest, src)
     60   #else
     61     #ifdef HAVE___VA_COPY
     62       #define VA_COPY(dest,src) __va_copy(dest, src)
     63     #else
     64       #ifndef VA_LIST_IS_ARRAY
     65         #define VA_COPY(dest,src) (dest) = (src)
     66       #else
     67         #include <string.h>
     68         #define VA_COPY(dest,src) memcpy((char *)(dest),(char *)(src),sizeof(va_list))
     69       #endif
     70     #endif
     71   #endif
     72 #endif
     73 
     74 /* #define DEBUG_CALLBACKS */
     75 /* #define DEBUG_READER */
     76 
     77 /**
     78  * TODO:
     79  *
     80  * macro to flag unimplemented blocks
     81  */
     82 #define TODO								\
     83     xmlGenericError(xmlGenericErrorContext,				\
     84 	    "Unimplemented block at %s:%d\n",				\
     85             __FILE__, __LINE__);
     86 
     87 #ifdef DEBUG_READER
     88 #define DUMP_READER xmlTextReaderDebug(reader);
     89 #else
     90 #define DUMP_READER
     91 #endif
     92 
     93 #define CHUNK_SIZE 512
     94 /************************************************************************
     95  *									*
     96  *	The parser: maps the Text Reader API on top of the existing	*
     97  *		parsing routines building a tree			*
     98  *									*
     99  ************************************************************************/
    100 
    101 #define XML_TEXTREADER_INPUT	1
    102 #define XML_TEXTREADER_CTXT	2
    103 
    104 typedef enum {
    105     XML_TEXTREADER_NONE = -1,
    106     XML_TEXTREADER_START= 0,
    107     XML_TEXTREADER_ELEMENT= 1,
    108     XML_TEXTREADER_END= 2,
    109     XML_TEXTREADER_EMPTY= 3,
    110     XML_TEXTREADER_BACKTRACK= 4,
    111     XML_TEXTREADER_DONE= 5,
    112     XML_TEXTREADER_ERROR= 6
    113 } xmlTextReaderState;
    114 
    115 typedef enum {
    116     XML_TEXTREADER_NOT_VALIDATE = 0,
    117     XML_TEXTREADER_VALIDATE_DTD = 1,
    118     XML_TEXTREADER_VALIDATE_RNG = 2,
    119     XML_TEXTREADER_VALIDATE_XSD = 4
    120 } xmlTextReaderValidate;
    121 
    122 struct _xmlTextReader {
    123     int				mode;	/* the parsing mode */
    124     xmlDocPtr			doc;    /* when walking an existing doc */
    125     xmlTextReaderValidate       validate;/* is there any validation */
    126     int				allocs;	/* what structure were deallocated */
    127     xmlTextReaderState		state;
    128     xmlParserCtxtPtr		ctxt;	/* the parser context */
    129     xmlSAXHandlerPtr		sax;	/* the parser SAX callbacks */
    130     xmlParserInputBufferPtr	input;	/* the input */
    131     startElementSAXFunc		startElement;/* initial SAX callbacks */
    132     endElementSAXFunc		endElement;  /* idem */
    133     startElementNsSAX2Func	startElementNs;/* idem */
    134     endElementNsSAX2Func	endElementNs;  /* idem */
    135     charactersSAXFunc		characters;
    136     cdataBlockSAXFunc		cdataBlock;
    137     unsigned int		base;	/* base of the segment in the input */
    138     unsigned int		cur;	/* current position in the input */
    139     xmlNodePtr			node;	/* current node */
    140     xmlNodePtr			curnode;/* current attribute node */
    141     int				depth;  /* depth of the current node */
    142     xmlNodePtr			faketext;/* fake xmlNs chld */
    143     int				preserve;/* preserve the resulting document */
    144     xmlBufPtr		        buffer; /* used to return const xmlChar * */
    145     xmlDictPtr			dict;	/* the context dictionnary */
    146 
    147     /* entity stack when traversing entities content */
    148     xmlNodePtr         ent;          /* Current Entity Ref Node */
    149     int                entNr;        /* Depth of the entities stack */
    150     int                entMax;       /* Max depth of the entities stack */
    151     xmlNodePtr        *entTab;       /* array of entities */
    152 
    153     /* error handling */
    154     xmlTextReaderErrorFunc errorFunc;    /* callback function */
    155     void                  *errorFuncArg; /* callback function user argument */
    156 
    157 #ifdef LIBXML_SCHEMAS_ENABLED
    158     /* Handling of RelaxNG validation */
    159     xmlRelaxNGPtr          rngSchemas;	/* The Relax NG schemas */
    160     xmlRelaxNGValidCtxtPtr rngValidCtxt;/* The Relax NG validation context */
    161     int                    rngPreserveCtxt; /* 1 if the context was provided by the user */
    162     int                    rngValidErrors;/* The number of errors detected */
    163     xmlNodePtr             rngFullNode;	/* the node if RNG not progressive */
    164     /* Handling of Schemas validation */
    165     xmlSchemaPtr          xsdSchemas;	/* The Schemas schemas */
    166     xmlSchemaValidCtxtPtr xsdValidCtxt;/* The Schemas validation context */
    167     int                   xsdPreserveCtxt; /* 1 if the context was provided by the user */
    168     int                   xsdValidErrors;/* The number of errors detected */
    169     xmlSchemaSAXPlugPtr   xsdPlug;	/* the schemas plug in SAX pipeline */
    170 #endif
    171 #ifdef LIBXML_XINCLUDE_ENABLED
    172     /* Handling of XInclude processing */
    173     int                xinclude;	/* is xinclude asked for */
    174     const xmlChar *    xinclude_name;	/* the xinclude name from dict */
    175     xmlXIncludeCtxtPtr xincctxt;	/* the xinclude context */
    176     int                in_xinclude;	/* counts for xinclude */
    177 #endif
    178 #ifdef LIBXML_PATTERN_ENABLED
    179     int                patternNr;       /* number of preserve patterns */
    180     int                patternMax;      /* max preserve patterns */
    181     xmlPatternPtr     *patternTab;      /* array of preserve patterns */
    182 #endif
    183     int                preserves;	/* level of preserves */
    184     int                parserFlags;	/* the set of options set */
    185     /* Structured error handling */
    186     xmlStructuredErrorFunc sErrorFunc;  /* callback function */
    187 };
    188 
    189 #define NODE_IS_EMPTY		0x1
    190 #define NODE_IS_PRESERVED	0x2
    191 #define NODE_IS_SPRESERVED	0x4
    192 
    193 /**
    194  * CONSTSTR:
    195  *
    196  * Macro used to return an interned string
    197  */
    198 #define CONSTSTR(str) xmlDictLookup(reader->dict, (str), -1)
    199 #define CONSTQSTR(p, str) xmlDictQLookup(reader->dict, (p), (str))
    200 
    201 static int xmlTextReaderReadTree(xmlTextReaderPtr reader);
    202 static int xmlTextReaderNextTree(xmlTextReaderPtr reader);
    203 
    204 /************************************************************************
    205  *									*
    206  *	Our own version of the freeing routines as we recycle nodes	*
    207  *									*
    208  ************************************************************************/
    209 /**
    210  * DICT_FREE:
    211  * @str:  a string
    212  *
    213  * Free a string if it is not owned by the "dict" dictionnary in the
    214  * current scope
    215  */
    216 #define DICT_FREE(str)						\
    217 	if ((str) && ((!dict) ||				\
    218 	    (xmlDictOwns(dict, (const xmlChar *)(str)) == 0)))	\
    219 	    xmlFree((char *)(str));
    220 
    221 static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
    222 static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur);
    223 
    224 /**
    225  * xmlFreeID:
    226  * @not:  A id
    227  *
    228  * Deallocate the memory used by an id definition
    229  */
    230 static void
    231 xmlFreeID(xmlIDPtr id) {
    232     xmlDictPtr dict = NULL;
    233 
    234     if (id == NULL) return;
    235 
    236     if (id->doc != NULL)
    237         dict = id->doc->dict;
    238 
    239     if (id->value != NULL)
    240 	DICT_FREE(id->value)
    241     xmlFree(id);
    242 }
    243 
    244 /**
    245  * xmlTextReaderRemoveID:
    246  * @doc:  the document
    247  * @attr:  the attribute
    248  *
    249  * Remove the given attribute from the ID table maintained internally.
    250  *
    251  * Returns -1 if the lookup failed and 0 otherwise
    252  */
    253 static int
    254 xmlTextReaderRemoveID(xmlDocPtr doc, xmlAttrPtr attr) {
    255     xmlIDTablePtr table;
    256     xmlIDPtr id;
    257     xmlChar *ID;
    258 
    259     if (doc == NULL) return(-1);
    260     if (attr == NULL) return(-1);
    261     table = (xmlIDTablePtr) doc->ids;
    262     if (table == NULL)
    263         return(-1);
    264 
    265     ID = xmlNodeListGetString(doc, attr->children, 1);
    266     if (ID == NULL)
    267 	return(-1);
    268     id = xmlHashLookup(table, ID);
    269     xmlFree(ID);
    270     if (id == NULL || id->attr != attr) {
    271 	return(-1);
    272     }
    273     id->name = attr->name;
    274     id->attr = NULL;
    275     return(0);
    276 }
    277 
    278 /**
    279  * xmlTextReaderFreeProp:
    280  * @reader:  the xmlTextReaderPtr used
    281  * @cur:  the node
    282  *
    283  * Free a node.
    284  */
    285 static void
    286 xmlTextReaderFreeProp(xmlTextReaderPtr reader, xmlAttrPtr cur) {
    287     xmlDictPtr dict;
    288 
    289     if ((reader != NULL) && (reader->ctxt != NULL))
    290 	dict = reader->ctxt->dict;
    291     else
    292         dict = NULL;
    293     if (cur == NULL) return;
    294 
    295     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    296 	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
    297 
    298     /* Check for ID removal -> leading to invalid references ! */
    299     if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
    300 	((cur->parent->doc->intSubset != NULL) ||
    301 	 (cur->parent->doc->extSubset != NULL))) {
    302         if (xmlIsID(cur->parent->doc, cur->parent, cur))
    303 	    xmlTextReaderRemoveID(cur->parent->doc, cur);
    304     }
    305     if (cur->children != NULL)
    306         xmlTextReaderFreeNodeList(reader, cur->children);
    307 
    308     DICT_FREE(cur->name);
    309     if ((reader != NULL) && (reader->ctxt != NULL) &&
    310         (reader->ctxt->freeAttrsNr < 100)) {
    311         cur->next = reader->ctxt->freeAttrs;
    312 	reader->ctxt->freeAttrs = cur;
    313 	reader->ctxt->freeAttrsNr++;
    314     } else {
    315 	xmlFree(cur);
    316     }
    317 }
    318 
    319 /**
    320  * xmlTextReaderFreePropList:
    321  * @reader:  the xmlTextReaderPtr used
    322  * @cur:  the first property in the list
    323  *
    324  * Free a property and all its siblings, all the children are freed too.
    325  */
    326 static void
    327 xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
    328     xmlAttrPtr next;
    329 
    330     while (cur != NULL) {
    331         next = cur->next;
    332         xmlTextReaderFreeProp(reader, cur);
    333 	cur = next;
    334     }
    335 }
    336 
    337 /**
    338  * xmlTextReaderFreeNodeList:
    339  * @reader:  the xmlTextReaderPtr used
    340  * @cur:  the first node in the list
    341  *
    342  * Free a node and all its siblings, this is a recursive behaviour, all
    343  * the children are freed too.
    344  */
    345 static void
    346 xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
    347     xmlNodePtr next;
    348     xmlDictPtr dict;
    349 
    350     if ((reader != NULL) && (reader->ctxt != NULL))
    351 	dict = reader->ctxt->dict;
    352     else
    353         dict = NULL;
    354     if (cur == NULL) return;
    355     if (cur->type == XML_NAMESPACE_DECL) {
    356 	xmlFreeNsList((xmlNsPtr) cur);
    357 	return;
    358     }
    359     if ((cur->type == XML_DOCUMENT_NODE) ||
    360 	(cur->type == XML_HTML_DOCUMENT_NODE)) {
    361 	xmlFreeDoc((xmlDocPtr) cur);
    362 	return;
    363     }
    364     while (cur != NULL) {
    365         next = cur->next;
    366 	/* unroll to speed up freeing the document */
    367 	if (cur->type != XML_DTD_NODE) {
    368 
    369 	    if ((cur->children != NULL) &&
    370 		(cur->type != XML_ENTITY_REF_NODE)) {
    371 		if (cur->children->parent == cur)
    372 		    xmlTextReaderFreeNodeList(reader, cur->children);
    373 		cur->children = NULL;
    374 	    }
    375 
    376 	    if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    377 		xmlDeregisterNodeDefaultValue(cur);
    378 
    379 	    if (((cur->type == XML_ELEMENT_NODE) ||
    380 		 (cur->type == XML_XINCLUDE_START) ||
    381 		 (cur->type == XML_XINCLUDE_END)) &&
    382 		(cur->properties != NULL))
    383 		xmlTextReaderFreePropList(reader, cur->properties);
    384 	    if ((cur->content != (xmlChar *) &(cur->properties)) &&
    385 	        (cur->type != XML_ELEMENT_NODE) &&
    386 		(cur->type != XML_XINCLUDE_START) &&
    387 		(cur->type != XML_XINCLUDE_END) &&
    388 		(cur->type != XML_ENTITY_REF_NODE)) {
    389 		DICT_FREE(cur->content);
    390 	    }
    391 	    if (((cur->type == XML_ELEMENT_NODE) ||
    392 	         (cur->type == XML_XINCLUDE_START) ||
    393 		 (cur->type == XML_XINCLUDE_END)) &&
    394 		(cur->nsDef != NULL))
    395 		xmlFreeNsList(cur->nsDef);
    396 
    397 	    /*
    398 	     * we don't free element names here they are interned now
    399 	     */
    400 	    if ((cur->type != XML_TEXT_NODE) &&
    401 		(cur->type != XML_COMMENT_NODE))
    402 		DICT_FREE(cur->name);
    403 	    if (((cur->type == XML_ELEMENT_NODE) ||
    404 		 (cur->type == XML_TEXT_NODE)) &&
    405 	        (reader != NULL) && (reader->ctxt != NULL) &&
    406 		(reader->ctxt->freeElemsNr < 100)) {
    407 	        cur->next = reader->ctxt->freeElems;
    408 		reader->ctxt->freeElems = cur;
    409 		reader->ctxt->freeElemsNr++;
    410 	    } else {
    411 		xmlFree(cur);
    412 	    }
    413 	}
    414 	cur = next;
    415     }
    416 }
    417 
    418 /**
    419  * xmlTextReaderFreeNode:
    420  * @reader:  the xmlTextReaderPtr used
    421  * @cur:  the node
    422  *
    423  * Free a node, this is a recursive behaviour, all the children are freed too.
    424  * This doesn't unlink the child from the list, use xmlUnlinkNode() first.
    425  */
    426 static void
    427 xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur) {
    428     xmlDictPtr dict;
    429 
    430     if ((reader != NULL) && (reader->ctxt != NULL))
    431 	dict = reader->ctxt->dict;
    432     else
    433         dict = NULL;
    434     if (cur->type == XML_DTD_NODE) {
    435 	xmlFreeDtd((xmlDtdPtr) cur);
    436 	return;
    437     }
    438     if (cur->type == XML_NAMESPACE_DECL) {
    439 	xmlFreeNs((xmlNsPtr) cur);
    440         return;
    441     }
    442     if (cur->type == XML_ATTRIBUTE_NODE) {
    443 	xmlTextReaderFreeProp(reader, (xmlAttrPtr) cur);
    444 	return;
    445     }
    446 
    447     if ((cur->children != NULL) &&
    448 	(cur->type != XML_ENTITY_REF_NODE)) {
    449 	if (cur->children->parent == cur)
    450 	    xmlTextReaderFreeNodeList(reader, cur->children);
    451 	cur->children = NULL;
    452     }
    453 
    454     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    455 	xmlDeregisterNodeDefaultValue(cur);
    456 
    457     if (((cur->type == XML_ELEMENT_NODE) ||
    458 	 (cur->type == XML_XINCLUDE_START) ||
    459 	 (cur->type == XML_XINCLUDE_END)) &&
    460 	(cur->properties != NULL))
    461 	xmlTextReaderFreePropList(reader, cur->properties);
    462     if ((cur->content != (xmlChar *) &(cur->properties)) &&
    463         (cur->type != XML_ELEMENT_NODE) &&
    464 	(cur->type != XML_XINCLUDE_START) &&
    465 	(cur->type != XML_XINCLUDE_END) &&
    466 	(cur->type != XML_ENTITY_REF_NODE)) {
    467 	DICT_FREE(cur->content);
    468     }
    469     if (((cur->type == XML_ELEMENT_NODE) ||
    470 	 (cur->type == XML_XINCLUDE_START) ||
    471 	 (cur->type == XML_XINCLUDE_END)) &&
    472 	(cur->nsDef != NULL))
    473 	xmlFreeNsList(cur->nsDef);
    474 
    475     /*
    476      * we don't free names here they are interned now
    477      */
    478     if ((cur->type != XML_TEXT_NODE) &&
    479         (cur->type != XML_COMMENT_NODE))
    480 	DICT_FREE(cur->name);
    481 
    482     if (((cur->type == XML_ELEMENT_NODE) ||
    483 	 (cur->type == XML_TEXT_NODE)) &&
    484 	(reader != NULL) && (reader->ctxt != NULL) &&
    485 	(reader->ctxt->freeElemsNr < 100)) {
    486 	cur->next = reader->ctxt->freeElems;
    487 	reader->ctxt->freeElems = cur;
    488 	reader->ctxt->freeElemsNr++;
    489     } else {
    490 	xmlFree(cur);
    491     }
    492 }
    493 
    494 /**
    495  * xmlTextReaderFreeIDTable:
    496  * @table:  An id table
    497  *
    498  * Deallocate the memory used by an ID hash table.
    499  */
    500 static void
    501 xmlTextReaderFreeIDTable(xmlIDTablePtr table) {
    502     xmlHashFree(table, (xmlHashDeallocator) xmlFreeID);
    503 }
    504 
    505 /**
    506  * xmlTextReaderFreeDoc:
    507  * @reader:  the xmlTextReaderPtr used
    508  * @cur:  pointer to the document
    509  *
    510  * Free up all the structures used by a document, tree included.
    511  */
    512 static void
    513 xmlTextReaderFreeDoc(xmlTextReaderPtr reader, xmlDocPtr cur) {
    514     xmlDtdPtr extSubset, intSubset;
    515 
    516     if (cur == NULL) return;
    517 
    518     if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
    519 	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
    520 
    521     /*
    522      * Do this before freeing the children list to avoid ID lookups
    523      */
    524     if (cur->ids != NULL) xmlTextReaderFreeIDTable((xmlIDTablePtr) cur->ids);
    525     cur->ids = NULL;
    526     if (cur->refs != NULL) xmlFreeRefTable((xmlRefTablePtr) cur->refs);
    527     cur->refs = NULL;
    528     extSubset = cur->extSubset;
    529     intSubset = cur->intSubset;
    530     if (intSubset == extSubset)
    531 	extSubset = NULL;
    532     if (extSubset != NULL) {
    533 	xmlUnlinkNode((xmlNodePtr) cur->extSubset);
    534 	cur->extSubset = NULL;
    535 	xmlFreeDtd(extSubset);
    536     }
    537     if (intSubset != NULL) {
    538 	xmlUnlinkNode((xmlNodePtr) cur->intSubset);
    539 	cur->intSubset = NULL;
    540 	xmlFreeDtd(intSubset);
    541     }
    542 
    543     if (cur->children != NULL) xmlTextReaderFreeNodeList(reader, cur->children);
    544 
    545     if (cur->version != NULL) xmlFree((char *) cur->version);
    546     if (cur->name != NULL) xmlFree((char *) cur->name);
    547     if (cur->encoding != NULL) xmlFree((char *) cur->encoding);
    548     if (cur->oldNs != NULL) xmlFreeNsList(cur->oldNs);
    549     if (cur->URL != NULL) xmlFree((char *) cur->URL);
    550     if (cur->dict != NULL) xmlDictFree(cur->dict);
    551 
    552     xmlFree(cur);
    553 }
    554 
    555 /************************************************************************
    556  *									*
    557  *			The reader core parser				*
    558  *									*
    559  ************************************************************************/
    560 #ifdef DEBUG_READER
    561 static void
    562 xmlTextReaderDebug(xmlTextReaderPtr reader) {
    563     if ((reader == NULL) || (reader->ctxt == NULL)) {
    564 	fprintf(stderr, "xmlTextReader NULL\n");
    565 	return;
    566     }
    567     fprintf(stderr, "xmlTextReader: state %d depth %d ",
    568 	    reader->state, reader->depth);
    569     if (reader->node == NULL) {
    570 	fprintf(stderr, "node = NULL\n");
    571     } else {
    572 	fprintf(stderr, "node %s\n", reader->node->name);
    573     }
    574     fprintf(stderr, "  input: base %d, cur %d, depth %d: ",
    575 	    reader->base, reader->cur, reader->ctxt->nodeNr);
    576     if (reader->input->buffer == NULL) {
    577 	fprintf(stderr, "buffer is NULL\n");
    578     } else {
    579 #ifdef LIBXML_DEBUG_ENABLED
    580 	xmlDebugDumpString(stderr,
    581 		&reader->input->buffer->content[reader->cur]);
    582 #endif
    583 	fprintf(stderr, "\n");
    584     }
    585 }
    586 #endif
    587 
    588 /**
    589  * xmlTextReaderEntPush:
    590  * @reader:  the xmlTextReaderPtr used
    591  * @value:  the entity reference node
    592  *
    593  * Pushes a new entity reference node on top of the entities stack
    594  *
    595  * Returns 0 in case of error, the index in the stack otherwise
    596  */
    597 static int
    598 xmlTextReaderEntPush(xmlTextReaderPtr reader, xmlNodePtr value)
    599 {
    600     if (reader->entMax <= 0) {
    601 	reader->entMax = 10;
    602 	reader->entTab = (xmlNodePtr *) xmlMalloc(reader->entMax *
    603 		                                  sizeof(reader->entTab[0]));
    604         if (reader->entTab == NULL) {
    605             xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
    606             return (0);
    607         }
    608     }
    609     if (reader->entNr >= reader->entMax) {
    610         reader->entMax *= 2;
    611         reader->entTab =
    612             (xmlNodePtr *) xmlRealloc(reader->entTab,
    613                                       reader->entMax *
    614                                       sizeof(reader->entTab[0]));
    615         if (reader->entTab == NULL) {
    616             xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
    617             return (0);
    618         }
    619     }
    620     reader->entTab[reader->entNr] = value;
    621     reader->ent = value;
    622     return (reader->entNr++);
    623 }
    624 
    625 /**
    626  * xmlTextReaderEntPop:
    627  * @reader:  the xmlTextReaderPtr used
    628  *
    629  * Pops the top element entity from the entities stack
    630  *
    631  * Returns the entity just removed
    632  */
    633 static xmlNodePtr
    634 xmlTextReaderEntPop(xmlTextReaderPtr reader)
    635 {
    636     xmlNodePtr ret;
    637 
    638     if (reader->entNr <= 0)
    639         return (NULL);
    640     reader->entNr--;
    641     if (reader->entNr > 0)
    642         reader->ent = reader->entTab[reader->entNr - 1];
    643     else
    644         reader->ent = NULL;
    645     ret = reader->entTab[reader->entNr];
    646     reader->entTab[reader->entNr] = NULL;
    647     return (ret);
    648 }
    649 
    650 /**
    651  * xmlTextReaderStartElement:
    652  * @ctx: the user data (XML parser context)
    653  * @fullname:  The element name, including namespace prefix
    654  * @atts:  An array of name/value attributes pairs, NULL terminated
    655  *
    656  * called when an opening tag has been processed.
    657  */
    658 static void
    659 xmlTextReaderStartElement(void *ctx, const xmlChar *fullname,
    660 	                  const xmlChar **atts) {
    661     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    662     xmlTextReaderPtr reader = ctxt->_private;
    663 
    664 #ifdef DEBUG_CALLBACKS
    665     printf("xmlTextReaderStartElement(%s)\n", fullname);
    666 #endif
    667     if ((reader != NULL) && (reader->startElement != NULL)) {
    668 	reader->startElement(ctx, fullname, atts);
    669 	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
    670 	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
    671 	    (ctxt->input->cur[1] == '>'))
    672 	    ctxt->node->extra = NODE_IS_EMPTY;
    673     }
    674     if (reader != NULL)
    675 	reader->state = XML_TEXTREADER_ELEMENT;
    676 }
    677 
    678 /**
    679  * xmlTextReaderEndElement:
    680  * @ctx: the user data (XML parser context)
    681  * @fullname:  The element name, including namespace prefix
    682  *
    683  * called when an ending tag has been processed.
    684  */
    685 static void
    686 xmlTextReaderEndElement(void *ctx, const xmlChar *fullname) {
    687     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    688     xmlTextReaderPtr reader = ctxt->_private;
    689 
    690 #ifdef DEBUG_CALLBACKS
    691     printf("xmlTextReaderEndElement(%s)\n", fullname);
    692 #endif
    693     if ((reader != NULL) && (reader->endElement != NULL)) {
    694 	reader->endElement(ctx, fullname);
    695     }
    696 }
    697 
    698 /**
    699  * xmlTextReaderStartElementNs:
    700  * @ctx: the user data (XML parser context)
    701  * @localname:  the local name of the element
    702  * @prefix:  the element namespace prefix if available
    703  * @URI:  the element namespace name if available
    704  * @nb_namespaces:  number of namespace definitions on that node
    705  * @namespaces:  pointer to the array of prefix/URI pairs namespace definitions
    706  * @nb_attributes:  the number of attributes on that node
    707  * nb_defaulted:  the number of defaulted attributes.
    708  * @attributes:  pointer to the array of (localname/prefix/URI/value/end)
    709  *               attribute values.
    710  *
    711  * called when an opening tag has been processed.
    712  */
    713 static void
    714 xmlTextReaderStartElementNs(void *ctx,
    715                       const xmlChar *localname,
    716 		      const xmlChar *prefix,
    717 		      const xmlChar *URI,
    718 		      int nb_namespaces,
    719 		      const xmlChar **namespaces,
    720 		      int nb_attributes,
    721 		      int nb_defaulted,
    722 		      const xmlChar **attributes)
    723 {
    724     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    725     xmlTextReaderPtr reader = ctxt->_private;
    726 
    727 #ifdef DEBUG_CALLBACKS
    728     printf("xmlTextReaderStartElementNs(%s)\n", localname);
    729 #endif
    730     if ((reader != NULL) && (reader->startElementNs != NULL)) {
    731 	reader->startElementNs(ctx, localname, prefix, URI, nb_namespaces,
    732 	                       namespaces, nb_attributes, nb_defaulted,
    733 			       attributes);
    734 	if ((ctxt->node != NULL) && (ctxt->input != NULL) &&
    735 	    (ctxt->input->cur != NULL) && (ctxt->input->cur[0] == '/') &&
    736 	    (ctxt->input->cur[1] == '>'))
    737 	    ctxt->node->extra = NODE_IS_EMPTY;
    738     }
    739     if (reader != NULL)
    740 	reader->state = XML_TEXTREADER_ELEMENT;
    741 }
    742 
    743 /**
    744  * xmlTextReaderEndElementNs:
    745  * @ctx: the user data (XML parser context)
    746  * @localname:  the local name of the element
    747  * @prefix:  the element namespace prefix if available
    748  * @URI:  the element namespace name if available
    749  *
    750  * called when an ending tag has been processed.
    751  */
    752 static void
    753 xmlTextReaderEndElementNs(void *ctx,
    754                           const xmlChar * localname,
    755                           const xmlChar * prefix,
    756 		          const xmlChar * URI)
    757 {
    758     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    759     xmlTextReaderPtr reader = ctxt->_private;
    760 
    761 #ifdef DEBUG_CALLBACKS
    762     printf("xmlTextReaderEndElementNs(%s)\n", localname);
    763 #endif
    764     if ((reader != NULL) && (reader->endElementNs != NULL)) {
    765 	reader->endElementNs(ctx, localname, prefix, URI);
    766     }
    767 }
    768 
    769 
    770 /**
    771  * xmlTextReaderCharacters:
    772  * @ctx: the user data (XML parser context)
    773  * @ch:  a xmlChar string
    774  * @len: the number of xmlChar
    775  *
    776  * receiving some chars from the parser.
    777  */
    778 static void
    779 xmlTextReaderCharacters(void *ctx, const xmlChar *ch, int len)
    780 {
    781     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    782     xmlTextReaderPtr reader = ctxt->_private;
    783 
    784 #ifdef DEBUG_CALLBACKS
    785     printf("xmlTextReaderCharacters()\n");
    786 #endif
    787     if ((reader != NULL) && (reader->characters != NULL)) {
    788 	reader->characters(ctx, ch, len);
    789     }
    790 }
    791 
    792 /**
    793  * xmlTextReaderCDataBlock:
    794  * @ctx: the user data (XML parser context)
    795  * @value:  The pcdata content
    796  * @len:  the block length
    797  *
    798  * called when a pcdata block has been parsed
    799  */
    800 static void
    801 xmlTextReaderCDataBlock(void *ctx, const xmlChar *ch, int len)
    802 {
    803     xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) ctx;
    804     xmlTextReaderPtr reader = ctxt->_private;
    805 
    806 #ifdef DEBUG_CALLBACKS
    807     printf("xmlTextReaderCDataBlock()\n");
    808 #endif
    809     if ((reader != NULL) && (reader->cdataBlock != NULL)) {
    810 	reader->cdataBlock(ctx, ch, len);
    811     }
    812 }
    813 
    814 /**
    815  * xmlTextReaderPushData:
    816  * @reader:  the xmlTextReaderPtr used
    817  *
    818  * Push data down the progressive parser until a significant callback
    819  * got raised.
    820  *
    821  * Returns -1 in case of failure, 0 otherwise
    822  */
    823 static int
    824 xmlTextReaderPushData(xmlTextReaderPtr reader) {
    825     xmlBufPtr inbuf;
    826     int val, s;
    827     xmlTextReaderState oldstate;
    828     int alloc;
    829 
    830     if ((reader->input == NULL) || (reader->input->buffer == NULL))
    831 	return(-1);
    832 
    833     oldstate = reader->state;
    834     reader->state = XML_TEXTREADER_NONE;
    835     inbuf = reader->input->buffer;
    836     alloc = xmlBufGetAllocationScheme(inbuf);
    837 
    838     while (reader->state == XML_TEXTREADER_NONE) {
    839 	if (xmlBufUse(inbuf) < reader->cur + CHUNK_SIZE) {
    840 	    /*
    841 	     * Refill the buffer unless we are at the end of the stream
    842 	     */
    843 	    if (reader->mode != XML_TEXTREADER_MODE_EOF) {
    844 		val = xmlParserInputBufferRead(reader->input, 4096);
    845 		if ((val == 0) &&
    846 		    (alloc == XML_BUFFER_ALLOC_IMMUTABLE)) {
    847 		    if (xmlBufUse(inbuf) == reader->cur) {
    848 			reader->mode = XML_TEXTREADER_MODE_EOF;
    849 			reader->state = oldstate;
    850 		    }
    851 		} else if (val < 0) {
    852 		    reader->mode = XML_TEXTREADER_MODE_EOF;
    853 		    reader->state = oldstate;
    854 		    if ((oldstate != XML_TEXTREADER_START) ||
    855 			(reader->ctxt->myDoc != NULL))
    856 			return(val);
    857 		} else if (val == 0) {
    858 		    /* mark the end of the stream and process the remains */
    859 		    reader->mode = XML_TEXTREADER_MODE_EOF;
    860 		    break;
    861 		}
    862 
    863 	    } else
    864 		break;
    865 	}
    866 	/*
    867 	 * parse by block of CHUNK_SIZE bytes, various tests show that
    868 	 * it's the best tradeoff at least on a 1.2GH Duron
    869 	 */
    870 	if (xmlBufUse(inbuf) >= reader->cur + CHUNK_SIZE) {
    871 	    val = xmlParseChunk(reader->ctxt,
    872                  (const char *) xmlBufContent(inbuf) + reader->cur,
    873                                 CHUNK_SIZE, 0);
    874 	    reader->cur += CHUNK_SIZE;
    875 	    if (val != 0)
    876 		reader->ctxt->wellFormed = 0;
    877 	    if (reader->ctxt->wellFormed == 0)
    878 		break;
    879 	} else {
    880 	    s = xmlBufUse(inbuf) - reader->cur;
    881 	    val = xmlParseChunk(reader->ctxt,
    882 		 (const char *) xmlBufContent(inbuf) + reader->cur,
    883 			        s, 0);
    884 	    reader->cur += s;
    885 	    if (val != 0)
    886 		reader->ctxt->wellFormed = 0;
    887 	    break;
    888 	}
    889     }
    890 
    891     /*
    892      * Discard the consumed input when needed and possible
    893      */
    894     if (reader->mode == XML_TEXTREADER_MODE_INTERACTIVE) {
    895         if (alloc != XML_BUFFER_ALLOC_IMMUTABLE) {
    896 	    if ((reader->cur >= 4096) &&
    897 		(xmlBufUse(inbuf) - reader->cur <= CHUNK_SIZE)) {
    898 		val = xmlBufShrink(inbuf, reader->cur);
    899 		if (val >= 0) {
    900 		    reader->cur -= val;
    901 		}
    902 	    }
    903 	}
    904     }
    905 
    906     /*
    907      * At the end of the stream signal that the work is done to the Push
    908      * parser.
    909      */
    910     else if (reader->mode == XML_TEXTREADER_MODE_EOF) {
    911 	if (reader->state != XML_TEXTREADER_DONE) {
    912 	    s = xmlBufUse(inbuf) - reader->cur;
    913 	    val = xmlParseChunk(reader->ctxt,
    914 		 (const char *) xmlBufContent(inbuf) + reader->cur,
    915 			        s, 1);
    916 	    reader->cur = xmlBufUse(inbuf);
    917 	    reader->state  = XML_TEXTREADER_DONE;
    918 	    if (val != 0) {
    919 	        if (reader->ctxt->wellFormed)
    920 		    reader->ctxt->wellFormed = 0;
    921 		else
    922 		    return(-1);
    923 	    }
    924 	}
    925     }
    926     reader->state = oldstate;
    927     if (reader->ctxt->wellFormed == 0) {
    928 	reader->mode = XML_TEXTREADER_MODE_EOF;
    929         return(-1);
    930     }
    931 
    932     return(0);
    933 }
    934 
    935 #ifdef LIBXML_REGEXP_ENABLED
    936 /**
    937  * xmlTextReaderValidatePush:
    938  * @reader:  the xmlTextReaderPtr used
    939  *
    940  * Push the current node for validation
    941  */
    942 static void
    943 xmlTextReaderValidatePush(xmlTextReaderPtr reader ATTRIBUTE_UNUSED) {
    944     xmlNodePtr node = reader->node;
    945 
    946 #ifdef LIBXML_VALID_ENABLED
    947     if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
    948         (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
    949 	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
    950 	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
    951 				    reader->ctxt->myDoc, node, node->name);
    952 	} else {
    953 	    /* TODO use the BuildQName interface */
    954 	    xmlChar *qname;
    955 
    956 	    qname = xmlStrdup(node->ns->prefix);
    957 	    qname = xmlStrcat(qname, BAD_CAST ":");
    958 	    qname = xmlStrcat(qname, node->name);
    959 	    reader->ctxt->valid &= xmlValidatePushElement(&reader->ctxt->vctxt,
    960 				    reader->ctxt->myDoc, node, qname);
    961 	    if (qname != NULL)
    962 		xmlFree(qname);
    963 	}
    964     }
    965 #endif /* LIBXML_VALID_ENABLED */
    966 #ifdef LIBXML_SCHEMAS_ENABLED
    967     if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
    968                (reader->rngValidCtxt != NULL)) {
    969 	int ret;
    970 
    971 	if (reader->rngFullNode != NULL) return;
    972 	ret = xmlRelaxNGValidatePushElement(reader->rngValidCtxt,
    973 	                                    reader->ctxt->myDoc,
    974 					    node);
    975 	if (ret == 0) {
    976 	    /*
    977 	     * this element requires a full tree
    978 	     */
    979 	    node = xmlTextReaderExpand(reader);
    980 	    if (node == NULL) {
    981 printf("Expand failed !\n");
    982 	        ret = -1;
    983 	    } else {
    984 		ret = xmlRelaxNGValidateFullElement(reader->rngValidCtxt,
    985 						    reader->ctxt->myDoc,
    986 						    node);
    987 		reader->rngFullNode = node;
    988 	    }
    989 	}
    990 	if (ret != 1)
    991 	    reader->rngValidErrors++;
    992     }
    993 #endif
    994 }
    995 
    996 /**
    997  * xmlTextReaderValidateCData:
    998  * @reader:  the xmlTextReaderPtr used
    999  * @data:  pointer to the CData
   1000  * @len:  length of the CData block in bytes.
   1001  *
   1002  * Push some CData for validation
   1003  */
   1004 static void
   1005 xmlTextReaderValidateCData(xmlTextReaderPtr reader,
   1006                            const xmlChar *data, int len) {
   1007 #ifdef LIBXML_VALID_ENABLED
   1008     if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
   1009         (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
   1010 	reader->ctxt->valid &= xmlValidatePushCData(&reader->ctxt->vctxt,
   1011 	                                            data, len);
   1012     }
   1013 #endif /* LIBXML_VALID_ENABLED */
   1014 #ifdef LIBXML_SCHEMAS_ENABLED
   1015     if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
   1016                (reader->rngValidCtxt != NULL)) {
   1017 	int ret;
   1018 
   1019 	if (reader->rngFullNode != NULL) return;
   1020 	ret = xmlRelaxNGValidatePushCData(reader->rngValidCtxt, data, len);
   1021 	if (ret != 1)
   1022 	    reader->rngValidErrors++;
   1023     }
   1024 #endif
   1025 }
   1026 
   1027 /**
   1028  * xmlTextReaderValidatePop:
   1029  * @reader:  the xmlTextReaderPtr used
   1030  *
   1031  * Pop the current node from validation
   1032  */
   1033 static void
   1034 xmlTextReaderValidatePop(xmlTextReaderPtr reader) {
   1035     xmlNodePtr node = reader->node;
   1036 
   1037 #ifdef LIBXML_VALID_ENABLED
   1038     if ((reader->validate == XML_TEXTREADER_VALIDATE_DTD) &&
   1039         (reader->ctxt != NULL) && (reader->ctxt->validate == 1)) {
   1040 	if ((node->ns == NULL) || (node->ns->prefix == NULL)) {
   1041 	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
   1042 				    reader->ctxt->myDoc, node, node->name);
   1043 	} else {
   1044 	    /* TODO use the BuildQName interface */
   1045 	    xmlChar *qname;
   1046 
   1047 	    qname = xmlStrdup(node->ns->prefix);
   1048 	    qname = xmlStrcat(qname, BAD_CAST ":");
   1049 	    qname = xmlStrcat(qname, node->name);
   1050 	    reader->ctxt->valid &= xmlValidatePopElement(&reader->ctxt->vctxt,
   1051 				    reader->ctxt->myDoc, node, qname);
   1052 	    if (qname != NULL)
   1053 		xmlFree(qname);
   1054 	}
   1055     }
   1056 #endif /* LIBXML_VALID_ENABLED */
   1057 #ifdef LIBXML_SCHEMAS_ENABLED
   1058     if ((reader->validate == XML_TEXTREADER_VALIDATE_RNG) &&
   1059                (reader->rngValidCtxt != NULL)) {
   1060 	int ret;
   1061 
   1062 	if (reader->rngFullNode != NULL) {
   1063 	    if (node == reader->rngFullNode)
   1064 	        reader->rngFullNode = NULL;
   1065 	    return;
   1066 	}
   1067 	ret = xmlRelaxNGValidatePopElement(reader->rngValidCtxt,
   1068 	                                   reader->ctxt->myDoc,
   1069 					   node);
   1070 	if (ret != 1)
   1071 	    reader->rngValidErrors++;
   1072     }
   1073 #endif
   1074 }
   1075 
   1076 /**
   1077  * xmlTextReaderValidateEntity:
   1078  * @reader:  the xmlTextReaderPtr used
   1079  *
   1080  * Handle the validation when an entity reference is encountered and
   1081  * entity substitution is not activated. As a result the parser interface
   1082  * must walk through the entity and do the validation calls
   1083  */
   1084 static void
   1085 xmlTextReaderValidateEntity(xmlTextReaderPtr reader) {
   1086     xmlNodePtr oldnode = reader->node;
   1087     xmlNodePtr node = reader->node;
   1088     xmlParserCtxtPtr ctxt = reader->ctxt;
   1089 
   1090     do {
   1091 	if (node->type == XML_ENTITY_REF_NODE) {
   1092 	    /*
   1093 	     * Case where the underlying tree is not availble, lookup the entity
   1094 	     * and walk it.
   1095 	     */
   1096 	    if ((node->children == NULL) && (ctxt->sax != NULL) &&
   1097 		(ctxt->sax->getEntity != NULL)) {
   1098 		node->children = (xmlNodePtr)
   1099 		    ctxt->sax->getEntity(ctxt, node->name);
   1100 	    }
   1101 
   1102 	    if ((node->children != NULL) &&
   1103 		(node->children->type == XML_ENTITY_DECL) &&
   1104 		(node->children->children != NULL)) {
   1105 		xmlTextReaderEntPush(reader, node);
   1106 		node = node->children->children;
   1107 		continue;
   1108 	    } else {
   1109 		/*
   1110 		 * The error has probably be raised already.
   1111 		 */
   1112 		if (node == oldnode)
   1113 		    break;
   1114 		node = node->next;
   1115 	    }
   1116 #ifdef LIBXML_REGEXP_ENABLED
   1117 	} else if (node->type == XML_ELEMENT_NODE) {
   1118 	    reader->node = node;
   1119 	    xmlTextReaderValidatePush(reader);
   1120 	} else if ((node->type == XML_TEXT_NODE) ||
   1121 		   (node->type == XML_CDATA_SECTION_NODE)) {
   1122             xmlTextReaderValidateCData(reader, node->content,
   1123 	                               xmlStrlen(node->content));
   1124 #endif
   1125 	}
   1126 
   1127 	/*
   1128 	 * go to next node
   1129 	 */
   1130 	if (node->children != NULL) {
   1131 	    node = node->children;
   1132 	    continue;
   1133 	} else if (node->type == XML_ELEMENT_NODE) {
   1134 	    xmlTextReaderValidatePop(reader);
   1135 	}
   1136 	if (node->next != NULL) {
   1137 	    node = node->next;
   1138 	    continue;
   1139 	}
   1140 	do {
   1141 	    node = node->parent;
   1142 	    if (node->type == XML_ELEMENT_NODE) {
   1143 	        xmlNodePtr tmp;
   1144 		if (reader->entNr == 0) {
   1145 		    while ((tmp = node->last) != NULL) {
   1146 			if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
   1147 			    xmlUnlinkNode(tmp);
   1148 			    xmlTextReaderFreeNode(reader, tmp);
   1149 			} else
   1150 			    break;
   1151 		    }
   1152 		}
   1153 		reader->node = node;
   1154 		xmlTextReaderValidatePop(reader);
   1155 	    }
   1156 	    if ((node->type == XML_ENTITY_DECL) &&
   1157 		(reader->ent != NULL) && (reader->ent->children == node)) {
   1158 		node = xmlTextReaderEntPop(reader);
   1159 	    }
   1160 	    if (node == oldnode)
   1161 		break;
   1162 	    if (node->next != NULL) {
   1163 		node = node->next;
   1164 		break;
   1165 	    }
   1166 	} while ((node != NULL) && (node != oldnode));
   1167     } while ((node != NULL) && (node != oldnode));
   1168     reader->node = oldnode;
   1169 }
   1170 #endif /* LIBXML_REGEXP_ENABLED */
   1171 
   1172 
   1173 /**
   1174  * xmlTextReaderGetSuccessor:
   1175  * @cur:  the current node
   1176  *
   1177  * Get the successor of a node if available.
   1178  *
   1179  * Returns the successor node or NULL
   1180  */
   1181 static xmlNodePtr
   1182 xmlTextReaderGetSuccessor(xmlNodePtr cur) {
   1183     if (cur == NULL) return(NULL) ; /* ERROR */
   1184     if (cur->next != NULL) return(cur->next) ;
   1185     do {
   1186         cur = cur->parent;
   1187         if (cur == NULL) break;
   1188         if (cur->next != NULL) return(cur->next);
   1189     } while (cur != NULL);
   1190     return(cur);
   1191 }
   1192 
   1193 /**
   1194  * xmlTextReaderDoExpand:
   1195  * @reader:  the xmlTextReaderPtr used
   1196  *
   1197  * Makes sure that the current node is fully read as well as all its
   1198  * descendant. It means the full DOM subtree must be available at the
   1199  * end of the call.
   1200  *
   1201  * Returns 1 if the node was expanded successfully, 0 if there is no more
   1202  *          nodes to read, or -1 in case of error
   1203  */
   1204 static int
   1205 xmlTextReaderDoExpand(xmlTextReaderPtr reader) {
   1206     int val;
   1207 
   1208     if ((reader == NULL) || (reader->node == NULL) || (reader->ctxt == NULL))
   1209         return(-1);
   1210     do {
   1211 	if (reader->ctxt->instate == XML_PARSER_EOF) return(1);
   1212 
   1213         if (xmlTextReaderGetSuccessor(reader->node) != NULL)
   1214 	    return(1);
   1215 	if (reader->ctxt->nodeNr < reader->depth)
   1216 	    return(1);
   1217 	if (reader->mode == XML_TEXTREADER_MODE_EOF)
   1218 	    return(1);
   1219 	val = xmlTextReaderPushData(reader);
   1220 	if (val < 0){
   1221 	    reader->mode = XML_TEXTREADER_MODE_ERROR;
   1222 	    return(-1);
   1223 	}
   1224     } while(reader->mode != XML_TEXTREADER_MODE_EOF);
   1225     return(1);
   1226 }
   1227 
   1228 /**
   1229  * xmlTextReaderCollectSiblings:
   1230  * @node:    the first child
   1231  *
   1232  *  Traverse depth-first through all sibling nodes and their children
   1233  *  nodes and concatenate their content. This is an auxiliary function
   1234  *  to xmlTextReaderReadString.
   1235  *
   1236  *  Returns a string containing the content, or NULL in case of error.
   1237  */
   1238 static xmlChar *
   1239 xmlTextReaderCollectSiblings(xmlNodePtr node)
   1240 {
   1241     xmlBufferPtr buffer;
   1242     xmlChar *ret;
   1243 
   1244     if ((node == NULL) || (node->type == XML_NAMESPACE_DECL))
   1245         return(NULL);
   1246 
   1247     buffer = xmlBufferCreate();
   1248     if (buffer == NULL)
   1249        return NULL;
   1250 
   1251     for ( ; node != NULL; node = node->next) {
   1252        switch (node->type) {
   1253        case XML_TEXT_NODE:
   1254        case XML_CDATA_SECTION_NODE:
   1255            xmlBufferCat(buffer, node->content);
   1256            break;
   1257        case XML_ELEMENT_NODE: {
   1258            xmlChar *tmp;
   1259 
   1260 	   tmp = xmlTextReaderCollectSiblings(node->children);
   1261            xmlBufferCat(buffer, tmp);
   1262 	   xmlFree(tmp);
   1263 	   break;
   1264        }
   1265        default:
   1266            break;
   1267        }
   1268     }
   1269     ret = buffer->content;
   1270     buffer->content = NULL;
   1271     xmlBufferFree(buffer);
   1272     return(ret);
   1273 }
   1274 
   1275 /**
   1276  * xmlTextReaderRead:
   1277  * @reader:  the xmlTextReaderPtr used
   1278  *
   1279  *  Moves the position of the current instance to the next node in
   1280  *  the stream, exposing its properties.
   1281  *
   1282  *  Returns 1 if the node was read successfully, 0 if there is no more
   1283  *          nodes to read, or -1 in case of error
   1284  */
   1285 int
   1286 xmlTextReaderRead(xmlTextReaderPtr reader) {
   1287     int val, olddepth = 0;
   1288     xmlTextReaderState oldstate = XML_TEXTREADER_START;
   1289     xmlNodePtr oldnode = NULL;
   1290 
   1291 
   1292     if (reader == NULL)
   1293 	return(-1);
   1294     reader->curnode = NULL;
   1295     if (reader->doc != NULL)
   1296         return(xmlTextReaderReadTree(reader));
   1297     if (reader->ctxt == NULL)
   1298 	return(-1);
   1299 
   1300 #ifdef DEBUG_READER
   1301     fprintf(stderr, "\nREAD ");
   1302     DUMP_READER
   1303 #endif
   1304     if (reader->mode == XML_TEXTREADER_MODE_INITIAL) {
   1305 	reader->mode = XML_TEXTREADER_MODE_INTERACTIVE;
   1306 	/*
   1307 	 * Initial state
   1308 	 */
   1309 	do {
   1310 	    val = xmlTextReaderPushData(reader);
   1311 		if (val < 0){
   1312 			reader->mode = XML_TEXTREADER_MODE_ERROR;
   1313 			reader->state = XML_TEXTREADER_ERROR;
   1314 		return(-1);
   1315 		}
   1316 	} while ((reader->ctxt->node == NULL) &&
   1317 		 ((reader->mode != XML_TEXTREADER_MODE_EOF) &&
   1318 		  (reader->state != XML_TEXTREADER_DONE)));
   1319 	if (reader->ctxt->node == NULL) {
   1320 	    if (reader->ctxt->myDoc != NULL) {
   1321 		reader->node = reader->ctxt->myDoc->children;
   1322 	    }
   1323 	    if (reader->node == NULL){
   1324 			reader->mode = XML_TEXTREADER_MODE_ERROR;
   1325 			reader->state = XML_TEXTREADER_ERROR;
   1326 		return(-1);
   1327 		}
   1328 	    reader->state = XML_TEXTREADER_ELEMENT;
   1329 	} else {
   1330 	    if (reader->ctxt->myDoc != NULL) {
   1331 		reader->node = reader->ctxt->myDoc->children;
   1332 	    }
   1333 	    if (reader->node == NULL)
   1334 		reader->node = reader->ctxt->nodeTab[0];
   1335 	    reader->state = XML_TEXTREADER_ELEMENT;
   1336 	}
   1337 	reader->depth = 0;
   1338 	reader->ctxt->parseMode = XML_PARSE_READER;
   1339 	goto node_found;
   1340     }
   1341     oldstate = reader->state;
   1342     olddepth = reader->ctxt->nodeNr;
   1343     oldnode = reader->node;
   1344 
   1345 get_next_node:
   1346     if (reader->node == NULL) {
   1347 	if (reader->mode == XML_TEXTREADER_MODE_EOF)
   1348 	    return(0);
   1349 	else
   1350 	    return(-1);
   1351     }
   1352 
   1353     /*
   1354      * If we are not backtracking on ancestors or examined nodes,
   1355      * that the parser didn't finished or that we arent at the end
   1356      * of stream, continue processing.
   1357      */
   1358     while ((reader->node != NULL) && (reader->node->next == NULL) &&
   1359 	   (reader->ctxt->nodeNr == olddepth) &&
   1360            ((oldstate == XML_TEXTREADER_BACKTRACK) ||
   1361             (reader->node->children == NULL) ||
   1362 	    (reader->node->type == XML_ENTITY_REF_NODE) ||
   1363 	    ((reader->node->children != NULL) &&
   1364 	     (reader->node->children->type == XML_TEXT_NODE) &&
   1365 	     (reader->node->children->next == NULL)) ||
   1366 	    (reader->node->type == XML_DTD_NODE) ||
   1367 	    (reader->node->type == XML_DOCUMENT_NODE) ||
   1368 	    (reader->node->type == XML_HTML_DOCUMENT_NODE)) &&
   1369 	   ((reader->ctxt->node == NULL) ||
   1370 	    (reader->ctxt->node == reader->node) ||
   1371 	    (reader->ctxt->node == reader->node->parent)) &&
   1372 	   (reader->ctxt->instate != XML_PARSER_EOF)) {
   1373 	val = xmlTextReaderPushData(reader);
   1374 	if (val < 0){
   1375 		reader->mode = XML_TEXTREADER_MODE_ERROR;
   1376 		reader->state = XML_TEXTREADER_ERROR;
   1377 	    return(-1);
   1378 	}
   1379 	if (reader->node == NULL)
   1380 	    goto node_end;
   1381     }
   1382     if (oldstate != XML_TEXTREADER_BACKTRACK) {
   1383 	if ((reader->node->children != NULL) &&
   1384 	    (reader->node->type != XML_ENTITY_REF_NODE) &&
   1385 	    (reader->node->type != XML_XINCLUDE_START) &&
   1386 	    (reader->node->type != XML_DTD_NODE)) {
   1387 	    reader->node = reader->node->children;
   1388 	    reader->depth++;
   1389 	    reader->state = XML_TEXTREADER_ELEMENT;
   1390 	    goto node_found;
   1391 	}
   1392     }
   1393     if (reader->node->next != NULL) {
   1394 	if ((oldstate == XML_TEXTREADER_ELEMENT) &&
   1395             (reader->node->type == XML_ELEMENT_NODE) &&
   1396 	    (reader->node->children == NULL) &&
   1397 	    ((reader->node->extra & NODE_IS_EMPTY) == 0)
   1398 #ifdef LIBXML_XINCLUDE_ENABLED
   1399 	    && (reader->in_xinclude <= 0)
   1400 #endif
   1401 	    ) {
   1402 	    reader->state = XML_TEXTREADER_END;
   1403 	    goto node_found;
   1404 	}
   1405 #ifdef LIBXML_REGEXP_ENABLED
   1406 	if ((reader->validate) &&
   1407 	    (reader->node->type == XML_ELEMENT_NODE))
   1408 	    xmlTextReaderValidatePop(reader);
   1409 #endif /* LIBXML_REGEXP_ENABLED */
   1410         if ((reader->preserves > 0) &&
   1411 	    (reader->node->extra & NODE_IS_SPRESERVED))
   1412 	    reader->preserves--;
   1413 	reader->node = reader->node->next;
   1414 	reader->state = XML_TEXTREADER_ELEMENT;
   1415 
   1416 	/*
   1417 	 * Cleanup of the old node
   1418 	 */
   1419 	if ((reader->preserves == 0) &&
   1420 #ifdef LIBXML_XINCLUDE_ENABLED
   1421 	    (reader->in_xinclude == 0) &&
   1422 #endif
   1423 	    (reader->entNr == 0) &&
   1424 	    (reader->node->prev != NULL) &&
   1425             (reader->node->prev->type != XML_DTD_NODE)) {
   1426 	    xmlNodePtr tmp = reader->node->prev;
   1427 	    if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
   1428 		xmlUnlinkNode(tmp);
   1429 		xmlTextReaderFreeNode(reader, tmp);
   1430 	    }
   1431 	}
   1432 
   1433 	goto node_found;
   1434     }
   1435     if ((oldstate == XML_TEXTREADER_ELEMENT) &&
   1436 	(reader->node->type == XML_ELEMENT_NODE) &&
   1437 	(reader->node->children == NULL) &&
   1438 	((reader->node->extra & NODE_IS_EMPTY) == 0)) {;
   1439 	reader->state = XML_TEXTREADER_END;
   1440 	goto node_found;
   1441     }
   1442 #ifdef LIBXML_REGEXP_ENABLED
   1443     if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && (reader->node->type == XML_ELEMENT_NODE))
   1444 	xmlTextReaderValidatePop(reader);
   1445 #endif /* LIBXML_REGEXP_ENABLED */
   1446     if ((reader->preserves > 0) &&
   1447 	(reader->node->extra & NODE_IS_SPRESERVED))
   1448 	reader->preserves--;
   1449     reader->node = reader->node->parent;
   1450     if ((reader->node == NULL) ||
   1451 	(reader->node->type == XML_DOCUMENT_NODE) ||
   1452 #ifdef LIBXML_DOCB_ENABLED
   1453 	(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
   1454 #endif
   1455 	(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
   1456 	if (reader->mode != XML_TEXTREADER_MODE_EOF) {
   1457 	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
   1458 	    reader->state = XML_TEXTREADER_DONE;
   1459 	    if (val != 0)
   1460 	        return(-1);
   1461 	}
   1462 	reader->node = NULL;
   1463 	reader->depth = -1;
   1464 
   1465 	/*
   1466 	 * Cleanup of the old node
   1467 	 */
   1468 	if ((oldnode != NULL) && (reader->preserves == 0) &&
   1469 #ifdef LIBXML_XINCLUDE_ENABLED
   1470 	    (reader->in_xinclude == 0) &&
   1471 #endif
   1472 	    (reader->entNr == 0) &&
   1473 	    (oldnode->type != XML_DTD_NODE) &&
   1474 	    ((oldnode->extra & NODE_IS_PRESERVED) == 0)) {
   1475 	    xmlUnlinkNode(oldnode);
   1476 	    xmlTextReaderFreeNode(reader, oldnode);
   1477 	}
   1478 
   1479 	goto node_end;
   1480     }
   1481     if ((reader->preserves == 0) &&
   1482 #ifdef LIBXML_XINCLUDE_ENABLED
   1483         (reader->in_xinclude == 0) &&
   1484 #endif
   1485 	(reader->entNr == 0) &&
   1486         (reader->node->last != NULL) &&
   1487         ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) {
   1488 	xmlNodePtr tmp = reader->node->last;
   1489 	xmlUnlinkNode(tmp);
   1490 	xmlTextReaderFreeNode(reader, tmp);
   1491     }
   1492     reader->depth--;
   1493     reader->state = XML_TEXTREADER_BACKTRACK;
   1494 
   1495 node_found:
   1496     DUMP_READER
   1497 
   1498     /*
   1499      * If we are in the middle of a piece of CDATA make sure it's finished
   1500      */
   1501     if ((reader->node != NULL) &&
   1502         (reader->node->next == NULL) &&
   1503         ((reader->node->type == XML_TEXT_NODE) ||
   1504 	 (reader->node->type == XML_CDATA_SECTION_NODE))) {
   1505             if (xmlTextReaderExpand(reader) == NULL)
   1506 	        return -1;
   1507     }
   1508 
   1509 #ifdef LIBXML_XINCLUDE_ENABLED
   1510     /*
   1511      * Handle XInclude if asked for
   1512      */
   1513     if ((reader->xinclude) && (reader->node != NULL) &&
   1514 	(reader->node->type == XML_ELEMENT_NODE) &&
   1515 	(reader->node->ns != NULL) &&
   1516 	((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
   1517 	 (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
   1518 	if (reader->xincctxt == NULL) {
   1519 	    reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
   1520 	    xmlXIncludeSetFlags(reader->xincctxt,
   1521 	                        reader->parserFlags & (~XML_PARSE_NOXINCNODE));
   1522 	}
   1523 	/*
   1524 	 * expand that node and process it
   1525 	 */
   1526 	if (xmlTextReaderExpand(reader) == NULL)
   1527 	    return -1;
   1528 	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
   1529     }
   1530     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
   1531         reader->in_xinclude++;
   1532 	goto get_next_node;
   1533     }
   1534     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) {
   1535         reader->in_xinclude--;
   1536 	goto get_next_node;
   1537     }
   1538 #endif
   1539     /*
   1540      * Handle entities enter and exit when in entity replacement mode
   1541      */
   1542     if ((reader->node != NULL) &&
   1543 	(reader->node->type == XML_ENTITY_REF_NODE) &&
   1544 	(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
   1545 	/*
   1546 	 * Case where the underlying tree is not availble, lookup the entity
   1547 	 * and walk it.
   1548 	 */
   1549 	if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
   1550 	    (reader->ctxt->sax->getEntity != NULL)) {
   1551 	    reader->node->children = (xmlNodePtr)
   1552 		reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
   1553 	}
   1554 
   1555 	if ((reader->node->children != NULL) &&
   1556 	    (reader->node->children->type == XML_ENTITY_DECL) &&
   1557 	    (reader->node->children->children != NULL)) {
   1558 	    xmlTextReaderEntPush(reader, reader->node);
   1559 	    reader->node = reader->node->children->children;
   1560 	}
   1561 #ifdef LIBXML_REGEXP_ENABLED
   1562     } else if ((reader->node != NULL) &&
   1563 	       (reader->node->type == XML_ENTITY_REF_NODE) &&
   1564 	       (reader->ctxt != NULL) && (reader->validate)) {
   1565 	xmlTextReaderValidateEntity(reader);
   1566 #endif /* LIBXML_REGEXP_ENABLED */
   1567     }
   1568     if ((reader->node != NULL) &&
   1569 	(reader->node->type == XML_ENTITY_DECL) &&
   1570 	(reader->ent != NULL) && (reader->ent->children == reader->node)) {
   1571 	reader->node = xmlTextReaderEntPop(reader);
   1572 	reader->depth++;
   1573         goto get_next_node;
   1574     }
   1575 #ifdef LIBXML_REGEXP_ENABLED
   1576     if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && (reader->node != NULL)) {
   1577 	xmlNodePtr node = reader->node;
   1578 
   1579 	if ((node->type == XML_ELEMENT_NODE) &&
   1580             ((reader->state != XML_TEXTREADER_END) &&
   1581 	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
   1582 	    xmlTextReaderValidatePush(reader);
   1583 	} else if ((node->type == XML_TEXT_NODE) ||
   1584 		   (node->type == XML_CDATA_SECTION_NODE)) {
   1585             xmlTextReaderValidateCData(reader, node->content,
   1586 	                               xmlStrlen(node->content));
   1587 	}
   1588     }
   1589 #endif /* LIBXML_REGEXP_ENABLED */
   1590 #ifdef LIBXML_PATTERN_ENABLED
   1591     if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
   1592         (reader->state != XML_TEXTREADER_BACKTRACK)) {
   1593         int i;
   1594 	for (i = 0;i < reader->patternNr;i++) {
   1595 	     if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
   1596 	         xmlTextReaderPreserve(reader);
   1597 		 break;
   1598              }
   1599 	}
   1600     }
   1601 #endif /* LIBXML_PATTERN_ENABLED */
   1602 #ifdef LIBXML_SCHEMAS_ENABLED
   1603     if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) &&
   1604         (reader->xsdValidErrors == 0) &&
   1605 	(reader->xsdValidCtxt != NULL)) {
   1606 	reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt);
   1607     }
   1608 #endif /* LIBXML_PATTERN_ENABLED */
   1609     return(1);
   1610 node_end:
   1611     reader->state = XML_TEXTREADER_DONE;
   1612     return(0);
   1613 }
   1614 
   1615 /**
   1616  * xmlTextReaderReadState:
   1617  * @reader:  the xmlTextReaderPtr used
   1618  *
   1619  * Gets the read state of the reader.
   1620  *
   1621  * Returns the state value, or -1 in case of error
   1622  */
   1623 int
   1624 xmlTextReaderReadState(xmlTextReaderPtr reader) {
   1625     if (reader == NULL)
   1626 	return(-1);
   1627     return(reader->mode);
   1628 }
   1629 
   1630 /**
   1631  * xmlTextReaderExpand:
   1632  * @reader:  the xmlTextReaderPtr used
   1633  *
   1634  * Reads the contents of the current node and the full subtree. It then makes
   1635  * the subtree available until the next xmlTextReaderRead() call
   1636  *
   1637  * Returns a node pointer valid until the next xmlTextReaderRead() call
   1638  *         or NULL in case of error.
   1639  */
   1640 xmlNodePtr
   1641 xmlTextReaderExpand(xmlTextReaderPtr reader) {
   1642     if ((reader == NULL) || (reader->node == NULL))
   1643         return(NULL);
   1644     if (reader->doc != NULL)
   1645         return(reader->node);
   1646     if (reader->ctxt == NULL)
   1647         return(NULL);
   1648     if (xmlTextReaderDoExpand(reader) < 0)
   1649         return(NULL);
   1650     return(reader->node);
   1651 }
   1652 
   1653 /**
   1654  * xmlTextReaderNext:
   1655  * @reader:  the xmlTextReaderPtr used
   1656  *
   1657  * Skip to the node following the current one in document order while
   1658  * avoiding the subtree if any.
   1659  *
   1660  * Returns 1 if the node was read successfully, 0 if there is no more
   1661  *          nodes to read, or -1 in case of error
   1662  */
   1663 int
   1664 xmlTextReaderNext(xmlTextReaderPtr reader) {
   1665     int ret;
   1666     xmlNodePtr cur;
   1667 
   1668     if (reader == NULL)
   1669 	return(-1);
   1670     if (reader->doc != NULL)
   1671         return(xmlTextReaderNextTree(reader));
   1672     cur = reader->node;
   1673     if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
   1674         return(xmlTextReaderRead(reader));
   1675     if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK)
   1676         return(xmlTextReaderRead(reader));
   1677     if (cur->extra & NODE_IS_EMPTY)
   1678         return(xmlTextReaderRead(reader));
   1679     do {
   1680         ret = xmlTextReaderRead(reader);
   1681 	if (ret != 1)
   1682 	    return(ret);
   1683     } while (reader->node != cur);
   1684     return(xmlTextReaderRead(reader));
   1685 }
   1686 
   1687 #ifdef LIBXML_WRITER_ENABLED
   1688 /**
   1689  * xmlTextReaderReadInnerXml:
   1690  * @reader:  the xmlTextReaderPtr used
   1691  *
   1692  * Reads the contents of the current node, including child nodes and markup.
   1693  *
   1694  * Returns a string containing the XML content, or NULL if the current node
   1695  *         is neither an element nor attribute, or has no child nodes. The
   1696  *         string must be deallocated by the caller.
   1697  */
   1698 xmlChar *
   1699 xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
   1700 {
   1701     xmlChar *resbuf;
   1702     xmlNodePtr node, cur_node;
   1703     xmlBufferPtr buff, buff2;
   1704     xmlDocPtr doc;
   1705 
   1706     if (xmlTextReaderExpand(reader) == NULL) {
   1707         return NULL;
   1708     }
   1709     doc = reader->doc;
   1710     buff = xmlBufferCreate();
   1711     for (cur_node = reader->node->children; cur_node != NULL;
   1712          cur_node = cur_node->next) {
   1713         node = xmlDocCopyNode(cur_node, doc, 1);
   1714         buff2 = xmlBufferCreate();
   1715         if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) {
   1716             xmlFreeNode(node);
   1717             xmlBufferFree(buff2);
   1718             xmlBufferFree(buff);
   1719             return NULL;
   1720         }
   1721         xmlBufferCat(buff, buff2->content);
   1722         xmlFreeNode(node);
   1723         xmlBufferFree(buff2);
   1724     }
   1725     resbuf = buff->content;
   1726     buff->content = NULL;
   1727 
   1728     xmlBufferFree(buff);
   1729     return resbuf;
   1730 }
   1731 #endif
   1732 
   1733 #ifdef LIBXML_WRITER_ENABLED
   1734 /**
   1735  * xmlTextReaderReadOuterXml:
   1736  * @reader:  the xmlTextReaderPtr used
   1737  *
   1738  * Reads the contents of the current node, including child nodes and markup.
   1739  *
   1740  * Returns a string containing the node and any XML content, or NULL if the
   1741  *         current node cannot be serialized. The string must be deallocated
   1742  *         by the caller.
   1743  */
   1744 xmlChar *
   1745 xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
   1746 {
   1747     xmlChar *resbuf;
   1748     xmlNodePtr node;
   1749     xmlBufferPtr buff;
   1750     xmlDocPtr doc;
   1751 
   1752     node = reader->node;
   1753     doc = reader->doc;
   1754     if (xmlTextReaderExpand(reader) == NULL) {
   1755         return NULL;
   1756     }
   1757 	if (node->type == XML_DTD_NODE) {
   1758 		node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node);
   1759 	} else {
   1760 		node = xmlDocCopyNode(node, doc, 1);
   1761 	}
   1762     buff = xmlBufferCreate();
   1763     if (xmlNodeDump(buff, doc, node, 0, 0) == -1) {
   1764         xmlFreeNode(node);
   1765         xmlBufferFree(buff);
   1766         return NULL;
   1767     }
   1768 
   1769     resbuf = buff->content;
   1770     buff->content = NULL;
   1771 
   1772     xmlFreeNode(node);
   1773     xmlBufferFree(buff);
   1774     return resbuf;
   1775 }
   1776 #endif
   1777 
   1778 /**
   1779  * xmlTextReaderReadString:
   1780  * @reader:  the xmlTextReaderPtr used
   1781  *
   1782  * Reads the contents of an element or a text node as a string.
   1783  *
   1784  * Returns a string containing the contents of the Element or Text node,
   1785  *         or NULL if the reader is positioned on any other type of node.
   1786  *         The string must be deallocated by the caller.
   1787  */
   1788 xmlChar *
   1789 xmlTextReaderReadString(xmlTextReaderPtr reader)
   1790 {
   1791     xmlNodePtr node;
   1792 
   1793     if ((reader == NULL) || (reader->node == NULL))
   1794        return(NULL);
   1795 
   1796     node = (reader->curnode != NULL) ? reader->curnode : reader->node;
   1797     switch (node->type) {
   1798     case XML_TEXT_NODE:
   1799        if (node->content != NULL)
   1800            return(xmlStrdup(node->content));
   1801        break;
   1802     case XML_ELEMENT_NODE:
   1803 	if (xmlTextReaderDoExpand(reader) != -1) {
   1804 	    return xmlTextReaderCollectSiblings(node->children);
   1805 	}
   1806 	break;
   1807     case XML_ATTRIBUTE_NODE:
   1808 	TODO
   1809 	break;
   1810     default:
   1811        break;
   1812     }
   1813     return(NULL);
   1814 }
   1815 
   1816 #if 0
   1817 /**
   1818  * xmlTextReaderReadBase64:
   1819  * @reader:  the xmlTextReaderPtr used
   1820  * @array:  a byte array to store the content.
   1821  * @offset:  the zero-based index into array where the method should
   1822  *           begin to write.
   1823  * @len:  the number of bytes to write.
   1824  *
   1825  * Reads and decodes the Base64 encoded contents of an element and
   1826  * stores the result in a byte buffer.
   1827  *
   1828  * Returns the number of bytes written to array, or zero if the current
   1829  *         instance is not positioned on an element or -1 in case of error.
   1830  */
   1831 int
   1832 xmlTextReaderReadBase64(xmlTextReaderPtr reader,
   1833                         unsigned char *array ATTRIBUTE_UNUSED,
   1834 	                int offset ATTRIBUTE_UNUSED,
   1835 			int len ATTRIBUTE_UNUSED) {
   1836     if ((reader == NULL) || (reader->ctxt == NULL))
   1837 	return(-1);
   1838     if (reader->ctxt->wellFormed != 1)
   1839 	return(-1);
   1840 
   1841     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
   1842 	return(0);
   1843     TODO
   1844     return(0);
   1845 }
   1846 
   1847 /**
   1848  * xmlTextReaderReadBinHex:
   1849  * @reader:  the xmlTextReaderPtr used
   1850  * @array:  a byte array to store the content.
   1851  * @offset:  the zero-based index into array where the method should
   1852  *           begin to write.
   1853  * @len:  the number of bytes to write.
   1854  *
   1855  * Reads and decodes the BinHex encoded contents of an element and
   1856  * stores the result in a byte buffer.
   1857  *
   1858  * Returns the number of bytes written to array, or zero if the current
   1859  *         instance is not positioned on an element or -1 in case of error.
   1860  */
   1861 int
   1862 xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
   1863                         unsigned char *array ATTRIBUTE_UNUSED,
   1864 	                int offset ATTRIBUTE_UNUSED,
   1865 			int len ATTRIBUTE_UNUSED) {
   1866     if ((reader == NULL) || (reader->ctxt == NULL))
   1867 	return(-1);
   1868     if (reader->ctxt->wellFormed != 1)
   1869 	return(-1);
   1870 
   1871     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
   1872 	return(0);
   1873     TODO
   1874     return(0);
   1875 }
   1876 #endif
   1877 
   1878 /************************************************************************
   1879  *									*
   1880  *			Operating on a preparsed tree			*
   1881  *									*
   1882  ************************************************************************/
   1883 static int
   1884 xmlTextReaderNextTree(xmlTextReaderPtr reader)
   1885 {
   1886     if (reader == NULL)
   1887         return(-1);
   1888 
   1889     if (reader->state == XML_TEXTREADER_END)
   1890         return(0);
   1891 
   1892     if (reader->node == NULL) {
   1893         if (reader->doc->children == NULL) {
   1894             reader->state = XML_TEXTREADER_END;
   1895             return(0);
   1896         }
   1897 
   1898         reader->node = reader->doc->children;
   1899         reader->state = XML_TEXTREADER_START;
   1900         return(1);
   1901     }
   1902 
   1903     if (reader->state != XML_TEXTREADER_BACKTRACK) {
   1904 	/* Here removed traversal to child, because we want to skip the subtree,
   1905 	replace with traversal to sibling to skip subtree */
   1906         if (reader->node->next != 0) {
   1907 	    /* Move to sibling if present,skipping sub-tree */
   1908             reader->node = reader->node->next;
   1909             reader->state = XML_TEXTREADER_START;
   1910             return(1);
   1911         }
   1912 
   1913 	/* if reader->node->next is NULL mean no subtree for current node,
   1914 	so need to move to sibling of parent node if present */
   1915         if ((reader->node->type == XML_ELEMENT_NODE) ||
   1916             (reader->node->type == XML_ATTRIBUTE_NODE)) {
   1917             reader->state = XML_TEXTREADER_BACKTRACK;
   1918 	    /* This will move to parent if present */
   1919             xmlTextReaderRead(reader);
   1920         }
   1921     }
   1922 
   1923     if (reader->node->next != 0) {
   1924         reader->node = reader->node->next;
   1925         reader->state = XML_TEXTREADER_START;
   1926         return(1);
   1927     }
   1928 
   1929     if (reader->node->parent != 0) {
   1930         if (reader->node->parent->type == XML_DOCUMENT_NODE) {
   1931             reader->state = XML_TEXTREADER_END;
   1932             return(0);
   1933         }
   1934 
   1935         reader->node = reader->node->parent;
   1936         reader->depth--;
   1937         reader->state = XML_TEXTREADER_BACKTRACK;
   1938 	/* Repeat process to move to sibling of parent node if present */
   1939         xmlTextReaderNextTree(reader);
   1940     }
   1941 
   1942     reader->state = XML_TEXTREADER_END;
   1943 
   1944     return(1);
   1945 }
   1946 
   1947 /**
   1948  * xmlTextReaderReadTree:
   1949  * @reader:  the xmlTextReaderPtr used
   1950  *
   1951  *  Moves the position of the current instance to the next node in
   1952  *  the stream, exposing its properties.
   1953  *
   1954  *  Returns 1 if the node was read successfully, 0 if there is no more
   1955  *          nodes to read, or -1 in case of error
   1956  */
   1957 static int
   1958 xmlTextReaderReadTree(xmlTextReaderPtr reader) {
   1959     if (reader->state == XML_TEXTREADER_END)
   1960         return(0);
   1961 
   1962 next_node:
   1963     if (reader->node == NULL) {
   1964         if (reader->doc->children == NULL) {
   1965             reader->state = XML_TEXTREADER_END;
   1966             return(0);
   1967         }
   1968 
   1969         reader->node = reader->doc->children;
   1970         reader->state = XML_TEXTREADER_START;
   1971         goto found_node;
   1972     }
   1973 
   1974     if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
   1975         (reader->node->type != XML_DTD_NODE) &&
   1976         (reader->node->type != XML_XINCLUDE_START) &&
   1977 	(reader->node->type != XML_ENTITY_REF_NODE)) {
   1978         if (reader->node->children != NULL) {
   1979             reader->node = reader->node->children;
   1980             reader->depth++;
   1981             reader->state = XML_TEXTREADER_START;
   1982             goto found_node;
   1983         }
   1984 
   1985         if (reader->node->type == XML_ATTRIBUTE_NODE) {
   1986             reader->state = XML_TEXTREADER_BACKTRACK;
   1987             goto found_node;
   1988         }
   1989     }
   1990 
   1991     if (reader->node->next != NULL) {
   1992         reader->node = reader->node->next;
   1993         reader->state = XML_TEXTREADER_START;
   1994         goto found_node;
   1995     }
   1996 
   1997     if (reader->node->parent != NULL) {
   1998         if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
   1999 	    (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
   2000             reader->state = XML_TEXTREADER_END;
   2001             return(0);
   2002         }
   2003 
   2004         reader->node = reader->node->parent;
   2005         reader->depth--;
   2006         reader->state = XML_TEXTREADER_BACKTRACK;
   2007         goto found_node;
   2008     }
   2009 
   2010     reader->state = XML_TEXTREADER_END;
   2011 
   2012 found_node:
   2013     if ((reader->node->type == XML_XINCLUDE_START) ||
   2014         (reader->node->type == XML_XINCLUDE_END))
   2015 	goto next_node;
   2016 
   2017     return(1);
   2018 }
   2019 
   2020 /**
   2021  * xmlTextReaderNextSibling:
   2022  * @reader:  the xmlTextReaderPtr used
   2023  *
   2024  * Skip to the node following the current one in document order while
   2025  * avoiding the subtree if any.
   2026  * Currently implemented only for Readers built on a document
   2027  *
   2028  * Returns 1 if the node was read successfully, 0 if there is no more
   2029  *          nodes to read, or -1 in case of error
   2030  */
   2031 int
   2032 xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
   2033     if (reader == NULL)
   2034         return(-1);
   2035     if (reader->doc == NULL) {
   2036         /* TODO */
   2037 	return(-1);
   2038     }
   2039 
   2040     if (reader->state == XML_TEXTREADER_END)
   2041         return(0);
   2042 
   2043     if (reader->node == NULL)
   2044         return(xmlTextReaderNextTree(reader));
   2045 
   2046     if (reader->node->next != NULL) {
   2047         reader->node = reader->node->next;
   2048         reader->state = XML_TEXTREADER_START;
   2049         return(1);
   2050     }
   2051 
   2052     return(0);
   2053 }
   2054 
   2055 /************************************************************************
   2056  *									*
   2057  *			Constructor and destructors			*
   2058  *									*
   2059  ************************************************************************/
   2060 /**
   2061  * xmlNewTextReader:
   2062  * @input: the xmlParserInputBufferPtr used to read data
   2063  * @URI: the URI information for the source if available
   2064  *
   2065  * Create an xmlTextReader structure fed with @input
   2066  *
   2067  * Returns the new xmlTextReaderPtr or NULL in case of error
   2068  */
   2069 xmlTextReaderPtr
   2070 xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
   2071     xmlTextReaderPtr ret;
   2072 
   2073     if (input == NULL)
   2074 	return(NULL);
   2075     ret = xmlMalloc(sizeof(xmlTextReader));
   2076     if (ret == NULL) {
   2077         xmlGenericError(xmlGenericErrorContext,
   2078 		"xmlNewTextReader : malloc failed\n");
   2079 	return(NULL);
   2080     }
   2081     memset(ret, 0, sizeof(xmlTextReader));
   2082     ret->doc = NULL;
   2083     ret->entTab = NULL;
   2084     ret->entMax = 0;
   2085     ret->entNr = 0;
   2086     ret->input = input;
   2087     ret->buffer = xmlBufCreateSize(100);
   2088     if (ret->buffer == NULL) {
   2089         xmlFree(ret);
   2090         xmlGenericError(xmlGenericErrorContext,
   2091 		"xmlNewTextReader : malloc failed\n");
   2092 	return(NULL);
   2093     }
   2094     /* no operation on a reader should require a huge buffer */
   2095     xmlBufSetAllocationScheme(ret->buffer,
   2096 			      XML_BUFFER_ALLOC_BOUNDED);
   2097     ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
   2098     if (ret->sax == NULL) {
   2099 	xmlBufFree(ret->buffer);
   2100 	xmlFree(ret);
   2101         xmlGenericError(xmlGenericErrorContext,
   2102 		"xmlNewTextReader : malloc failed\n");
   2103 	return(NULL);
   2104     }
   2105     xmlSAXVersion(ret->sax, 2);
   2106     ret->startElement = ret->sax->startElement;
   2107     ret->sax->startElement = xmlTextReaderStartElement;
   2108     ret->endElement = ret->sax->endElement;
   2109     ret->sax->endElement = xmlTextReaderEndElement;
   2110 #ifdef LIBXML_SAX1_ENABLED
   2111     if (ret->sax->initialized == XML_SAX2_MAGIC) {
   2112 #endif /* LIBXML_SAX1_ENABLED */
   2113 	ret->startElementNs = ret->sax->startElementNs;
   2114 	ret->sax->startElementNs = xmlTextReaderStartElementNs;
   2115 	ret->endElementNs = ret->sax->endElementNs;
   2116 	ret->sax->endElementNs = xmlTextReaderEndElementNs;
   2117 #ifdef LIBXML_SAX1_ENABLED
   2118     } else {
   2119 	ret->startElementNs = NULL;
   2120 	ret->endElementNs = NULL;
   2121     }
   2122 #endif /* LIBXML_SAX1_ENABLED */
   2123     ret->characters = ret->sax->characters;
   2124     ret->sax->characters = xmlTextReaderCharacters;
   2125     ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
   2126     ret->cdataBlock = ret->sax->cdataBlock;
   2127     ret->sax->cdataBlock = xmlTextReaderCDataBlock;
   2128 
   2129     ret->mode = XML_TEXTREADER_MODE_INITIAL;
   2130     ret->node = NULL;
   2131     ret->curnode = NULL;
   2132     if (xmlBufUse(ret->input->buffer) < 4) {
   2133 	xmlParserInputBufferRead(input, 4);
   2134     }
   2135     if (xmlBufUse(ret->input->buffer) >= 4) {
   2136 	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
   2137 			     (const char *) xmlBufContent(ret->input->buffer),
   2138                                             4, URI);
   2139 	ret->base = 0;
   2140 	ret->cur = 4;
   2141     } else {
   2142 	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
   2143 	ret->base = 0;
   2144 	ret->cur = 0;
   2145     }
   2146 
   2147     if (ret->ctxt == NULL) {
   2148         xmlGenericError(xmlGenericErrorContext,
   2149 		"xmlNewTextReader : malloc failed\n");
   2150 	xmlBufFree(ret->buffer);
   2151 	xmlFree(ret->sax);
   2152 	xmlFree(ret);
   2153 	return(NULL);
   2154     }
   2155     ret->ctxt->parseMode = XML_PARSE_READER;
   2156     ret->ctxt->_private = ret;
   2157     ret->ctxt->linenumbers = 1;
   2158     ret->ctxt->dictNames = 1;
   2159     ret->allocs = XML_TEXTREADER_CTXT;
   2160     /*
   2161      * use the parser dictionnary to allocate all elements and attributes names
   2162      */
   2163     ret->ctxt->docdict = 1;
   2164     ret->dict = ret->ctxt->dict;
   2165 #ifdef LIBXML_XINCLUDE_ENABLED
   2166     ret->xinclude = 0;
   2167 #endif
   2168 #ifdef LIBXML_PATTERN_ENABLED
   2169     ret->patternMax = 0;
   2170     ret->patternTab = NULL;
   2171 #endif
   2172     return(ret);
   2173 }
   2174 
   2175 /**
   2176  * xmlNewTextReaderFilename:
   2177  * @URI: the URI of the resource to process
   2178  *
   2179  * Create an xmlTextReader structure fed with the resource at @URI
   2180  *
   2181  * Returns the new xmlTextReaderPtr or NULL in case of error
   2182  */
   2183 xmlTextReaderPtr
   2184 xmlNewTextReaderFilename(const char *URI) {
   2185     xmlParserInputBufferPtr input;
   2186     xmlTextReaderPtr ret;
   2187     char *directory = NULL;
   2188 
   2189     input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
   2190     if (input == NULL)
   2191 	return(NULL);
   2192     ret = xmlNewTextReader(input, URI);
   2193     if (ret == NULL) {
   2194 	xmlFreeParserInputBuffer(input);
   2195 	return(NULL);
   2196     }
   2197     ret->allocs |= XML_TEXTREADER_INPUT;
   2198     if (ret->ctxt->directory == NULL)
   2199         directory = xmlParserGetDirectory(URI);
   2200     if ((ret->ctxt->directory == NULL) && (directory != NULL))
   2201         ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
   2202     if (directory != NULL)
   2203 	xmlFree(directory);
   2204     return(ret);
   2205 }
   2206 
   2207 /**
   2208  * xmlFreeTextReader:
   2209  * @reader:  the xmlTextReaderPtr
   2210  *
   2211  * Deallocate all the resources associated to the reader
   2212  */
   2213 void
   2214 xmlFreeTextReader(xmlTextReaderPtr reader) {
   2215     if (reader == NULL)
   2216 	return;
   2217 #ifdef LIBXML_SCHEMAS_ENABLED
   2218     if (reader->rngSchemas != NULL) {
   2219 	xmlRelaxNGFree(reader->rngSchemas);
   2220 	reader->rngSchemas = NULL;
   2221     }
   2222     if (reader->rngValidCtxt != NULL) {
   2223 	if (! reader->rngPreserveCtxt)
   2224 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
   2225 	reader->rngValidCtxt = NULL;
   2226     }
   2227     if (reader->xsdPlug != NULL) {
   2228 	xmlSchemaSAXUnplug(reader->xsdPlug);
   2229 	reader->xsdPlug = NULL;
   2230     }
   2231     if (reader->xsdValidCtxt != NULL) {
   2232 	if (! reader->xsdPreserveCtxt)
   2233 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
   2234 	reader->xsdValidCtxt = NULL;
   2235     }
   2236     if (reader->xsdSchemas != NULL) {
   2237 	xmlSchemaFree(reader->xsdSchemas);
   2238 	reader->xsdSchemas = NULL;
   2239     }
   2240 #endif
   2241 #ifdef LIBXML_XINCLUDE_ENABLED
   2242     if (reader->xincctxt != NULL)
   2243 	xmlXIncludeFreeContext(reader->xincctxt);
   2244 #endif
   2245 #ifdef LIBXML_PATTERN_ENABLED
   2246     if (reader->patternTab != NULL) {
   2247         int i;
   2248 	for (i = 0;i < reader->patternNr;i++) {
   2249 	    if (reader->patternTab[i] != NULL)
   2250 	        xmlFreePattern(reader->patternTab[i]);
   2251 	}
   2252 	xmlFree(reader->patternTab);
   2253     }
   2254 #endif
   2255     if (reader->faketext != NULL) {
   2256 	xmlFreeNode(reader->faketext);
   2257     }
   2258     if (reader->ctxt != NULL) {
   2259         if (reader->dict == reader->ctxt->dict)
   2260 	    reader->dict = NULL;
   2261 	if (reader->ctxt->myDoc != NULL) {
   2262 	    if (reader->preserve == 0)
   2263 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
   2264 	    reader->ctxt->myDoc = NULL;
   2265 	}
   2266 	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
   2267 	    (reader->ctxt->vctxt.vstateMax > 0)){
   2268 	    xmlFree(reader->ctxt->vctxt.vstateTab);
   2269 	    reader->ctxt->vctxt.vstateTab = NULL;
   2270 	    reader->ctxt->vctxt.vstateMax = 0;
   2271 	}
   2272 	if (reader->allocs & XML_TEXTREADER_CTXT)
   2273 	    xmlFreeParserCtxt(reader->ctxt);
   2274     }
   2275     if (reader->sax != NULL)
   2276 	xmlFree(reader->sax);
   2277     if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
   2278 	xmlFreeParserInputBuffer(reader->input);
   2279     if (reader->buffer != NULL)
   2280         xmlBufFree(reader->buffer);
   2281     if (reader->entTab != NULL)
   2282 	xmlFree(reader->entTab);
   2283     if (reader->dict != NULL)
   2284         xmlDictFree(reader->dict);
   2285     xmlFree(reader);
   2286 }
   2287 
   2288 /************************************************************************
   2289  *									*
   2290  *			Methods for XmlTextReader			*
   2291  *									*
   2292  ************************************************************************/
   2293 /**
   2294  * xmlTextReaderClose:
   2295  * @reader:  the xmlTextReaderPtr used
   2296  *
   2297  * This method releases any resources allocated by the current instance
   2298  * changes the state to Closed and close any underlying input.
   2299  *
   2300  * Returns 0 or -1 in case of error
   2301  */
   2302 int
   2303 xmlTextReaderClose(xmlTextReaderPtr reader) {
   2304     if (reader == NULL)
   2305 	return(-1);
   2306     reader->node = NULL;
   2307     reader->curnode = NULL;
   2308     reader->mode = XML_TEXTREADER_MODE_CLOSED;
   2309     if (reader->ctxt != NULL) {
   2310 	xmlStopParser(reader->ctxt);
   2311 	if (reader->ctxt->myDoc != NULL) {
   2312 	    if (reader->preserve == 0)
   2313 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
   2314 	    reader->ctxt->myDoc = NULL;
   2315 	}
   2316     }
   2317     if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
   2318 	xmlFreeParserInputBuffer(reader->input);
   2319 	reader->allocs -= XML_TEXTREADER_INPUT;
   2320     }
   2321     return(0);
   2322 }
   2323 
   2324 /**
   2325  * xmlTextReaderGetAttributeNo:
   2326  * @reader:  the xmlTextReaderPtr used
   2327  * @no: the zero-based index of the attribute relative to the containing element
   2328  *
   2329  * Provides the value of the attribute with the specified index relative
   2330  * to the containing element.
   2331  *
   2332  * Returns a string containing the value of the specified attribute, or NULL
   2333  *    in case of error. The string must be deallocated by the caller.
   2334  */
   2335 xmlChar *
   2336 xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
   2337     xmlChar *ret;
   2338     int i;
   2339     xmlAttrPtr cur;
   2340     xmlNsPtr ns;
   2341 
   2342     if (reader == NULL)
   2343 	return(NULL);
   2344     if (reader->node == NULL)
   2345 	return(NULL);
   2346     if (reader->curnode != NULL)
   2347 	return(NULL);
   2348     /* TODO: handle the xmlDecl */
   2349     if (reader->node->type != XML_ELEMENT_NODE)
   2350 	return(NULL);
   2351 
   2352     ns = reader->node->nsDef;
   2353     for (i = 0;(i < no) && (ns != NULL);i++) {
   2354 	ns = ns->next;
   2355     }
   2356     if (ns != NULL)
   2357 	return(xmlStrdup(ns->href));
   2358 
   2359     cur = reader->node->properties;
   2360     if (cur == NULL)
   2361 	return(NULL);
   2362     for (;i < no;i++) {
   2363 	cur = cur->next;
   2364 	if (cur == NULL)
   2365 	    return(NULL);
   2366     }
   2367     /* TODO walk the DTD if present */
   2368 
   2369     ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
   2370     if (ret == NULL) return(xmlStrdup((xmlChar *)""));
   2371     return(ret);
   2372 }
   2373 
   2374 /**
   2375  * xmlTextReaderGetAttribute:
   2376  * @reader:  the xmlTextReaderPtr used
   2377  * @name: the qualified name of the attribute.
   2378  *
   2379  * Provides the value of the attribute with the specified qualified name.
   2380  *
   2381  * Returns a string containing the value of the specified attribute, or NULL
   2382  *    in case of error. The string must be deallocated by the caller.
   2383  */
   2384 xmlChar *
   2385 xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
   2386     xmlChar *prefix = NULL;
   2387     xmlChar *localname;
   2388     xmlNsPtr ns;
   2389     xmlChar *ret = NULL;
   2390 
   2391     if ((reader == NULL) || (name == NULL))
   2392 	return(NULL);
   2393     if (reader->node == NULL)
   2394 	return(NULL);
   2395     if (reader->curnode != NULL)
   2396 	return(NULL);
   2397 
   2398     /* TODO: handle the xmlDecl */
   2399     if (reader->node->type != XML_ELEMENT_NODE)
   2400 	return(NULL);
   2401 
   2402     localname = xmlSplitQName2(name, &prefix);
   2403     if (localname == NULL) {
   2404 		/*
   2405 		 * Namespace default decl
   2406 		 */
   2407 		if (xmlStrEqual(name, BAD_CAST "xmlns")) {
   2408 			ns = reader->node->nsDef;
   2409 			while (ns != NULL) {
   2410 				if (ns->prefix == NULL) {
   2411 					return(xmlStrdup(ns->href));
   2412 				}
   2413 				ns = ns->next;
   2414 			}
   2415 			return NULL;
   2416 		}
   2417 		return(xmlGetNoNsProp(reader->node, name));
   2418 	}
   2419 
   2420     /*
   2421      * Namespace default decl
   2422      */
   2423     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
   2424 		ns = reader->node->nsDef;
   2425 		while (ns != NULL) {
   2426 			if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
   2427 				ret = xmlStrdup(ns->href);
   2428 				break;
   2429 			}
   2430 			ns = ns->next;
   2431 		}
   2432     } else {
   2433 		ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
   2434 		if (ns != NULL)
   2435 			ret = xmlGetNsProp(reader->node, localname, ns->href);
   2436 	}
   2437 
   2438     xmlFree(localname);
   2439     if (prefix != NULL)
   2440         xmlFree(prefix);
   2441     return(ret);
   2442 }
   2443 
   2444 
   2445 /**
   2446  * xmlTextReaderGetAttributeNs:
   2447  * @reader:  the xmlTextReaderPtr used
   2448  * @localName: the local name of the attribute.
   2449  * @namespaceURI: the namespace URI of the attribute.
   2450  *
   2451  * Provides the value of the specified attribute
   2452  *
   2453  * Returns a string containing the value of the specified attribute, or NULL
   2454  *    in case of error. The string must be deallocated by the caller.
   2455  */
   2456 xmlChar *
   2457 xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
   2458 			    const xmlChar *namespaceURI) {
   2459     xmlChar *prefix = NULL;
   2460     xmlNsPtr ns;
   2461 
   2462     if ((reader == NULL) || (localName == NULL))
   2463 	return(NULL);
   2464     if (reader->node == NULL)
   2465 	return(NULL);
   2466     if (reader->curnode != NULL)
   2467 	return(NULL);
   2468 
   2469     /* TODO: handle the xmlDecl */
   2470     if (reader->node->type != XML_ELEMENT_NODE)
   2471 	return(NULL);
   2472 
   2473     if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
   2474 		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
   2475 			prefix = BAD_CAST localName;
   2476 		}
   2477 		ns = reader->node->nsDef;
   2478 		while (ns != NULL) {
   2479 			if ((prefix == NULL && ns->prefix == NULL) ||
   2480 				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
   2481 				return xmlStrdup(ns->href);
   2482 			}
   2483 			ns = ns->next;
   2484 		}
   2485 		return NULL;
   2486     }
   2487 
   2488     return(xmlGetNsProp(reader->node, localName, namespaceURI));
   2489 }
   2490 
   2491 /**
   2492  * xmlTextReaderGetRemainder:
   2493  * @reader:  the xmlTextReaderPtr used
   2494  *
   2495  * Method to get the remainder of the buffered XML. this method stops the
   2496  * parser, set its state to End Of File and return the input stream with
   2497  * what is left that the parser did not use.
   2498  *
   2499  * The implementation is not good, the parser certainly procgressed past
   2500  * what's left in reader->input, and there is an allocation problem. Best
   2501  * would be to rewrite it differently.
   2502  *
   2503  * Returns the xmlParserInputBufferPtr attached to the XML or NULL
   2504  *    in case of error.
   2505  */
   2506 xmlParserInputBufferPtr
   2507 xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
   2508     xmlParserInputBufferPtr ret = NULL;
   2509 
   2510     if (reader == NULL)
   2511 	return(NULL);
   2512     if (reader->node == NULL)
   2513 	return(NULL);
   2514 
   2515     reader->node = NULL;
   2516     reader->curnode = NULL;
   2517     reader->mode = XML_TEXTREADER_MODE_EOF;
   2518     if (reader->ctxt != NULL) {
   2519 	xmlStopParser(reader->ctxt);
   2520 	if (reader->ctxt->myDoc != NULL) {
   2521 	    if (reader->preserve == 0)
   2522 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
   2523 	    reader->ctxt->myDoc = NULL;
   2524 	}
   2525     }
   2526     if (reader->allocs & XML_TEXTREADER_INPUT) {
   2527 	ret = reader->input;
   2528 	reader->input = NULL;
   2529 	reader->allocs -= XML_TEXTREADER_INPUT;
   2530     } else {
   2531 	/*
   2532 	 * Hum, one may need to duplicate the data structure because
   2533 	 * without reference counting the input may be freed twice:
   2534 	 *   - by the layer which allocated it.
   2535 	 *   - by the layer to which would have been returned to.
   2536 	 */
   2537 	TODO
   2538 	return(NULL);
   2539     }
   2540     return(ret);
   2541 }
   2542 
   2543 /**
   2544  * xmlTextReaderLookupNamespace:
   2545  * @reader:  the xmlTextReaderPtr used
   2546  * @prefix: the prefix whose namespace URI is to be resolved. To return
   2547  *          the default namespace, specify NULL
   2548  *
   2549  * Resolves a namespace prefix in the scope of the current element.
   2550  *
   2551  * Returns a string containing the namespace URI to which the prefix maps
   2552  *    or NULL in case of error. The string must be deallocated by the caller.
   2553  */
   2554 xmlChar *
   2555 xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
   2556     xmlNsPtr ns;
   2557 
   2558     if (reader == NULL)
   2559 	return(NULL);
   2560     if (reader->node == NULL)
   2561 	return(NULL);
   2562 
   2563     ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
   2564     if (ns == NULL)
   2565 	return(NULL);
   2566     return(xmlStrdup(ns->href));
   2567 }
   2568 
   2569 /**
   2570  * xmlTextReaderMoveToAttributeNo:
   2571  * @reader:  the xmlTextReaderPtr used
   2572  * @no: the zero-based index of the attribute relative to the containing
   2573  *      element.
   2574  *
   2575  * Moves the position of the current instance to the attribute with
   2576  * the specified index relative to the containing element.
   2577  *
   2578  * Returns 1 in case of success, -1 in case of error, 0 if not found
   2579  */
   2580 int
   2581 xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
   2582     int i;
   2583     xmlAttrPtr cur;
   2584     xmlNsPtr ns;
   2585 
   2586     if (reader == NULL)
   2587 	return(-1);
   2588     if (reader->node == NULL)
   2589 	return(-1);
   2590     /* TODO: handle the xmlDecl */
   2591     if (reader->node->type != XML_ELEMENT_NODE)
   2592 	return(-1);
   2593 
   2594     reader->curnode = NULL;
   2595 
   2596     ns = reader->node->nsDef;
   2597     for (i = 0;(i < no) && (ns != NULL);i++) {
   2598 	ns = ns->next;
   2599     }
   2600     if (ns != NULL) {
   2601 	reader->curnode = (xmlNodePtr) ns;
   2602 	return(1);
   2603     }
   2604 
   2605     cur = reader->node->properties;
   2606     if (cur == NULL)
   2607 	return(0);
   2608     for (;i < no;i++) {
   2609 	cur = cur->next;
   2610 	if (cur == NULL)
   2611 	    return(0);
   2612     }
   2613     /* TODO walk the DTD if present */
   2614 
   2615     reader->curnode = (xmlNodePtr) cur;
   2616     return(1);
   2617 }
   2618 
   2619 /**
   2620  * xmlTextReaderMoveToAttribute:
   2621  * @reader:  the xmlTextReaderPtr used
   2622  * @name: the qualified name of the attribute.
   2623  *
   2624  * Moves the position of the current instance to the attribute with
   2625  * the specified qualified name.
   2626  *
   2627  * Returns 1 in case of success, -1 in case of error, 0 if not found
   2628  */
   2629 int
   2630 xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
   2631     xmlChar *prefix = NULL;
   2632     xmlChar *localname;
   2633     xmlNsPtr ns;
   2634     xmlAttrPtr prop;
   2635 
   2636     if ((reader == NULL) || (name == NULL))
   2637 	return(-1);
   2638     if (reader->node == NULL)
   2639 	return(-1);
   2640 
   2641     /* TODO: handle the xmlDecl */
   2642     if (reader->node->type != XML_ELEMENT_NODE)
   2643 	return(0);
   2644 
   2645     localname = xmlSplitQName2(name, &prefix);
   2646     if (localname == NULL) {
   2647 	/*
   2648 	 * Namespace default decl
   2649 	 */
   2650 	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
   2651 	    ns = reader->node->nsDef;
   2652 	    while (ns != NULL) {
   2653 		if (ns->prefix == NULL) {
   2654 		    reader->curnode = (xmlNodePtr) ns;
   2655 		    return(1);
   2656 		}
   2657 		ns = ns->next;
   2658 	    }
   2659 	    return(0);
   2660 	}
   2661 
   2662 	prop = reader->node->properties;
   2663 	while (prop != NULL) {
   2664 	    /*
   2665 	     * One need to have
   2666 	     *   - same attribute names
   2667 	     *   - and the attribute carrying that namespace
   2668 	     */
   2669 	    if ((xmlStrEqual(prop->name, name)) &&
   2670 		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
   2671 		reader->curnode = (xmlNodePtr) prop;
   2672 		return(1);
   2673 	    }
   2674 	    prop = prop->next;
   2675 	}
   2676 	return(0);
   2677     }
   2678 
   2679     /*
   2680      * Namespace default decl
   2681      */
   2682     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
   2683 	ns = reader->node->nsDef;
   2684 	while (ns != NULL) {
   2685 	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
   2686 		reader->curnode = (xmlNodePtr) ns;
   2687 		goto found;
   2688 	    }
   2689 	    ns = ns->next;
   2690 	}
   2691 	goto not_found;
   2692     }
   2693     prop = reader->node->properties;
   2694     while (prop != NULL) {
   2695 	/*
   2696 	 * One need to have
   2697 	 *   - same attribute names
   2698 	 *   - and the attribute carrying that namespace
   2699 	 */
   2700 	if ((xmlStrEqual(prop->name, localname)) &&
   2701 	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
   2702 	    reader->curnode = (xmlNodePtr) prop;
   2703 	    goto found;
   2704 	}
   2705 	prop = prop->next;
   2706     }
   2707 not_found:
   2708     if (localname != NULL)
   2709         xmlFree(localname);
   2710     if (prefix != NULL)
   2711         xmlFree(prefix);
   2712     return(0);
   2713 
   2714 found:
   2715     if (localname != NULL)
   2716         xmlFree(localname);
   2717     if (prefix != NULL)
   2718         xmlFree(prefix);
   2719     return(1);
   2720 }
   2721 
   2722 /**
   2723  * xmlTextReaderMoveToAttributeNs:
   2724  * @reader:  the xmlTextReaderPtr used
   2725  * @localName:  the local name of the attribute.
   2726  * @namespaceURI:  the namespace URI of the attribute.
   2727  *
   2728  * Moves the position of the current instance to the attribute with the
   2729  * specified local name and namespace URI.
   2730  *
   2731  * Returns 1 in case of success, -1 in case of error, 0 if not found
   2732  */
   2733 int
   2734 xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
   2735 	const xmlChar *localName, const xmlChar *namespaceURI) {
   2736     xmlAttrPtr prop;
   2737     xmlNodePtr node;
   2738     xmlNsPtr ns;
   2739     xmlChar *prefix = NULL;
   2740 
   2741     if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
   2742 	return(-1);
   2743     if (reader->node == NULL)
   2744 	return(-1);
   2745     if (reader->node->type != XML_ELEMENT_NODE)
   2746 	return(0);
   2747     node = reader->node;
   2748 
   2749     if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
   2750 		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
   2751 			prefix = BAD_CAST localName;
   2752 		}
   2753 		ns = reader->node->nsDef;
   2754 		while (ns != NULL) {
   2755 			if ((prefix == NULL && ns->prefix == NULL) ||
   2756 				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
   2757 				reader->curnode = (xmlNodePtr) ns;
   2758 				return(1);
   2759 			}
   2760 			ns = ns->next;
   2761 		}
   2762 		return(0);
   2763     }
   2764 
   2765     prop = node->properties;
   2766     while (prop != NULL) {
   2767 	/*
   2768 	 * One need to have
   2769 	 *   - same attribute names
   2770 	 *   - and the attribute carrying that namespace
   2771 	 */
   2772         if (xmlStrEqual(prop->name, localName) &&
   2773 	    ((prop->ns != NULL) &&
   2774 	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
   2775 	    reader->curnode = (xmlNodePtr) prop;
   2776 	    return(1);
   2777         }
   2778 	prop = prop->next;
   2779     }
   2780     return(0);
   2781 }
   2782 
   2783 /**
   2784  * xmlTextReaderMoveToFirstAttribute:
   2785  * @reader:  the xmlTextReaderPtr used
   2786  *
   2787  * Moves the position of the current instance to the first attribute
   2788  * associated with the current node.
   2789  *
   2790  * Returns 1 in case of success, -1 in case of error, 0 if not found
   2791  */
   2792 int
   2793 xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
   2794     if (reader == NULL)
   2795 	return(-1);
   2796     if (reader->node == NULL)
   2797 	return(-1);
   2798     if (reader->node->type != XML_ELEMENT_NODE)
   2799 	return(0);
   2800 
   2801     if (reader->node->nsDef != NULL) {
   2802 	reader->curnode = (xmlNodePtr) reader->node->nsDef;
   2803 	return(1);
   2804     }
   2805     if (reader->node->properties != NULL) {
   2806 	reader->curnode = (xmlNodePtr) reader->node->properties;
   2807 	return(1);
   2808     }
   2809     return(0);
   2810 }
   2811 
   2812 /**
   2813  * xmlTextReaderMoveToNextAttribute:
   2814  * @reader:  the xmlTextReaderPtr used
   2815  *
   2816  * Moves the position of the current instance to the next attribute
   2817  * associated with the current node.
   2818  *
   2819  * Returns 1 in case of success, -1 in case of error, 0 if not found
   2820  */
   2821 int
   2822 xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
   2823     if (reader == NULL)
   2824 	return(-1);
   2825     if (reader->node == NULL)
   2826 	return(-1);
   2827     if (reader->node->type != XML_ELEMENT_NODE)
   2828 	return(0);
   2829     if (reader->curnode == NULL)
   2830 	return(xmlTextReaderMoveToFirstAttribute(reader));
   2831 
   2832     if (reader->curnode->type == XML_NAMESPACE_DECL) {
   2833 	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
   2834 	if (ns->next != NULL) {
   2835 	    reader->curnode = (xmlNodePtr) ns->next;
   2836 	    return(1);
   2837 	}
   2838 	if (reader->node->properties != NULL) {
   2839 	    reader->curnode = (xmlNodePtr) reader->node->properties;
   2840 	    return(1);
   2841 	}
   2842 	return(0);
   2843     } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
   2844 	       (reader->curnode->next != NULL)) {
   2845 	reader->curnode = reader->curnode->next;
   2846 	return(1);
   2847     }
   2848     return(0);
   2849 }
   2850 
   2851 /**
   2852  * xmlTextReaderMoveToElement:
   2853  * @reader:  the xmlTextReaderPtr used
   2854  *
   2855  * Moves the position of the current instance to the node that
   2856  * contains the current Attribute  node.
   2857  *
   2858  * Returns 1 in case of success, -1 in case of error, 0 if not moved
   2859  */
   2860 int
   2861 xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
   2862     if (reader == NULL)
   2863 	return(-1);
   2864     if (reader->node == NULL)
   2865 	return(-1);
   2866     if (reader->node->type != XML_ELEMENT_NODE)
   2867 	return(0);
   2868     if (reader->curnode != NULL) {
   2869 	reader->curnode = NULL;
   2870 	return(1);
   2871     }
   2872     return(0);
   2873 }
   2874 
   2875 /**
   2876  * xmlTextReaderReadAttributeValue:
   2877  * @reader:  the xmlTextReaderPtr used
   2878  *
   2879  * Parses an attribute value into one or more Text and EntityReference nodes.
   2880  *
   2881  * Returns 1 in case of success, 0 if the reader was not positionned on an
   2882  *         ttribute node or all the attribute values have been read, or -1
   2883  *         in case of error.
   2884  */
   2885 int
   2886 xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
   2887     if (reader == NULL)
   2888 	return(-1);
   2889     if (reader->node == NULL)
   2890 	return(-1);
   2891     if (reader->curnode == NULL)
   2892 	return(0);
   2893     if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
   2894 	if (reader->curnode->children == NULL)
   2895 	    return(0);
   2896 	reader->curnode = reader->curnode->children;
   2897     } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
   2898 	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
   2899 
   2900 	if (reader->faketext == NULL) {
   2901 	    reader->faketext = xmlNewDocText(reader->node->doc,
   2902 		                             ns->href);
   2903 	} else {
   2904             if ((reader->faketext->content != NULL) &&
   2905 	        (reader->faketext->content !=
   2906 		 (xmlChar *) &(reader->faketext->properties)))
   2907 		xmlFree(reader->faketext->content);
   2908 	    reader->faketext->content = xmlStrdup(ns->href);
   2909 	}
   2910 	reader->curnode = reader->faketext;
   2911     } else {
   2912 	if (reader->curnode->next == NULL)
   2913 	    return(0);
   2914 	reader->curnode = reader->curnode->next;
   2915     }
   2916     return(1);
   2917 }
   2918 
   2919 /**
   2920  * xmlTextReaderConstEncoding:
   2921  * @reader:  the xmlTextReaderPtr used
   2922  *
   2923  * Determine the encoding of the document being read.
   2924  *
   2925  * Returns a string containing the encoding of the document or NULL in
   2926  * case of error.  The string is deallocated with the reader.
   2927  */
   2928 const xmlChar *
   2929 xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
   2930     xmlDocPtr doc = NULL;
   2931     if (reader == NULL)
   2932 	return(NULL);
   2933     if (reader->doc != NULL)
   2934         doc = reader->doc;
   2935     else if (reader->ctxt != NULL)
   2936 	doc = reader->ctxt->myDoc;
   2937     if (doc == NULL)
   2938 	return(NULL);
   2939 
   2940     if (doc->encoding == NULL)
   2941 	return(NULL);
   2942     else
   2943       return(CONSTSTR(doc->encoding));
   2944 }
   2945 
   2946 
   2947 /************************************************************************
   2948  *									*
   2949  *			Acces API to the current node			*
   2950  *									*
   2951  ************************************************************************/
   2952 /**
   2953  * xmlTextReaderAttributeCount:
   2954  * @reader:  the xmlTextReaderPtr used
   2955  *
   2956  * Provides the number of attributes of the current node
   2957  *
   2958  * Returns 0 i no attributes, -1 in case of error or the attribute count
   2959  */
   2960 int
   2961 xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
   2962     int ret;
   2963     xmlAttrPtr attr;
   2964     xmlNsPtr ns;
   2965     xmlNodePtr node;
   2966 
   2967     if (reader == NULL)
   2968 	return(-1);
   2969     if (reader->node == NULL)
   2970 	return(0);
   2971 
   2972     if (reader->curnode != NULL)
   2973 	node = reader->curnode;
   2974     else
   2975 	node = reader->node;
   2976 
   2977     if (node->type != XML_ELEMENT_NODE)
   2978 	return(0);
   2979     if ((reader->state == XML_TEXTREADER_END) ||
   2980 	(reader->state == XML_TEXTREADER_BACKTRACK))
   2981 	return(0);
   2982     ret = 0;
   2983     attr = node->properties;
   2984     while (attr != NULL) {
   2985 	ret++;
   2986 	attr = attr->next;
   2987     }
   2988     ns = node->nsDef;
   2989     while (ns != NULL) {
   2990 	ret++;
   2991 	ns = ns->next;
   2992     }
   2993     return(ret);
   2994 }
   2995 
   2996 /**
   2997  * xmlTextReaderNodeType:
   2998  * @reader:  the xmlTextReaderPtr used
   2999  *
   3000  * Get the node type of the current node
   3001  * Reference:
   3002  * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html
   3003  *
   3004  * Returns the xmlNodeType of the current node or -1 in case of error
   3005  */
   3006 int
   3007 xmlTextReaderNodeType(xmlTextReaderPtr reader) {
   3008     xmlNodePtr node;
   3009 
   3010     if (reader == NULL)
   3011 	return(-1);
   3012     if (reader->node == NULL)
   3013 	return(XML_READER_TYPE_NONE);
   3014     if (reader->curnode != NULL)
   3015 	node = reader->curnode;
   3016     else
   3017 	node = reader->node;
   3018     switch (node->type) {
   3019         case XML_ELEMENT_NODE:
   3020 	    if ((reader->state == XML_TEXTREADER_END) ||
   3021 		(reader->state == XML_TEXTREADER_BACKTRACK))
   3022 		return(XML_READER_TYPE_END_ELEMENT);
   3023 	    return(XML_READER_TYPE_ELEMENT);
   3024         case XML_NAMESPACE_DECL:
   3025         case XML_ATTRIBUTE_NODE:
   3026 	    return(XML_READER_TYPE_ATTRIBUTE);
   3027         case XML_TEXT_NODE:
   3028 	    if (xmlIsBlankNode(reader->node)) {
   3029 		if (xmlNodeGetSpacePreserve(reader->node))
   3030 		    return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
   3031 		else
   3032 		    return(XML_READER_TYPE_WHITESPACE);
   3033 	    } else {
   3034 		return(XML_READER_TYPE_TEXT);
   3035 	    }
   3036         case XML_CDATA_SECTION_NODE:
   3037 	    return(XML_READER_TYPE_CDATA);
   3038         case XML_ENTITY_REF_NODE:
   3039 	    return(XML_READER_TYPE_ENTITY_REFERENCE);
   3040         case XML_ENTITY_NODE:
   3041 	    return(XML_READER_TYPE_ENTITY);
   3042         case XML_PI_NODE:
   3043 	    return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
   3044         case XML_COMMENT_NODE:
   3045 	    return(XML_READER_TYPE_COMMENT);
   3046         case XML_DOCUMENT_NODE:
   3047         case XML_HTML_DOCUMENT_NODE:
   3048 #ifdef LIBXML_DOCB_ENABLED
   3049         case XML_DOCB_DOCUMENT_NODE:
   3050 #endif
   3051 	    return(XML_READER_TYPE_DOCUMENT);
   3052         case XML_DOCUMENT_FRAG_NODE:
   3053 	    return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
   3054         case XML_NOTATION_NODE:
   3055 	    return(XML_READER_TYPE_NOTATION);
   3056         case XML_DOCUMENT_TYPE_NODE:
   3057         case XML_DTD_NODE:
   3058 	    return(XML_READER_TYPE_DOCUMENT_TYPE);
   3059 
   3060         case XML_ELEMENT_DECL:
   3061         case XML_ATTRIBUTE_DECL:
   3062         case XML_ENTITY_DECL:
   3063         case XML_XINCLUDE_START:
   3064         case XML_XINCLUDE_END:
   3065 	    return(XML_READER_TYPE_NONE);
   3066     }
   3067     return(-1);
   3068 }
   3069 
   3070 /**
   3071  * xmlTextReaderIsEmptyElement:
   3072  * @reader:  the xmlTextReaderPtr used
   3073  *
   3074  * Check if the current node is empty
   3075  *
   3076  * Returns 1 if empty, 0 if not and -1 in case of error
   3077  */
   3078 int
   3079 xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
   3080     if ((reader == NULL) || (reader->node == NULL))
   3081 	return(-1);
   3082     if (reader->node->type != XML_ELEMENT_NODE)
   3083 	return(0);
   3084     if (reader->curnode != NULL)
   3085 	return(0);
   3086     if (reader->node->children != NULL)
   3087 	return(0);
   3088     if (reader->state == XML_TEXTREADER_END)
   3089 	return(0);
   3090     if (reader->doc != NULL)
   3091         return(1);
   3092 #ifdef LIBXML_XINCLUDE_ENABLED
   3093     if (reader->in_xinclude > 0)
   3094         return(1);
   3095 #endif
   3096     return((reader->node->extra & NODE_IS_EMPTY) != 0);
   3097 }
   3098 
   3099 /**
   3100  * xmlTextReaderLocalName:
   3101  * @reader:  the xmlTextReaderPtr used
   3102  *
   3103  * The local name of the node.
   3104  *
   3105  * Returns the local name or NULL if not available,
   3106  *   if non NULL it need to be freed by the caller.
   3107  */
   3108 xmlChar *
   3109 xmlTextReaderLocalName(xmlTextReaderPtr reader) {
   3110     xmlNodePtr node;
   3111     if ((reader == NULL) || (reader->node == NULL))
   3112 	return(NULL);
   3113     if (reader->curnode != NULL)
   3114 	node = reader->curnode;
   3115     else
   3116 	node = reader->node;
   3117     if (node->type == XML_NAMESPACE_DECL) {
   3118 	xmlNsPtr ns = (xmlNsPtr) node;
   3119 	if (ns->prefix == NULL)
   3120 	    return(xmlStrdup(BAD_CAST "xmlns"));
   3121 	else
   3122 	    return(xmlStrdup(ns->prefix));
   3123     }
   3124     if ((node->type != XML_ELEMENT_NODE) &&
   3125 	(node->type != XML_ATTRIBUTE_NODE))
   3126 	return(xmlTextReaderName(reader));
   3127     return(xmlStrdup(node->name));
   3128 }
   3129 
   3130 /**
   3131  * xmlTextReaderConstLocalName:
   3132  * @reader:  the xmlTextReaderPtr used
   3133  *
   3134  * The local name of the node.
   3135  *
   3136  * Returns the local name or NULL if not available, the
   3137  *         string will be deallocated with the reader.
   3138  */
   3139 const xmlChar *
   3140 xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
   3141     xmlNodePtr node;
   3142     if ((reader == NULL) || (reader->node == NULL))
   3143 	return(NULL);
   3144     if (reader->curnode != NULL)
   3145 	node = reader->curnode;
   3146     else
   3147 	node = reader->node;
   3148     if (node->type == XML_NAMESPACE_DECL) {
   3149 	xmlNsPtr ns = (xmlNsPtr) node;
   3150 	if (ns->prefix == NULL)
   3151 	    return(CONSTSTR(BAD_CAST "xmlns"));
   3152 	else
   3153 	    return(ns->prefix);
   3154     }
   3155     if ((node->type != XML_ELEMENT_NODE) &&
   3156 	(node->type != XML_ATTRIBUTE_NODE))
   3157 	return(xmlTextReaderConstName(reader));
   3158     return(node->name);
   3159 }
   3160 
   3161 /**
   3162  * xmlTextReaderName:
   3163  * @reader:  the xmlTextReaderPtr used
   3164  *
   3165  * The qualified name of the node, equal to Prefix :LocalName.
   3166  *
   3167  * Returns the local name or NULL if not available,
   3168  *   if non NULL it need to be freed by the caller.
   3169  */
   3170 xmlChar *
   3171 xmlTextReaderName(xmlTextReaderPtr reader) {
   3172     xmlNodePtr node;
   3173     xmlChar *ret;
   3174 
   3175     if ((reader == NULL) || (reader->node == NULL))
   3176 	return(NULL);
   3177     if (reader->curnode != NULL)
   3178 	node = reader->curnode;
   3179     else
   3180 	node = reader->node;
   3181     switch (node->type) {
   3182         case XML_ELEMENT_NODE:
   3183         case XML_ATTRIBUTE_NODE:
   3184 	    if ((node->ns == NULL) ||
   3185 		(node->ns->prefix == NULL))
   3186 		return(xmlStrdup(node->name));
   3187 
   3188 	    ret = xmlStrdup(node->ns->prefix);
   3189 	    ret = xmlStrcat(ret, BAD_CAST ":");
   3190 	    ret = xmlStrcat(ret, node->name);
   3191 	    return(ret);
   3192         case XML_TEXT_NODE:
   3193 	    return(xmlStrdup(BAD_CAST "#text"));
   3194         case XML_CDATA_SECTION_NODE:
   3195 	    return(xmlStrdup(BAD_CAST "#cdata-section"));
   3196         case XML_ENTITY_NODE:
   3197         case XML_ENTITY_REF_NODE:
   3198 	    return(xmlStrdup(node->name));
   3199         case XML_PI_NODE:
   3200 	    return(xmlStrdup(node->name));
   3201         case XML_COMMENT_NODE:
   3202 	    return(xmlStrdup(BAD_CAST "#comment"));
   3203         case XML_DOCUMENT_NODE:
   3204         case XML_HTML_DOCUMENT_NODE:
   3205 #ifdef LIBXML_DOCB_ENABLED
   3206         case XML_DOCB_DOCUMENT_NODE:
   3207 #endif
   3208 	    return(xmlStrdup(BAD_CAST "#document"));
   3209         case XML_DOCUMENT_FRAG_NODE:
   3210 	    return(xmlStrdup(BAD_CAST "#document-fragment"));
   3211         case XML_NOTATION_NODE:
   3212 	    return(xmlStrdup(node->name));
   3213         case XML_DOCUMENT_TYPE_NODE:
   3214         case XML_DTD_NODE:
   3215 	    return(xmlStrdup(node->name));
   3216         case XML_NAMESPACE_DECL: {
   3217 	    xmlNsPtr ns = (xmlNsPtr) node;
   3218 
   3219 	    ret = xmlStrdup(BAD_CAST "xmlns");
   3220 	    if (ns->prefix == NULL)
   3221 		return(ret);
   3222 	    ret = xmlStrcat(ret, BAD_CAST ":");
   3223 	    ret = xmlStrcat(ret, ns->prefix);
   3224 	    return(ret);
   3225 	}
   3226 
   3227         case XML_ELEMENT_DECL:
   3228         case XML_ATTRIBUTE_DECL:
   3229         case XML_ENTITY_DECL:
   3230         case XML_XINCLUDE_START:
   3231         case XML_XINCLUDE_END:
   3232 	    return(NULL);
   3233     }
   3234     return(NULL);
   3235 }
   3236 
   3237 /**
   3238  * xmlTextReaderConstName:
   3239  * @reader:  the xmlTextReaderPtr used
   3240  *
   3241  * The qualified name of the node, equal to Prefix :LocalName.
   3242  *
   3243  * Returns the local name or NULL if not available, the string is
   3244  *         deallocated with the reader.
   3245  */
   3246 const xmlChar *
   3247 xmlTextReaderConstName(xmlTextReaderPtr reader) {
   3248     xmlNodePtr node;
   3249 
   3250     if ((reader == NULL) || (reader->node == NULL))
   3251 	return(NULL);
   3252     if (reader->curnode != NULL)
   3253 	node = reader->curnode;
   3254     else
   3255 	node = reader->node;
   3256     switch (node->type) {
   3257         case XML_ELEMENT_NODE:
   3258         case XML_ATTRIBUTE_NODE:
   3259 	    if ((node->ns == NULL) ||
   3260 		(node->ns->prefix == NULL))
   3261 		return(node->name);
   3262 	    return(CONSTQSTR(node->ns->prefix, node->name));
   3263         case XML_TEXT_NODE:
   3264 	    return(CONSTSTR(BAD_CAST "#text"));
   3265         case XML_CDATA_SECTION_NODE:
   3266 	    return(CONSTSTR(BAD_CAST "#cdata-section"));
   3267         case XML_ENTITY_NODE:
   3268         case XML_ENTITY_REF_NODE:
   3269 	    return(CONSTSTR(node->name));
   3270         case XML_PI_NODE:
   3271 	    return(CONSTSTR(node->name));
   3272         case XML_COMMENT_NODE:
   3273 	    return(CONSTSTR(BAD_CAST "#comment"));
   3274         case XML_DOCUMENT_NODE:
   3275         case XML_HTML_DOCUMENT_NODE:
   3276 #ifdef LIBXML_DOCB_ENABLED
   3277         case XML_DOCB_DOCUMENT_NODE:
   3278 #endif
   3279 	    return(CONSTSTR(BAD_CAST "#document"));
   3280         case XML_DOCUMENT_FRAG_NODE:
   3281 	    return(CONSTSTR(BAD_CAST "#document-fragment"));
   3282         case XML_NOTATION_NODE:
   3283 	    return(CONSTSTR(node->name));
   3284         case XML_DOCUMENT_TYPE_NODE:
   3285         case XML_DTD_NODE:
   3286 	    return(CONSTSTR(node->name));
   3287         case XML_NAMESPACE_DECL: {
   3288 	    xmlNsPtr ns = (xmlNsPtr) node;
   3289 
   3290 	    if (ns->prefix == NULL)
   3291 		return(CONSTSTR(BAD_CAST "xmlns"));
   3292 	    return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
   3293 	}
   3294 
   3295         case XML_ELEMENT_DECL:
   3296         case XML_ATTRIBUTE_DECL:
   3297         case XML_ENTITY_DECL:
   3298         case XML_XINCLUDE_START:
   3299         case XML_XINCLUDE_END:
   3300 	    return(NULL);
   3301     }
   3302     return(NULL);
   3303 }
   3304 
   3305 /**
   3306  * xmlTextReaderPrefix:
   3307  * @reader:  the xmlTextReaderPtr used
   3308  *
   3309  * A shorthand reference to the namespace associated with the node.
   3310  *
   3311  * Returns the prefix or NULL if not available,
   3312  *    if non NULL it need to be freed by the caller.
   3313  */
   3314 xmlChar *
   3315 xmlTextReaderPrefix(xmlTextReaderPtr reader) {
   3316     xmlNodePtr node;
   3317     if ((reader == NULL) || (reader->node == NULL))
   3318 	return(NULL);
   3319     if (reader->curnode != NULL)
   3320 	node = reader->curnode;
   3321     else
   3322 	node = reader->node;
   3323     if (node->type == XML_NAMESPACE_DECL) {
   3324 	xmlNsPtr ns = (xmlNsPtr) node;
   3325 	if (ns->prefix == NULL)
   3326 	    return(NULL);
   3327 	return(xmlStrdup(BAD_CAST "xmlns"));
   3328     }
   3329     if ((node->type != XML_ELEMENT_NODE) &&
   3330 	(node->type != XML_ATTRIBUTE_NODE))
   3331 	return(NULL);
   3332     if ((node->ns != NULL) && (node->ns->prefix != NULL))
   3333 	return(xmlStrdup(node->ns->prefix));
   3334     return(NULL);
   3335 }
   3336 
   3337 /**
   3338  * xmlTextReaderConstPrefix:
   3339  * @reader:  the xmlTextReaderPtr used
   3340  *
   3341  * A shorthand reference to the namespace associated with the node.
   3342  *
   3343  * Returns the prefix or NULL if not available, the string is deallocated
   3344  *         with the reader.
   3345  */
   3346 const xmlChar *
   3347 xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
   3348     xmlNodePtr node;
   3349     if ((reader == NULL) || (reader->node == NULL))
   3350 	return(NULL);
   3351     if (reader->curnode != NULL)
   3352 	node = reader->curnode;
   3353     else
   3354 	node = reader->node;
   3355     if (node->type == XML_NAMESPACE_DECL) {
   3356 	xmlNsPtr ns = (xmlNsPtr) node;
   3357 	if (ns->prefix == NULL)
   3358 	    return(NULL);
   3359 	return(CONSTSTR(BAD_CAST "xmlns"));
   3360     }
   3361     if ((node->type != XML_ELEMENT_NODE) &&
   3362 	(node->type != XML_ATTRIBUTE_NODE))
   3363 	return(NULL);
   3364     if ((node->ns != NULL) && (node->ns->prefix != NULL))
   3365 	return(CONSTSTR(node->ns->prefix));
   3366     return(NULL);
   3367 }
   3368 
   3369 /**
   3370  * xmlTextReaderNamespaceUri:
   3371  * @reader:  the xmlTextReaderPtr used
   3372  *
   3373  * The URI defining the namespace associated with the node.
   3374  *
   3375  * Returns the namespace URI or NULL if not available,
   3376  *    if non NULL it need to be freed by the caller.
   3377  */
   3378 xmlChar *
   3379 xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
   3380     xmlNodePtr node;
   3381     if ((reader == NULL) || (reader->node == NULL))
   3382 	return(NULL);
   3383     if (reader->curnode != NULL)
   3384 	node = reader->curnode;
   3385     else
   3386 	node = reader->node;
   3387     if (node->type == XML_NAMESPACE_DECL)
   3388 	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
   3389     if ((node->type != XML_ELEMENT_NODE) &&
   3390 	(node->type != XML_ATTRIBUTE_NODE))
   3391 	return(NULL);
   3392     if (node->ns != NULL)
   3393 	return(xmlStrdup(node->ns->href));
   3394     return(NULL);
   3395 }
   3396 
   3397 /**
   3398  * xmlTextReaderConstNamespaceUri:
   3399  * @reader:  the xmlTextReaderPtr used
   3400  *
   3401  * The URI defining the namespace associated with the node.
   3402  *
   3403  * Returns the namespace URI or NULL if not available, the string
   3404  *         will be deallocated with the reader
   3405  */
   3406 const xmlChar *
   3407 xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
   3408     xmlNodePtr node;
   3409     if ((reader == NULL) || (reader->node == NULL))
   3410 	return(NULL);
   3411     if (reader->curnode != NULL)
   3412 	node = reader->curnode;
   3413     else
   3414 	node = reader->node;
   3415     if (node->type == XML_NAMESPACE_DECL)
   3416 	return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
   3417     if ((node->type != XML_ELEMENT_NODE) &&
   3418 	(node->type != XML_ATTRIBUTE_NODE))
   3419 	return(NULL);
   3420     if (node->ns != NULL)
   3421 	return(CONSTSTR(node->ns->href));
   3422     return(NULL);
   3423 }
   3424 
   3425 /**
   3426  * xmlTextReaderBaseUri:
   3427  * @reader:  the xmlTextReaderPtr used
   3428  *
   3429  * The base URI of the node.
   3430  *
   3431  * Returns the base URI or NULL if not available,
   3432  *    if non NULL it need to be freed by the caller.
   3433  */
   3434 xmlChar *
   3435 xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
   3436     if ((reader == NULL) || (reader->node == NULL))
   3437 	return(NULL);
   3438     return(xmlNodeGetBase(NULL, reader->node));
   3439 }
   3440 
   3441 /**
   3442  * xmlTextReaderConstBaseUri:
   3443  * @reader:  the xmlTextReaderPtr used
   3444  *
   3445  * The base URI of the node.
   3446  *
   3447  * Returns the base URI or NULL if not available, the string
   3448  *         will be deallocated with the reader
   3449  */
   3450 const xmlChar *
   3451 xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
   3452     xmlChar *tmp;
   3453     const xmlChar *ret;
   3454 
   3455     if ((reader == NULL) || (reader->node == NULL))
   3456 	return(NULL);
   3457     tmp = xmlNodeGetBase(NULL, reader->node);
   3458     if (tmp == NULL)
   3459         return(NULL);
   3460     ret = CONSTSTR(tmp);
   3461     xmlFree(tmp);
   3462     return(ret);
   3463 }
   3464 
   3465 /**
   3466  * xmlTextReaderDepth:
   3467  * @reader:  the xmlTextReaderPtr used
   3468  *
   3469  * The depth of the node in the tree.
   3470  *
   3471  * Returns the depth or -1 in case of error
   3472  */
   3473 int
   3474 xmlTextReaderDepth(xmlTextReaderPtr reader) {
   3475     if (reader == NULL)
   3476 	return(-1);
   3477     if (reader->node == NULL)
   3478 	return(0);
   3479 
   3480     if (reader->curnode != NULL) {
   3481 	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
   3482 	    (reader->curnode->type == XML_NAMESPACE_DECL))
   3483 	    return(reader->depth + 1);
   3484 	return(reader->depth + 2);
   3485     }
   3486     return(reader->depth);
   3487 }
   3488 
   3489 /**
   3490  * xmlTextReaderHasAttributes:
   3491  * @reader:  the xmlTextReaderPtr used
   3492  *
   3493  * Whether the node has attributes.
   3494  *
   3495  * Returns 1 if true, 0 if false, and -1 in case or error
   3496  */
   3497 int
   3498 xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
   3499     xmlNodePtr node;
   3500     if (reader == NULL)
   3501 	return(-1);
   3502     if (reader->node == NULL)
   3503 	return(0);
   3504     if (reader->curnode != NULL)
   3505 	node = reader->curnode;
   3506     else
   3507 	node = reader->node;
   3508 
   3509     if ((node->type == XML_ELEMENT_NODE) &&
   3510 	((node->properties != NULL) || (node->nsDef != NULL)))
   3511 	return(1);
   3512     /* TODO: handle the xmlDecl */
   3513     return(0);
   3514 }
   3515 
   3516 /**
   3517  * xmlTextReaderHasValue:
   3518  * @reader:  the xmlTextReaderPtr used
   3519  *
   3520  * Whether the node can have a text value.
   3521  *
   3522  * Returns 1 if true, 0 if false, and -1 in case or error
   3523  */
   3524 int
   3525 xmlTextReaderHasValue(xmlTextReaderPtr reader) {
   3526     xmlNodePtr node;
   3527     if (reader == NULL)
   3528 	return(-1);
   3529     if (reader->node == NULL)
   3530 	return(0);
   3531     if (reader->curnode != NULL)
   3532 	node = reader->curnode;
   3533     else
   3534 	node = reader->node;
   3535 
   3536     switch (node->type) {
   3537         case XML_ATTRIBUTE_NODE:
   3538         case XML_TEXT_NODE:
   3539         case XML_CDATA_SECTION_NODE:
   3540         case XML_PI_NODE:
   3541         case XML_COMMENT_NODE:
   3542         case XML_NAMESPACE_DECL:
   3543 	    return(1);
   3544 	default:
   3545 	    break;
   3546     }
   3547     return(0);
   3548 }
   3549 
   3550 /**
   3551  * xmlTextReaderValue:
   3552  * @reader:  the xmlTextReaderPtr used
   3553  *
   3554  * Provides the text value of the node if present
   3555  *
   3556  * Returns the string or NULL if not available. The result must be deallocated
   3557  *     with xmlFree()
   3558  */
   3559 xmlChar *
   3560 xmlTextReaderValue(xmlTextReaderPtr reader) {
   3561     xmlNodePtr node;
   3562     if (reader == NULL)
   3563 	return(NULL);
   3564     if (reader->node == NULL)
   3565 	return(NULL);
   3566     if (reader->curnode != NULL)
   3567 	node = reader->curnode;
   3568     else
   3569 	node = reader->node;
   3570 
   3571     switch (node->type) {
   3572         case XML_NAMESPACE_DECL:
   3573 	    return(xmlStrdup(((xmlNsPtr) node)->href));
   3574         case XML_ATTRIBUTE_NODE:{
   3575 	    xmlAttrPtr attr = (xmlAttrPtr) node;
   3576 
   3577 	    if (attr->parent != NULL)
   3578 		return (xmlNodeListGetString
   3579 			(attr->parent->doc, attr->children, 1));
   3580 	    else
   3581 		return (xmlNodeListGetString(NULL, attr->children, 1));
   3582 	    break;
   3583 	}
   3584         case XML_TEXT_NODE:
   3585         case XML_CDATA_SECTION_NODE:
   3586         case XML_PI_NODE:
   3587         case XML_COMMENT_NODE:
   3588             if (node->content != NULL)
   3589                 return (xmlStrdup(node->content));
   3590 	default:
   3591 	    break;
   3592     }
   3593     return(NULL);
   3594 }
   3595 
   3596 /**
   3597  * xmlTextReaderConstValue:
   3598  * @reader:  the xmlTextReaderPtr used
   3599  *
   3600  * Provides the text value of the node if present
   3601  *
   3602  * Returns the string or NULL if not available. The result will be
   3603  *     deallocated on the next Read() operation.
   3604  */
   3605 const xmlChar *
   3606 xmlTextReaderConstValue(xmlTextReaderPtr reader) {
   3607     xmlNodePtr node;
   3608     if (reader == NULL)
   3609 	return(NULL);
   3610     if (reader->node == NULL)
   3611 	return(NULL);
   3612     if (reader->curnode != NULL)
   3613 	node = reader->curnode;
   3614     else
   3615 	node = reader->node;
   3616 
   3617     switch (node->type) {
   3618         case XML_NAMESPACE_DECL:
   3619 	    return(((xmlNsPtr) node)->href);
   3620         case XML_ATTRIBUTE_NODE:{
   3621 	    xmlAttrPtr attr = (xmlAttrPtr) node;
   3622 	    const xmlChar *ret;
   3623 
   3624 	    if ((attr->children != NULL) &&
   3625 	        (attr->children->type == XML_TEXT_NODE) &&
   3626 		(attr->children->next == NULL))
   3627 		return(attr->children->content);
   3628 	    else {
   3629 		if (reader->buffer == NULL) {
   3630 		    reader->buffer = xmlBufCreateSize(100);
   3631                     if (reader->buffer == NULL) {
   3632                         xmlGenericError(xmlGenericErrorContext,
   3633                                         "xmlTextReaderSetup : malloc failed\n");
   3634                         return (NULL);
   3635                     }
   3636 		    xmlBufSetAllocationScheme(reader->buffer,
   3637 		                              XML_BUFFER_ALLOC_BOUNDED);
   3638                 } else
   3639                     xmlBufEmpty(reader->buffer);
   3640 	        xmlBufGetNodeContent(reader->buffer, node);
   3641 		ret = xmlBufContent(reader->buffer);
   3642 		if (ret == NULL) {
   3643 		    /* error on the buffer best to reallocate */
   3644 		    xmlBufFree(reader->buffer);
   3645 		    reader->buffer = xmlBufCreateSize(100);
   3646 		    xmlBufSetAllocationScheme(reader->buffer,
   3647 		                              XML_BUFFER_ALLOC_BOUNDED);
   3648 		    ret = BAD_CAST "";
   3649 		}
   3650 		return(ret);
   3651 	    }
   3652 	    break;
   3653 	}
   3654         case XML_TEXT_NODE:
   3655         case XML_CDATA_SECTION_NODE:
   3656         case XML_PI_NODE:
   3657         case XML_COMMENT_NODE:
   3658 	    return(node->content);
   3659 	default:
   3660 	    break;
   3661     }
   3662     return(NULL);
   3663 }
   3664 
   3665 /**
   3666  * xmlTextReaderIsDefault:
   3667  * @reader:  the xmlTextReaderPtr used
   3668  *
   3669  * Whether an Attribute  node was generated from the default value
   3670  * defined in the DTD or schema.
   3671  *
   3672  * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
   3673  */
   3674 int
   3675 xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
   3676     if (reader == NULL)
   3677 	return(-1);
   3678     return(0);
   3679 }
   3680 
   3681 /**
   3682  * xmlTextReaderQuoteChar:
   3683  * @reader:  the xmlTextReaderPtr used
   3684  *
   3685  * The quotation mark character used to enclose the value of an attribute.
   3686  *
   3687  * Returns " or ' and -1 in case of error
   3688  */
   3689 int
   3690 xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
   3691     if (reader == NULL)
   3692 	return(-1);
   3693     /* TODO maybe lookup the attribute value for " first */
   3694     return((int) '"');
   3695 }
   3696 
   3697 /**
   3698  * xmlTextReaderXmlLang:
   3699  * @reader:  the xmlTextReaderPtr used
   3700  *
   3701  * The xml:lang scope within which the node resides.
   3702  *
   3703  * Returns the xml:lang value or NULL if none exists.,
   3704  *    if non NULL it need to be freed by the caller.
   3705  */
   3706 xmlChar *
   3707 xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
   3708     if (reader == NULL)
   3709 	return(NULL);
   3710     if (reader->node == NULL)
   3711 	return(NULL);
   3712     return(xmlNodeGetLang(reader->node));
   3713 }
   3714 
   3715 /**
   3716  * xmlTextReaderConstXmlLang:
   3717  * @reader:  the xmlTextReaderPtr used
   3718  *
   3719  * The xml:lang scope within which the node resides.
   3720  *
   3721  * Returns the xml:lang value or NULL if none exists.
   3722  */
   3723 const xmlChar *
   3724 xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
   3725     xmlChar *tmp;
   3726     const xmlChar *ret;
   3727 
   3728     if (reader == NULL)
   3729 	return(NULL);
   3730     if (reader->node == NULL)
   3731 	return(NULL);
   3732     tmp = xmlNodeGetLang(reader->node);
   3733     if (tmp == NULL)
   3734         return(NULL);
   3735     ret = CONSTSTR(tmp);
   3736     xmlFree(tmp);
   3737     return(ret);
   3738 }
   3739 
   3740 /**
   3741  * xmlTextReaderConstString:
   3742  * @reader:  the xmlTextReaderPtr used
   3743  * @str:  the string to intern.
   3744  *
   3745  * Get an interned string from the reader, allows for example to
   3746  * speedup string name comparisons
   3747  *
   3748  * Returns an interned copy of the string or NULL in case of error. The
   3749  *         string will be deallocated with the reader.
   3750  */
   3751 const xmlChar *
   3752 xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
   3753     if (reader == NULL)
   3754 	return(NULL);
   3755     return(CONSTSTR(str));
   3756 }
   3757 
   3758 /**
   3759  * xmlTextReaderNormalization:
   3760  * @reader:  the xmlTextReaderPtr used
   3761  *
   3762  * The value indicating whether to normalize white space and attribute values.
   3763  * Since attribute value and end of line normalizations are a MUST in the XML
   3764  * specification only the value true is accepted. The broken bahaviour of
   3765  * accepting out of range character entities like &#0; is of course not
   3766  * supported either.
   3767  *
   3768  * Returns 1 or -1 in case of error.
   3769  */
   3770 int
   3771 xmlTextReaderNormalization(xmlTextReaderPtr reader) {
   3772     if (reader == NULL)
   3773 	return(-1);
   3774     return(1);
   3775 }
   3776 
   3777 /************************************************************************
   3778  *									*
   3779  *			Extensions to the base APIs			*
   3780  *									*
   3781  ************************************************************************/
   3782 
   3783 /**
   3784  * xmlTextReaderSetParserProp:
   3785  * @reader:  the xmlTextReaderPtr used
   3786  * @prop:  the xmlParserProperties to set
   3787  * @value:  usually 0 or 1 to (de)activate it
   3788  *
   3789  * Change the parser processing behaviour by changing some of its internal
   3790  * properties. Note that some properties can only be changed before any
   3791  * read has been done.
   3792  *
   3793  * Returns 0 if the call was successful, or -1 in case of error
   3794  */
   3795 int
   3796 xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
   3797     xmlParserProperties p = (xmlParserProperties) prop;
   3798     xmlParserCtxtPtr ctxt;
   3799 
   3800     if ((reader == NULL) || (reader->ctxt == NULL))
   3801 	return(-1);
   3802     ctxt = reader->ctxt;
   3803 
   3804     switch (p) {
   3805         case XML_PARSER_LOADDTD:
   3806 	    if (value != 0) {
   3807 		if (ctxt->loadsubset == 0) {
   3808 		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
   3809 			return(-1);
   3810 		    ctxt->loadsubset = XML_DETECT_IDS;
   3811 		}
   3812 	    } else {
   3813 		ctxt->loadsubset = 0;
   3814 	    }
   3815 	    return(0);
   3816         case XML_PARSER_DEFAULTATTRS:
   3817 	    if (value != 0) {
   3818 		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
   3819 	    } else {
   3820 		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
   3821 		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
   3822 	    }
   3823 	    return(0);
   3824         case XML_PARSER_VALIDATE:
   3825 	    if (value != 0) {
   3826 		ctxt->validate = 1;
   3827 		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
   3828 	    } else {
   3829 		ctxt->validate = 0;
   3830 	    }
   3831 	    return(0);
   3832         case XML_PARSER_SUBST_ENTITIES:
   3833 	    if (value != 0) {
   3834 		ctxt->replaceEntities = 1;
   3835 	    } else {
   3836 		ctxt->replaceEntities = 0;
   3837 	    }
   3838 	    return(0);
   3839     }
   3840     return(-1);
   3841 }
   3842 
   3843 /**
   3844  * xmlTextReaderGetParserProp:
   3845  * @reader:  the xmlTextReaderPtr used
   3846  * @prop:  the xmlParserProperties to get
   3847  *
   3848  * Read the parser internal property.
   3849  *
   3850  * Returns the value, usually 0 or 1, or -1 in case of error.
   3851  */
   3852 int
   3853 xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
   3854     xmlParserProperties p = (xmlParserProperties) prop;
   3855     xmlParserCtxtPtr ctxt;
   3856 
   3857     if ((reader == NULL) || (reader->ctxt == NULL))
   3858 	return(-1);
   3859     ctxt = reader->ctxt;
   3860 
   3861     switch (p) {
   3862         case XML_PARSER_LOADDTD:
   3863 	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
   3864 		return(1);
   3865 	    return(0);
   3866         case XML_PARSER_DEFAULTATTRS:
   3867 	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
   3868 		return(1);
   3869 	    return(0);
   3870         case XML_PARSER_VALIDATE:
   3871 	    return(reader->validate);
   3872 	case XML_PARSER_SUBST_ENTITIES:
   3873 	    return(ctxt->replaceEntities);
   3874     }
   3875     return(-1);
   3876 }
   3877 
   3878 
   3879 /**
   3880  * xmlTextReaderGetParserLineNumber:
   3881  * @reader: the user data (XML reader context)
   3882  *
   3883  * Provide the line number of the current parsing point.
   3884  *
   3885  * Returns an int or 0 if not available
   3886  */
   3887 int
   3888 xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
   3889 {
   3890     if ((reader == NULL) || (reader->ctxt == NULL) ||
   3891         (reader->ctxt->input == NULL)) {
   3892         return (0);
   3893     }
   3894     return (reader->ctxt->input->line);
   3895 }
   3896 
   3897 /**
   3898  * xmlTextReaderGetParserColumnNumber:
   3899  * @reader: the user data (XML reader context)
   3900  *
   3901  * Provide the column number of the current parsing point.
   3902  *
   3903  * Returns an int or 0 if not available
   3904  */
   3905 int
   3906 xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
   3907 {
   3908     if ((reader == NULL) || (reader->ctxt == NULL) ||
   3909         (reader->ctxt->input == NULL)) {
   3910         return (0);
   3911     }
   3912     return (reader->ctxt->input->col);
   3913 }
   3914 
   3915 /**
   3916  * xmlTextReaderCurrentNode:
   3917  * @reader:  the xmlTextReaderPtr used
   3918  *
   3919  * Hacking interface allowing to get the xmlNodePtr correponding to the
   3920  * current node being accessed by the xmlTextReader. This is dangerous
   3921  * because the underlying node may be destroyed on the next Reads.
   3922  *
   3923  * Returns the xmlNodePtr or NULL in case of error.
   3924  */
   3925 xmlNodePtr
   3926 xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
   3927     if (reader == NULL)
   3928 	return(NULL);
   3929 
   3930     if (reader->curnode != NULL)
   3931 	return(reader->curnode);
   3932     return(reader->node);
   3933 }
   3934 
   3935 /**
   3936  * xmlTextReaderPreserve:
   3937  * @reader:  the xmlTextReaderPtr used
   3938  *
   3939  * This tells the XML Reader to preserve the current node.
   3940  * The caller must also use xmlTextReaderCurrentDoc() to
   3941  * keep an handle on the resulting document once parsing has finished
   3942  *
   3943  * Returns the xmlNodePtr or NULL in case of error.
   3944  */
   3945 xmlNodePtr
   3946 xmlTextReaderPreserve(xmlTextReaderPtr reader) {
   3947     xmlNodePtr cur, parent;
   3948 
   3949     if (reader == NULL)
   3950 	return(NULL);
   3951 
   3952     if (reader->curnode != NULL)
   3953         cur = reader->curnode;
   3954     else
   3955         cur = reader->node;
   3956     if (cur == NULL)
   3957         return(NULL);
   3958 
   3959     if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
   3960 	cur->extra |= NODE_IS_PRESERVED;
   3961 	cur->extra |= NODE_IS_SPRESERVED;
   3962     }
   3963     reader->preserves++;
   3964 
   3965     parent = cur->parent;;
   3966     while (parent != NULL) {
   3967         if (parent->type == XML_ELEMENT_NODE)
   3968 	    parent->extra |= NODE_IS_PRESERVED;
   3969 	parent = parent->parent;
   3970     }
   3971     return(cur);
   3972 }
   3973 
   3974 #ifdef LIBXML_PATTERN_ENABLED
   3975 /**
   3976  * xmlTextReaderPreservePattern:
   3977  * @reader:  the xmlTextReaderPtr used
   3978  * @pattern:  an XPath subset pattern
   3979  * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
   3980  *
   3981  * This tells the XML Reader to preserve all nodes matched by the
   3982  * pattern. The caller must also use xmlTextReaderCurrentDoc() to
   3983  * keep an handle on the resulting document once parsing has finished
   3984  *
   3985  * Returns a positive number in case of success and -1 in case of error
   3986  */
   3987 int
   3988 xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
   3989                              const xmlChar **namespaces)
   3990 {
   3991     xmlPatternPtr comp;
   3992 
   3993     if ((reader == NULL) || (pattern == NULL))
   3994 	return(-1);
   3995 
   3996     comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
   3997     if (comp == NULL)
   3998         return(-1);
   3999 
   4000     if (reader->patternMax <= 0) {
   4001 	reader->patternMax = 4;
   4002 	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
   4003 					      sizeof(reader->patternTab[0]));
   4004         if (reader->patternTab == NULL) {
   4005             xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
   4006             return (-1);
   4007         }
   4008     }
   4009     if (reader->patternNr >= reader->patternMax) {
   4010         xmlPatternPtr *tmp;
   4011         reader->patternMax *= 2;
   4012 	tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
   4013                                       reader->patternMax *
   4014                                       sizeof(reader->patternTab[0]));
   4015         if (tmp == NULL) {
   4016             xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
   4017 	    reader->patternMax /= 2;
   4018             return (-1);
   4019         }
   4020 	reader->patternTab = tmp;
   4021     }
   4022     reader->patternTab[reader->patternNr] = comp;
   4023     return(reader->patternNr++);
   4024 }
   4025 #endif
   4026 
   4027 /**
   4028  * xmlTextReaderCurrentDoc:
   4029  * @reader:  the xmlTextReaderPtr used
   4030  *
   4031  * Hacking interface allowing to get the xmlDocPtr correponding to the
   4032  * current document being accessed by the xmlTextReader.
   4033  * NOTE: as a result of this call, the reader will not destroy the
   4034  *       associated XML document and calling xmlFreeDoc() on the result
   4035  *       is needed once the reader parsing has finished.
   4036  *
   4037  * Returns the xmlDocPtr or NULL in case of error.
   4038  */
   4039 xmlDocPtr
   4040 xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
   4041     if (reader == NULL)
   4042 	return(NULL);
   4043     if (reader->doc != NULL)
   4044         return(reader->doc);
   4045     if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
   4046 	return(NULL);
   4047 
   4048     reader->preserve = 1;
   4049     return(reader->ctxt->myDoc);
   4050 }
   4051 
   4052 #ifdef LIBXML_SCHEMAS_ENABLED
   4053 static char *xmlTextReaderBuildMessage(const char *msg, va_list ap);
   4054 
   4055 static void XMLCDECL
   4056 xmlTextReaderValidityError(void *ctxt, const char *msg, ...);
   4057 
   4058 static void XMLCDECL
   4059 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);
   4060 
   4061 static void XMLCDECL
   4062 xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
   4063 {
   4064     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
   4065 
   4066     char *str;
   4067 
   4068     va_list ap;
   4069 
   4070     va_start(ap, msg);
   4071     str = xmlTextReaderBuildMessage(msg, ap);
   4072     if (!reader->errorFunc) {
   4073         xmlTextReaderValidityError(ctx, "%s", str);
   4074     } else {
   4075         reader->errorFunc(reader->errorFuncArg, str,
   4076                           XML_PARSER_SEVERITY_VALIDITY_ERROR,
   4077                           NULL /* locator */ );
   4078     }
   4079     if (str != NULL)
   4080         xmlFree(str);
   4081     va_end(ap);
   4082 }
   4083 
   4084 static void XMLCDECL
   4085 xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
   4086 {
   4087     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
   4088 
   4089     char *str;
   4090 
   4091     va_list ap;
   4092 
   4093     va_start(ap, msg);
   4094     str = xmlTextReaderBuildMessage(msg, ap);
   4095     if (!reader->errorFunc) {
   4096         xmlTextReaderValidityWarning(ctx, "%s", str);
   4097     } else {
   4098         reader->errorFunc(reader->errorFuncArg, str,
   4099                           XML_PARSER_SEVERITY_VALIDITY_WARNING,
   4100                           NULL /* locator */ );
   4101     }
   4102     if (str != NULL)
   4103         xmlFree(str);
   4104     va_end(ap);
   4105 }
   4106 
   4107 static void
   4108   xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
   4109 
   4110 static void
   4111 xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error)
   4112 {
   4113     xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
   4114 
   4115     if (reader->sErrorFunc) {
   4116         reader->sErrorFunc(reader->errorFuncArg, error);
   4117     } else {
   4118         xmlTextReaderStructuredError(reader, error);
   4119     }
   4120 }
   4121 /**
   4122  * xmlTextReaderRelaxNGSetSchema:
   4123  * @reader:  the xmlTextReaderPtr used
   4124  * @schema:  a precompiled RelaxNG schema
   4125  *
   4126  * Use RelaxNG to validate the document as it is processed.
   4127  * Activation is only possible before the first Read().
   4128  * if @schema is NULL, then RelaxNG validation is desactivated.
   4129  @ The @schema should not be freed until the reader is deallocated
   4130  * or its use has been deactivated.
   4131  *
   4132  * Returns 0 in case the RelaxNG validation could be (des)activated and
   4133  *         -1 in case of error.
   4134  */
   4135 int
   4136 xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
   4137     if (reader == NULL)
   4138         return(-1);
   4139     if (schema == NULL) {
   4140         if (reader->rngSchemas != NULL) {
   4141 	    xmlRelaxNGFree(reader->rngSchemas);
   4142 	    reader->rngSchemas = NULL;
   4143 	}
   4144         if (reader->rngValidCtxt != NULL) {
   4145 	    if (! reader->rngPreserveCtxt)
   4146 		xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
   4147 	    reader->rngValidCtxt = NULL;
   4148         }
   4149 	reader->rngPreserveCtxt = 0;
   4150 	return(0);
   4151     }
   4152     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
   4153 	return(-1);
   4154     if (reader->rngSchemas != NULL) {
   4155 	xmlRelaxNGFree(reader->rngSchemas);
   4156 	reader->rngSchemas = NULL;
   4157     }
   4158     if (reader->rngValidCtxt != NULL) {
   4159 	if (! reader->rngPreserveCtxt)
   4160 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
   4161 	reader->rngValidCtxt = NULL;
   4162     }
   4163     reader->rngPreserveCtxt = 0;
   4164     reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
   4165     if (reader->rngValidCtxt == NULL)
   4166         return(-1);
   4167     if (reader->errorFunc != NULL) {
   4168 	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
   4169 			xmlTextReaderValidityErrorRelay,
   4170 			xmlTextReaderValidityWarningRelay,
   4171 			reader);
   4172     }
   4173 	if (reader->sErrorFunc != NULL) {
   4174 		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
   4175 			xmlTextReaderValidityStructuredRelay,
   4176 			reader);
   4177     }
   4178     reader->rngValidErrors = 0;
   4179     reader->rngFullNode = NULL;
   4180     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
   4181     return(0);
   4182 }
   4183 
   4184 /**
   4185  * xmlTextReaderLocator:
   4186  * @ctx: the xmlTextReaderPtr used
   4187  * @file: returned file information
   4188  * @line: returned line information
   4189  *
   4190  * Internal locator function for the readers
   4191  *
   4192  * Returns 0 in case the Schema validation could be (des)activated and
   4193  *         -1 in case of error.
   4194  */
   4195 static int
   4196 xmlTextReaderLocator(void *ctx, const char **file, unsigned long *line) {
   4197     xmlTextReaderPtr reader;
   4198 
   4199     if ((ctx == NULL) || ((file == NULL) && (line == NULL)))
   4200         return(-1);
   4201 
   4202     if (file != NULL)
   4203         *file = NULL;
   4204     if (line != NULL)
   4205         *line = 0;
   4206 
   4207     reader = (xmlTextReaderPtr) ctx;
   4208     if ((reader->ctxt != NULL) && (reader->ctxt->input != NULL)) {
   4209 	if (file != NULL)
   4210 	    *file = reader->ctxt->input->filename;
   4211 	if (line != NULL)
   4212 	    *line = reader->ctxt->input->line;
   4213 	return(0);
   4214     }
   4215     if (reader->node != NULL) {
   4216         long res;
   4217 	int ret = 0;
   4218 
   4219 	if (line != NULL) {
   4220 	    res = xmlGetLineNo(reader->node);
   4221 	    if (res > 0)
   4222 	        *line = (unsigned long) res;
   4223 	    else
   4224                 ret = -1;
   4225 	}
   4226         if (file != NULL) {
   4227 	    xmlDocPtr doc = reader->node->doc;
   4228 	    if ((doc != NULL) && (doc->URL != NULL))
   4229 	        *file = (const char *) doc->URL;
   4230 	    else
   4231                 ret = -1;
   4232 	}
   4233 	return(ret);
   4234     }
   4235     return(-1);
   4236 }
   4237 
   4238 /**
   4239  * xmlTextReaderSetSchema:
   4240  * @reader:  the xmlTextReaderPtr used
   4241  * @schema:  a precompiled Schema schema
   4242  *
   4243  * Use XSD Schema to validate the document as it is processed.
   4244  * Activation is only possible before the first Read().
   4245  * if @schema is NULL, then Schema validation is desactivated.
   4246  @ The @schema should not be freed until the reader is deallocated
   4247  * or its use has been deactivated.
   4248  *
   4249  * Returns 0 in case the Schema validation could be (des)activated and
   4250  *         -1 in case of error.
   4251  */
   4252 int
   4253 xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
   4254     if (reader == NULL)
   4255         return(-1);
   4256     if (schema == NULL) {
   4257 	if (reader->xsdPlug != NULL) {
   4258 	    xmlSchemaSAXUnplug(reader->xsdPlug);
   4259 	    reader->xsdPlug = NULL;
   4260 	}
   4261         if (reader->xsdValidCtxt != NULL) {
   4262 	    if (! reader->xsdPreserveCtxt)
   4263 		xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
   4264 	    reader->xsdValidCtxt = NULL;
   4265         }
   4266 	reader->xsdPreserveCtxt = 0;
   4267         if (reader->xsdSchemas != NULL) {
   4268 	    xmlSchemaFree(reader->xsdSchemas);
   4269 	    reader->xsdSchemas = NULL;
   4270 	}
   4271 	return(0);
   4272     }
   4273     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
   4274 	return(-1);
   4275     if (reader->xsdPlug != NULL) {
   4276 	xmlSchemaSAXUnplug(reader->xsdPlug);
   4277 	reader->xsdPlug = NULL;
   4278     }
   4279     if (reader->xsdValidCtxt != NULL) {
   4280 	if (! reader->xsdPreserveCtxt)
   4281 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
   4282 	reader->xsdValidCtxt = NULL;
   4283     }
   4284     reader->xsdPreserveCtxt = 0;
   4285     if (reader->xsdSchemas != NULL) {
   4286 	xmlSchemaFree(reader->xsdSchemas);
   4287 	reader->xsdSchemas = NULL;
   4288     }
   4289     reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
   4290     if (reader->xsdValidCtxt == NULL) {
   4291 	xmlSchemaFree(reader->xsdSchemas);
   4292 	reader->xsdSchemas = NULL;
   4293         return(-1);
   4294     }
   4295     reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
   4296                                        &(reader->ctxt->sax),
   4297 				       &(reader->ctxt->userData));
   4298     if (reader->xsdPlug == NULL) {
   4299 	xmlSchemaFree(reader->xsdSchemas);
   4300 	reader->xsdSchemas = NULL;
   4301 	xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
   4302 	reader->xsdValidCtxt = NULL;
   4303 	return(-1);
   4304     }
   4305     xmlSchemaValidateSetLocator(reader->xsdValidCtxt,
   4306                                 xmlTextReaderLocator,
   4307 				(void *) reader);
   4308 
   4309     if (reader->errorFunc != NULL) {
   4310 	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
   4311 			xmlTextReaderValidityErrorRelay,
   4312 			xmlTextReaderValidityWarningRelay,
   4313 			reader);
   4314     }
   4315 	if (reader->sErrorFunc != NULL) {
   4316 		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
   4317 			xmlTextReaderValidityStructuredRelay,
   4318 			reader);
   4319     }
   4320     reader->xsdValidErrors = 0;
   4321     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
   4322     return(0);
   4323 }
   4324 
   4325 /**
   4326  * xmlTextReaderRelaxNGValidateInternal:
   4327  * @reader:  the xmlTextReaderPtr used
   4328  * @rng:  the path to a RelaxNG schema or NULL
   4329  * @ctxt: the RelaxNG schema validation context or NULL
   4330  * @options: options (not yet used)
   4331  *
   4332  * Use RelaxNG to validate the document as it is processed.
   4333  * Activation is only possible before the first Read().
   4334  * If both @rng and @ctxt are NULL, then RelaxNG validation is deactivated.
   4335  *
   4336  * Returns 0 in case the RelaxNG validation could be (de)activated and
   4337  *	   -1 in case of error.
   4338  */
   4339 static int
   4340 xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader,
   4341 				     const char *rng,
   4342 				     xmlRelaxNGValidCtxtPtr ctxt,
   4343 				     int options ATTRIBUTE_UNUSED)
   4344 {
   4345     if (reader == NULL)
   4346 	return(-1);
   4347 
   4348     if ((rng != NULL) && (ctxt != NULL))
   4349 	return (-1);
   4350 
   4351     if (((rng != NULL) || (ctxt != NULL)) &&
   4352 	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
   4353 	 (reader->ctxt == NULL)))
   4354 	return(-1);
   4355 
   4356     /* Cleanup previous validation stuff. */
   4357     if (reader->rngValidCtxt != NULL) {
   4358 	if ( !reader->rngPreserveCtxt)
   4359 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
   4360 	reader->rngValidCtxt = NULL;
   4361     }
   4362     reader->rngPreserveCtxt = 0;
   4363     if (reader->rngSchemas != NULL) {
   4364 	xmlRelaxNGFree(reader->rngSchemas);
   4365 	reader->rngSchemas = NULL;
   4366     }
   4367 
   4368     if ((rng == NULL) && (ctxt == NULL)) {
   4369 	/* We just want to deactivate the validation, so get out. */
   4370 	return(0);
   4371     }
   4372 
   4373 
   4374     if (rng != NULL) {
   4375 	xmlRelaxNGParserCtxtPtr pctxt;
   4376 	/* Parse the schema and create validation environment. */
   4377 
   4378 	pctxt = xmlRelaxNGNewParserCtxt(rng);
   4379 	if (reader->errorFunc != NULL) {
   4380 	    xmlRelaxNGSetParserErrors(pctxt,
   4381 		xmlTextReaderValidityErrorRelay,
   4382 		xmlTextReaderValidityWarningRelay,
   4383 		reader);
   4384 	}
   4385 	if (reader->sErrorFunc != NULL) {
   4386 	    xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
   4387 		xmlTextReaderValidityStructuredRelay,
   4388 		reader);
   4389 	}
   4390 	reader->rngSchemas = xmlRelaxNGParse(pctxt);
   4391 	xmlRelaxNGFreeParserCtxt(pctxt);
   4392 	if (reader->rngSchemas == NULL)
   4393 	    return(-1);
   4394 	reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
   4395 	if (reader->rngValidCtxt == NULL) {
   4396 	    xmlRelaxNGFree(reader->rngSchemas);
   4397 	    reader->rngSchemas = NULL;
   4398 	    return(-1);
   4399 	}
   4400     } else {
   4401 	/* Use the given validation context. */
   4402 	reader->rngValidCtxt = ctxt;
   4403 	reader->rngPreserveCtxt = 1;
   4404     }
   4405     /*
   4406     * Redirect the validation context's error channels to use
   4407     * the reader channels.
   4408     * TODO: In case the user provides the validation context we
   4409     *	could make this redirection optional.
   4410     */
   4411     if (reader->errorFunc != NULL) {
   4412 	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
   4413 			 xmlTextReaderValidityErrorRelay,
   4414 			 xmlTextReaderValidityWarningRelay,
   4415 			 reader);
   4416     }
   4417 	if (reader->sErrorFunc != NULL) {
   4418 		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
   4419 			xmlTextReaderValidityStructuredRelay,
   4420 			reader);
   4421     }
   4422     reader->rngValidErrors = 0;
   4423     reader->rngFullNode = NULL;
   4424     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
   4425     return(0);
   4426 }
   4427 
   4428 /**
   4429  * xmlTextReaderSchemaValidateInternal:
   4430  * @reader:  the xmlTextReaderPtr used
   4431  * @xsd:  the path to a W3C XSD schema or NULL
   4432  * @ctxt: the XML Schema validation context or NULL
   4433  * @options: options (not used yet)
   4434  *
   4435  * Validate the document as it is processed using XML Schema.
   4436  * Activation is only possible before the first Read().
   4437  * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
   4438  *
   4439  * Returns 0 in case the schemas validation could be (de)activated and
   4440  *         -1 in case of error.
   4441  */
   4442 static int
   4443 xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
   4444 				    const char *xsd,
   4445 				    xmlSchemaValidCtxtPtr ctxt,
   4446 				    int options ATTRIBUTE_UNUSED)
   4447 {
   4448     if (reader == NULL)
   4449         return(-1);
   4450 
   4451     if ((xsd != NULL) && (ctxt != NULL))
   4452 	return(-1);
   4453 
   4454     if (((xsd != NULL) || (ctxt != NULL)) &&
   4455 	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
   4456         (reader->ctxt == NULL)))
   4457 	return(-1);
   4458 
   4459     /* Cleanup previous validation stuff. */
   4460     if (reader->xsdPlug != NULL) {
   4461 	xmlSchemaSAXUnplug(reader->xsdPlug);
   4462 	reader->xsdPlug = NULL;
   4463     }
   4464     if (reader->xsdValidCtxt != NULL) {
   4465 	if (! reader->xsdPreserveCtxt)
   4466 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
   4467 	reader->xsdValidCtxt = NULL;
   4468     }
   4469     reader->xsdPreserveCtxt = 0;
   4470     if (reader->xsdSchemas != NULL) {
   4471 	xmlSchemaFree(reader->xsdSchemas);
   4472 	reader->xsdSchemas = NULL;
   4473     }
   4474 
   4475     if ((xsd == NULL) && (ctxt == NULL)) {
   4476 	/* We just want to deactivate the validation, so get out. */
   4477 	return(0);
   4478     }
   4479 
   4480     if (xsd != NULL) {
   4481 	xmlSchemaParserCtxtPtr pctxt;
   4482 	/* Parse the schema and create validation environment. */
   4483 	pctxt = xmlSchemaNewParserCtxt(xsd);
   4484 	if (reader->errorFunc != NULL) {
   4485 	    xmlSchemaSetParserErrors(pctxt,
   4486 		xmlTextReaderValidityErrorRelay,
   4487 		xmlTextReaderValidityWarningRelay,
   4488 		reader);
   4489 	}
   4490 	reader->xsdSchemas = xmlSchemaParse(pctxt);
   4491 	xmlSchemaFreeParserCtxt(pctxt);
   4492 	if (reader->xsdSchemas == NULL)
   4493 	    return(-1);
   4494 	reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
   4495 	if (reader->xsdValidCtxt == NULL) {
   4496 	    xmlSchemaFree(reader->xsdSchemas);
   4497 	    reader->xsdSchemas = NULL;
   4498 	    return(-1);
   4499 	}
   4500 	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
   4501 	    &(reader->ctxt->sax),
   4502 	    &(reader->ctxt->userData));
   4503 	if (reader->xsdPlug == NULL) {
   4504 	    xmlSchemaFree(reader->xsdSchemas);
   4505 	    reader->xsdSchemas = NULL;
   4506 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
   4507 	    reader->xsdValidCtxt = NULL;
   4508 	    return(-1);
   4509 	}
   4510     } else {
   4511 	/* Use the given validation context. */
   4512 	reader->xsdValidCtxt = ctxt;
   4513 	reader->xsdPreserveCtxt = 1;
   4514 	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
   4515 	    &(reader->ctxt->sax),
   4516 	    &(reader->ctxt->userData));
   4517 	if (reader->xsdPlug == NULL) {
   4518 	    reader->xsdValidCtxt = NULL;
   4519 	    reader->xsdPreserveCtxt = 0;
   4520 	    return(-1);
   4521 	}
   4522     }
   4523     xmlSchemaValidateSetLocator(reader->xsdValidCtxt,
   4524                                 xmlTextReaderLocator,
   4525 				(void *) reader);
   4526     /*
   4527     * Redirect the validation context's error channels to use
   4528     * the reader channels.
   4529     * TODO: In case the user provides the validation context we
   4530     *   could make this redirection optional.
   4531     */
   4532     if (reader->errorFunc != NULL) {
   4533 	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
   4534 			 xmlTextReaderValidityErrorRelay,
   4535 			 xmlTextReaderValidityWarningRelay,
   4536 			 reader);
   4537     }
   4538 	if (reader->sErrorFunc != NULL) {
   4539 		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
   4540 			xmlTextReaderValidityStructuredRelay,
   4541 			reader);
   4542     }
   4543     reader->xsdValidErrors = 0;
   4544     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
   4545     return(0);
   4546 }
   4547 
   4548 /**
   4549  * xmlTextReaderSchemaValidateCtxt:
   4550  * @reader:  the xmlTextReaderPtr used
   4551  * @ctxt: the XML Schema validation context or NULL
   4552  * @options: options (not used yet)
   4553  *
   4554  * Use W3C XSD schema context to validate the document as it is processed.
   4555  * Activation is only possible before the first Read().
   4556  * If @ctxt is NULL, then XML Schema validation is deactivated.
   4557  *
   4558  * Returns 0 in case the schemas validation could be (de)activated and
   4559  *         -1 in case of error.
   4560  */
   4561 int
   4562 xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
   4563 				    xmlSchemaValidCtxtPtr ctxt,
   4564 				    int options)
   4565 {
   4566     return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
   4567 }
   4568 
   4569 /**
   4570  * xmlTextReaderSchemaValidate:
   4571  * @reader:  the xmlTextReaderPtr used
   4572  * @xsd:  the path to a W3C XSD schema or NULL
   4573  *
   4574  * Use W3C XSD schema to validate the document as it is processed.
   4575  * Activation is only possible before the first Read().
   4576  * If @xsd is NULL, then XML Schema validation is deactivated.
   4577  *
   4578  * Returns 0 in case the schemas validation could be (de)activated and
   4579  *         -1 in case of error.
   4580  */
   4581 int
   4582 xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
   4583 {
   4584     return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
   4585 }
   4586 
   4587 /**
   4588  * xmlTextReaderRelaxNGValidateCtxt:
   4589  * @reader:  the xmlTextReaderPtr used
   4590  * @ctxt: the RelaxNG schema validation context or NULL
   4591  * @options: options (not used yet)
   4592  *
   4593  * Use RelaxNG schema context to validate the document as it is processed.
   4594  * Activation is only possible before the first Read().
   4595  * If @ctxt is NULL, then RelaxNG schema validation is deactivated.
   4596  *
   4597  * Returns 0 in case the schemas validation could be (de)activated and
   4598  *         -1 in case of error.
   4599  */
   4600 int
   4601 xmlTextReaderRelaxNGValidateCtxt(xmlTextReaderPtr reader,
   4602 				 xmlRelaxNGValidCtxtPtr ctxt,
   4603 				 int options)
   4604 {
   4605     return(xmlTextReaderRelaxNGValidateInternal(reader, NULL, ctxt, options));
   4606 }
   4607 
   4608 /**
   4609  * xmlTextReaderRelaxNGValidate:
   4610  * @reader:  the xmlTextReaderPtr used
   4611  * @rng:  the path to a RelaxNG schema or NULL
   4612  *
   4613  * Use RelaxNG schema to validate the document as it is processed.
   4614  * Activation is only possible before the first Read().
   4615  * If @rng is NULL, then RelaxNG schema validation is deactivated.
   4616  *
   4617  * Returns 0 in case the schemas validation could be (de)activated and
   4618  *         -1 in case of error.
   4619  */
   4620 int
   4621 xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng)
   4622 {
   4623     return(xmlTextReaderRelaxNGValidateInternal(reader, rng, NULL, 0));
   4624 }
   4625 
   4626 #endif
   4627 
   4628 /**
   4629  * xmlTextReaderIsNamespaceDecl:
   4630  * @reader: the xmlTextReaderPtr used
   4631  *
   4632  * Determine whether the current node is a namespace declaration
   4633  * rather than a regular attribute.
   4634  *
   4635  * Returns 1 if the current node is a namespace declaration, 0 if it
   4636  * is a regular attribute or other type of node, or -1 in case of
   4637  * error.
   4638  */
   4639 int
   4640 xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
   4641     xmlNodePtr node;
   4642     if (reader == NULL)
   4643 	return(-1);
   4644     if (reader->node == NULL)
   4645 	return(-1);
   4646     if (reader->curnode != NULL)
   4647 	node = reader->curnode;
   4648     else
   4649 	node = reader->node;
   4650 
   4651     if (XML_NAMESPACE_DECL == node->type)
   4652 	return(1);
   4653     else
   4654 	return(0);
   4655 }
   4656 
   4657 /**
   4658  * xmlTextReaderConstXmlVersion:
   4659  * @reader:  the xmlTextReaderPtr used
   4660  *
   4661  * Determine the XML version of the document being read.
   4662  *
   4663  * Returns a string containing the XML version of the document or NULL
   4664  * in case of error.  The string is deallocated with the reader.
   4665  */
   4666 const xmlChar *
   4667 xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
   4668     xmlDocPtr doc = NULL;
   4669     if (reader == NULL)
   4670 	return(NULL);
   4671     if (reader->doc != NULL)
   4672         doc = reader->doc;
   4673     else if (reader->ctxt != NULL)
   4674 	doc = reader->ctxt->myDoc;
   4675     if (doc == NULL)
   4676 	return(NULL);
   4677 
   4678     if (doc->version == NULL)
   4679 	return(NULL);
   4680     else
   4681       return(CONSTSTR(doc->version));
   4682 }
   4683 
   4684 /**
   4685  * xmlTextReaderStandalone:
   4686  * @reader:  the xmlTextReaderPtr used
   4687  *
   4688  * Determine the standalone status of the document being read.
   4689  *
   4690  * Returns 1 if the document was declared to be standalone, 0 if it
   4691  * was declared to be not standalone, or -1 if the document did not
   4692  * specify its standalone status or in case of error.
   4693  */
   4694 int
   4695 xmlTextReaderStandalone(xmlTextReaderPtr reader) {
   4696     xmlDocPtr doc = NULL;
   4697     if (reader == NULL)
   4698 	return(-1);
   4699     if (reader->doc != NULL)
   4700         doc = reader->doc;
   4701     else if (reader->ctxt != NULL)
   4702 	doc = reader->ctxt->myDoc;
   4703     if (doc == NULL)
   4704 	return(-1);
   4705 
   4706     return(doc->standalone);
   4707 }
   4708 
   4709 /************************************************************************
   4710  *									*
   4711  *			Error Handling Extensions                       *
   4712  *									*
   4713  ************************************************************************/
   4714 
   4715 /* helper to build a xmlMalloc'ed string from a format and va_list */
   4716 static char *
   4717 xmlTextReaderBuildMessage(const char *msg, va_list ap) {
   4718     int size = 0;
   4719     int chars;
   4720     char *larger;
   4721     char *str = NULL;
   4722     va_list aq;
   4723 
   4724     while (1) {
   4725         VA_COPY(aq, ap);
   4726         chars = vsnprintf(str, size, msg, aq);
   4727         va_end(aq);
   4728         if (chars < 0) {
   4729 	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
   4730 	    if (str)
   4731 		xmlFree(str);
   4732 	    return NULL;
   4733 	}
   4734 	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
   4735             break;
   4736         if (chars < MAX_ERR_MSG_SIZE)
   4737 	size = chars + 1;
   4738 	else
   4739 		size = MAX_ERR_MSG_SIZE;
   4740         if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
   4741 	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
   4742 	    if (str)
   4743                 xmlFree(str);
   4744             return NULL;
   4745         }
   4746         str = larger;
   4747     }
   4748 
   4749     return str;
   4750 }
   4751 
   4752 /**
   4753  * xmlTextReaderLocatorLineNumber:
   4754  * @locator: the xmlTextReaderLocatorPtr used
   4755  *
   4756  * Obtain the line number for the given locator.
   4757  *
   4758  * Returns the line number or -1 in case of error.
   4759  */
   4760 int
   4761 xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
   4762     /* we know that locator is a xmlParserCtxtPtr */
   4763     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
   4764     int ret = -1;
   4765 
   4766     if (locator == NULL)
   4767         return(-1);
   4768     if (ctx->node != NULL) {
   4769 	ret = xmlGetLineNo(ctx->node);
   4770     }
   4771     else {
   4772 	/* inspired from error.c */
   4773 	xmlParserInputPtr input;
   4774 	input = ctx->input;
   4775 	if ((input->filename == NULL) && (ctx->inputNr > 1))
   4776 	    input = ctx->inputTab[ctx->inputNr - 2];
   4777 	if (input != NULL) {
   4778 	    ret = input->line;
   4779 	}
   4780 	else {
   4781 	    ret = -1;
   4782 	}
   4783     }
   4784 
   4785     return ret;
   4786 }
   4787 
   4788 /**
   4789  * xmlTextReaderLocatorBaseURI:
   4790  * @locator: the xmlTextReaderLocatorPtr used
   4791  *
   4792  * Obtain the base URI for the given locator.
   4793  *
   4794  * Returns the base URI or NULL in case of error,
   4795  *    if non NULL it need to be freed by the caller.
   4796  */
   4797 xmlChar *
   4798 xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
   4799     /* we know that locator is a xmlParserCtxtPtr */
   4800     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
   4801     xmlChar *ret = NULL;
   4802 
   4803     if (locator == NULL)
   4804         return(NULL);
   4805     if (ctx->node != NULL) {
   4806 	ret = xmlNodeGetBase(NULL,ctx->node);
   4807     }
   4808     else {
   4809 	/* inspired from error.c */
   4810 	xmlParserInputPtr input;
   4811 	input = ctx->input;
   4812 	if ((input->filename == NULL) && (ctx->inputNr > 1))
   4813 	    input = ctx->inputTab[ctx->inputNr - 2];
   4814 	if (input != NULL) {
   4815 	    ret = xmlStrdup(BAD_CAST input->filename);
   4816 	}
   4817 	else {
   4818 	    ret = NULL;
   4819 	}
   4820     }
   4821 
   4822     return ret;
   4823 }
   4824 
   4825 static void
   4826 xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
   4827                           char *str)
   4828 {
   4829     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
   4830 
   4831     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
   4832 
   4833     if (str != NULL) {
   4834         if (reader->errorFunc)
   4835             reader->errorFunc(reader->errorFuncArg, str, severity,
   4836                               (xmlTextReaderLocatorPtr) ctx);
   4837         xmlFree(str);
   4838     }
   4839 }
   4840 
   4841 static void
   4842 xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error)
   4843 {
   4844     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
   4845 
   4846     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
   4847 
   4848     if (error && reader->sErrorFunc) {
   4849         reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
   4850     }
   4851 }
   4852 
   4853 static void XMLCDECL
   4854 xmlTextReaderError(void *ctxt, const char *msg, ...)
   4855 {
   4856     va_list ap;
   4857 
   4858     va_start(ap, msg);
   4859     xmlTextReaderGenericError(ctxt,
   4860                               XML_PARSER_SEVERITY_ERROR,
   4861                               xmlTextReaderBuildMessage(msg, ap));
   4862     va_end(ap);
   4863 
   4864 }
   4865 
   4866 static void XMLCDECL
   4867 xmlTextReaderWarning(void *ctxt, const char *msg, ...)
   4868 {
   4869     va_list ap;
   4870 
   4871     va_start(ap, msg);
   4872     xmlTextReaderGenericError(ctxt,
   4873                               XML_PARSER_SEVERITY_WARNING,
   4874                               xmlTextReaderBuildMessage(msg, ap));
   4875     va_end(ap);
   4876 }
   4877 
   4878 static void XMLCDECL
   4879 xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
   4880 {
   4881     va_list ap;
   4882 
   4883     int len = xmlStrlen((const xmlChar *) msg);
   4884 
   4885     if ((len > 1) && (msg[len - 2] != ':')) {
   4886         /*
   4887          * some callbacks only report locator information:
   4888          * skip them (mimicking behaviour in error.c)
   4889          */
   4890         va_start(ap, msg);
   4891         xmlTextReaderGenericError(ctxt,
   4892                                   XML_PARSER_SEVERITY_VALIDITY_ERROR,
   4893                                   xmlTextReaderBuildMessage(msg, ap));
   4894         va_end(ap);
   4895     }
   4896 }
   4897 
   4898 static void XMLCDECL
   4899 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
   4900 {
   4901     va_list ap;
   4902 
   4903     int len = xmlStrlen((const xmlChar *) msg);
   4904 
   4905     if ((len != 0) && (msg[len - 1] != ':')) {
   4906         /*
   4907          * some callbacks only report locator information:
   4908          * skip them (mimicking behaviour in error.c)
   4909          */
   4910         va_start(ap, msg);
   4911         xmlTextReaderGenericError(ctxt,
   4912                                   XML_PARSER_SEVERITY_VALIDITY_WARNING,
   4913                                   xmlTextReaderBuildMessage(msg, ap));
   4914         va_end(ap);
   4915     }
   4916 }
   4917 
   4918 /**
   4919  * xmlTextReaderSetErrorHandler:
   4920  * @reader:  the xmlTextReaderPtr used
   4921  * @f:	the callback function to call on error and warnings
   4922  * @arg:    a user argument to pass to the callback function
   4923  *
   4924  * Register a callback function that will be called on error and warnings.
   4925  *
   4926  * If @f is NULL, the default error and warning handlers are restored.
   4927  */
   4928 void
   4929 xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
   4930                              xmlTextReaderErrorFunc f, void *arg)
   4931 {
   4932     if (f != NULL) {
   4933         reader->ctxt->sax->error = xmlTextReaderError;
   4934         reader->ctxt->sax->serror = NULL;
   4935         reader->ctxt->vctxt.error = xmlTextReaderValidityError;
   4936         reader->ctxt->sax->warning = xmlTextReaderWarning;
   4937         reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
   4938         reader->errorFunc = f;
   4939         reader->sErrorFunc = NULL;
   4940         reader->errorFuncArg = arg;
   4941 #ifdef LIBXML_SCHEMAS_ENABLED
   4942         if (reader->rngValidCtxt) {
   4943             xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
   4944                                      xmlTextReaderValidityErrorRelay,
   4945                                      xmlTextReaderValidityWarningRelay,
   4946                                      reader);
   4947             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
   4948                                                reader);
   4949         }
   4950         if (reader->xsdValidCtxt) {
   4951             xmlSchemaSetValidErrors(reader->xsdValidCtxt,
   4952                                     xmlTextReaderValidityErrorRelay,
   4953                                     xmlTextReaderValidityWarningRelay,
   4954                                     reader);
   4955             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
   4956                                               reader);
   4957         }
   4958 #endif
   4959     } else {
   4960         /* restore defaults */
   4961         reader->ctxt->sax->error = xmlParserError;
   4962         reader->ctxt->vctxt.error = xmlParserValidityError;
   4963         reader->ctxt->sax->warning = xmlParserWarning;
   4964         reader->ctxt->vctxt.warning = xmlParserValidityWarning;
   4965         reader->errorFunc = NULL;
   4966         reader->sErrorFunc = NULL;
   4967         reader->errorFuncArg = NULL;
   4968 #ifdef LIBXML_SCHEMAS_ENABLED
   4969         if (reader->rngValidCtxt) {
   4970             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
   4971                                      reader);
   4972             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
   4973                                                reader);
   4974         }
   4975         if (reader->xsdValidCtxt) {
   4976             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
   4977                                     reader);
   4978             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
   4979                                               reader);
   4980         }
   4981 #endif
   4982     }
   4983 }
   4984 
   4985 /**
   4986 * xmlTextReaderSetStructuredErrorHandler:
   4987  * @reader:  the xmlTextReaderPtr used
   4988  * @f:	the callback function to call on error and warnings
   4989  * @arg:    a user argument to pass to the callback function
   4990  *
   4991  * Register a callback function that will be called on error and warnings.
   4992  *
   4993  * If @f is NULL, the default error and warning handlers are restored.
   4994  */
   4995 void
   4996 xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
   4997                                        xmlStructuredErrorFunc f, void *arg)
   4998 {
   4999     if (f != NULL) {
   5000         reader->ctxt->sax->error = NULL;
   5001         reader->ctxt->sax->serror = xmlTextReaderStructuredError;
   5002         reader->ctxt->vctxt.error = xmlTextReaderValidityError;
   5003         reader->ctxt->sax->warning = xmlTextReaderWarning;
   5004         reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
   5005         reader->sErrorFunc = f;
   5006         reader->errorFunc = NULL;
   5007         reader->errorFuncArg = arg;
   5008 #ifdef LIBXML_SCHEMAS_ENABLED
   5009         if (reader->rngValidCtxt) {
   5010             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
   5011                                      reader);
   5012             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
   5013                                         xmlTextReaderValidityStructuredRelay,
   5014                                                reader);
   5015         }
   5016         if (reader->xsdValidCtxt) {
   5017             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
   5018                                     reader);
   5019             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
   5020                                        xmlTextReaderValidityStructuredRelay,
   5021                                               reader);
   5022         }
   5023 #endif
   5024     } else {
   5025         /* restore defaults */
   5026         reader->ctxt->sax->error = xmlParserError;
   5027         reader->ctxt->sax->serror = NULL;
   5028         reader->ctxt->vctxt.error = xmlParserValidityError;
   5029         reader->ctxt->sax->warning = xmlParserWarning;
   5030         reader->ctxt->vctxt.warning = xmlParserValidityWarning;
   5031         reader->errorFunc = NULL;
   5032         reader->sErrorFunc = NULL;
   5033         reader->errorFuncArg = NULL;
   5034 #ifdef LIBXML_SCHEMAS_ENABLED
   5035         if (reader->rngValidCtxt) {
   5036             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
   5037                                      reader);
   5038             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
   5039                                                reader);
   5040         }
   5041         if (reader->xsdValidCtxt) {
   5042             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
   5043                                     reader);
   5044             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
   5045                                               reader);
   5046         }
   5047 #endif
   5048     }
   5049 }
   5050 
   5051 /**
   5052  * xmlTextReaderIsValid:
   5053  * @reader:  the xmlTextReaderPtr used
   5054  *
   5055  * Retrieve the validity status from the parser context
   5056  *
   5057  * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
   5058  */
   5059 int
   5060 xmlTextReaderIsValid(xmlTextReaderPtr reader)
   5061 {
   5062     if (reader == NULL)
   5063         return (-1);
   5064 #ifdef LIBXML_SCHEMAS_ENABLED
   5065     if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
   5066         return (reader->rngValidErrors == 0);
   5067     if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
   5068         return (reader->xsdValidErrors == 0);
   5069 #endif
   5070     if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
   5071         return (reader->ctxt->valid);
   5072     return (0);
   5073 }
   5074 
   5075 /**
   5076  * xmlTextReaderGetErrorHandler:
   5077  * @reader:  the xmlTextReaderPtr used
   5078  * @f:	the callback function or NULL is no callback has been registered
   5079  * @arg:    a user argument
   5080  *
   5081  * Retrieve the error callback function and user argument.
   5082  */
   5083 void
   5084 xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
   5085                              xmlTextReaderErrorFunc * f, void **arg)
   5086 {
   5087     if (f != NULL)
   5088         *f = reader->errorFunc;
   5089     if (arg != NULL)
   5090         *arg = reader->errorFuncArg;
   5091 }
   5092 /************************************************************************
   5093  *									*
   5094  *	New set (2.6.0) of simpler and more flexible APIs		*
   5095  *									*
   5096  ************************************************************************/
   5097 
   5098 /**
   5099  * xmlTextReaderSetup:
   5100  * @reader:  an XML reader
   5101  * @input: xmlParserInputBufferPtr used to feed the reader, will
   5102  *         be destroyed with it.
   5103  * @URL:  the base URL to use for the document
   5104  * @encoding:  the document encoding, or NULL
   5105  * @options:  a combination of xmlParserOption
   5106  *
   5107  * Setup an XML reader with new options
   5108  *
   5109  * Returns 0 in case of success and -1 in case of error.
   5110  */
   5111 int
   5112 xmlTextReaderSetup(xmlTextReaderPtr reader,
   5113                    xmlParserInputBufferPtr input, const char *URL,
   5114                    const char *encoding, int options)
   5115 {
   5116     if (reader == NULL) {
   5117         if (input != NULL)
   5118 	    xmlFreeParserInputBuffer(input);
   5119         return (-1);
   5120     }
   5121 
   5122     /*
   5123      * we force the generation of compact text nodes on the reader
   5124      * since usr applications should never modify the tree
   5125      */
   5126     options |= XML_PARSE_COMPACT;
   5127 
   5128     reader->doc = NULL;
   5129     reader->entNr = 0;
   5130     reader->parserFlags = options;
   5131     reader->validate = XML_TEXTREADER_NOT_VALIDATE;
   5132     if ((input != NULL) && (reader->input != NULL) &&
   5133         (reader->allocs & XML_TEXTREADER_INPUT)) {
   5134 	xmlFreeParserInputBuffer(reader->input);
   5135 	reader->input = NULL;
   5136 	reader->allocs -= XML_TEXTREADER_INPUT;
   5137     }
   5138     if (input != NULL) {
   5139 	reader->input = input;
   5140 	reader->allocs |= XML_TEXTREADER_INPUT;
   5141     }
   5142     if (reader->buffer == NULL)
   5143         reader->buffer = xmlBufCreateSize(100);
   5144     if (reader->buffer == NULL) {
   5145         xmlGenericError(xmlGenericErrorContext,
   5146                         "xmlTextReaderSetup : malloc failed\n");
   5147         return (-1);
   5148     }
   5149     /* no operation on a reader should require a huge buffer */
   5150     xmlBufSetAllocationScheme(reader->buffer,
   5151 			      XML_BUFFER_ALLOC_BOUNDED);
   5152     if (reader->sax == NULL)
   5153 	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
   5154     if (reader->sax == NULL) {
   5155         xmlGenericError(xmlGenericErrorContext,
   5156                         "xmlTextReaderSetup : malloc failed\n");
   5157         return (-1);
   5158     }
   5159     xmlSAXVersion(reader->sax, 2);
   5160     reader->startElement = reader->sax->startElement;
   5161     reader->sax->startElement = xmlTextReaderStartElement;
   5162     reader->endElement = reader->sax->endElement;
   5163     reader->sax->endElement = xmlTextReaderEndElement;
   5164 #ifdef LIBXML_SAX1_ENABLED
   5165     if (reader->sax->initialized == XML_SAX2_MAGIC) {
   5166 #endif /* LIBXML_SAX1_ENABLED */
   5167         reader->startElementNs = reader->sax->startElementNs;
   5168         reader->sax->startElementNs = xmlTextReaderStartElementNs;
   5169         reader->endElementNs = reader->sax->endElementNs;
   5170         reader->sax->endElementNs = xmlTextReaderEndElementNs;
   5171 #ifdef LIBXML_SAX1_ENABLED
   5172     } else {
   5173         reader->startElementNs = NULL;
   5174         reader->endElementNs = NULL;
   5175     }
   5176 #endif /* LIBXML_SAX1_ENABLED */
   5177     reader->characters = reader->sax->characters;
   5178     reader->sax->characters = xmlTextReaderCharacters;
   5179     reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
   5180     reader->cdataBlock = reader->sax->cdataBlock;
   5181     reader->sax->cdataBlock = xmlTextReaderCDataBlock;
   5182 
   5183     reader->mode = XML_TEXTREADER_MODE_INITIAL;
   5184     reader->node = NULL;
   5185     reader->curnode = NULL;
   5186     if (input != NULL) {
   5187         if (xmlBufUse(reader->input->buffer) < 4) {
   5188             xmlParserInputBufferRead(input, 4);
   5189         }
   5190         if (reader->ctxt == NULL) {
   5191             if (xmlBufUse(reader->input->buffer) >= 4) {
   5192                 reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
   5193 		       (const char *) xmlBufContent(reader->input->buffer),
   5194                                       4, URL);
   5195                 reader->base = 0;
   5196                 reader->cur = 4;
   5197             } else {
   5198                 reader->ctxt =
   5199                     xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
   5200                 reader->base = 0;
   5201                 reader->cur = 0;
   5202             }
   5203         } else {
   5204 	    xmlParserInputPtr inputStream;
   5205 	    xmlParserInputBufferPtr buf;
   5206 	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
   5207 
   5208 	    xmlCtxtReset(reader->ctxt);
   5209 	    buf = xmlAllocParserInputBuffer(enc);
   5210 	    if (buf == NULL) return(-1);
   5211 	    inputStream = xmlNewInputStream(reader->ctxt);
   5212 	    if (inputStream == NULL) {
   5213 		xmlFreeParserInputBuffer(buf);
   5214 		return(-1);
   5215 	    }
   5216 
   5217 	    if (URL == NULL)
   5218 		inputStream->filename = NULL;
   5219 	    else
   5220 		inputStream->filename = (char *)
   5221 		    xmlCanonicPath((const xmlChar *) URL);
   5222 	    inputStream->buf = buf;
   5223             xmlBufResetInput(buf->buffer, inputStream);
   5224 
   5225 	    inputPush(reader->ctxt, inputStream);
   5226 	    reader->cur = 0;
   5227 	}
   5228         if (reader->ctxt == NULL) {
   5229             xmlGenericError(xmlGenericErrorContext,
   5230                             "xmlTextReaderSetup : malloc failed\n");
   5231             return (-1);
   5232         }
   5233     }
   5234     if (reader->dict != NULL) {
   5235         if (reader->ctxt->dict != NULL) {
   5236 	    if (reader->dict != reader->ctxt->dict) {
   5237 		xmlDictFree(reader->dict);
   5238 		reader->dict = reader->ctxt->dict;
   5239 	    }
   5240 	} else {
   5241 	    reader->ctxt->dict = reader->dict;
   5242 	}
   5243     } else {
   5244 	if (reader->ctxt->dict == NULL)
   5245 	    reader->ctxt->dict = xmlDictCreate();
   5246         reader->dict = reader->ctxt->dict;
   5247     }
   5248     reader->ctxt->_private = reader;
   5249     reader->ctxt->linenumbers = 1;
   5250     reader->ctxt->dictNames = 1;
   5251     /*
   5252      * use the parser dictionnary to allocate all elements and attributes names
   5253      */
   5254     reader->ctxt->docdict = 1;
   5255     reader->ctxt->parseMode = XML_PARSE_READER;
   5256 
   5257 #ifdef LIBXML_XINCLUDE_ENABLED
   5258     if (reader->xincctxt != NULL) {
   5259 	xmlXIncludeFreeContext(reader->xincctxt);
   5260 	reader->xincctxt = NULL;
   5261     }
   5262     if (options & XML_PARSE_XINCLUDE) {
   5263         reader->xinclude = 1;
   5264 	reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
   5265 	options -= XML_PARSE_XINCLUDE;
   5266     } else
   5267         reader->xinclude = 0;
   5268     reader->in_xinclude = 0;
   5269 #endif
   5270 #ifdef LIBXML_PATTERN_ENABLED
   5271     if (reader->patternTab == NULL) {
   5272         reader->patternNr = 0;
   5273 	reader->patternMax = 0;
   5274     }
   5275     while (reader->patternNr > 0) {
   5276         reader->patternNr--;
   5277 	if (reader->patternTab[reader->patternNr] != NULL) {
   5278 	    xmlFreePattern(reader->patternTab[reader->patternNr]);
   5279             reader->patternTab[reader->patternNr] = NULL;
   5280 	}
   5281     }
   5282 #endif
   5283 
   5284     if (options & XML_PARSE_DTDVALID)
   5285         reader->validate = XML_TEXTREADER_VALIDATE_DTD;
   5286 
   5287     xmlCtxtUseOptions(reader->ctxt, options);
   5288     if (encoding != NULL) {
   5289         xmlCharEncodingHandlerPtr hdlr;
   5290 
   5291         hdlr = xmlFindCharEncodingHandler(encoding);
   5292         if (hdlr != NULL)
   5293             xmlSwitchToEncoding(reader->ctxt, hdlr);
   5294     }
   5295     if ((URL != NULL) && (reader->ctxt->input != NULL) &&
   5296         (reader->ctxt->input->filename == NULL))
   5297         reader->ctxt->input->filename = (char *)
   5298             xmlStrdup((const xmlChar *) URL);
   5299 
   5300     reader->doc = NULL;
   5301 
   5302     return (0);
   5303 }
   5304 
   5305 /**
   5306  * xmlTextReaderByteConsumed:
   5307  * @reader: an XML reader
   5308  *
   5309  * This function provides the current index of the parser used
   5310  * by the reader, relative to the start of the current entity.
   5311  * This function actually just wraps a call to xmlBytesConsumed()
   5312  * for the parser context associated with the reader.
   5313  * See xmlBytesConsumed() for more information.
   5314  *
   5315  * Returns the index in bytes from the beginning of the entity or -1
   5316  *         in case the index could not be computed.
   5317  */
   5318 long
   5319 xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
   5320     if ((reader == NULL) || (reader->ctxt == NULL))
   5321         return(-1);
   5322     return(xmlByteConsumed(reader->ctxt));
   5323 }
   5324 
   5325 
   5326 /**
   5327  * xmlReaderWalker:
   5328  * @doc:  a preparsed document
   5329  *
   5330  * Create an xmltextReader for a preparsed document.
   5331  *
   5332  * Returns the new reader or NULL in case of error.
   5333  */
   5334 xmlTextReaderPtr
   5335 xmlReaderWalker(xmlDocPtr doc)
   5336 {
   5337     xmlTextReaderPtr ret;
   5338 
   5339     if (doc == NULL)
   5340         return(NULL);
   5341 
   5342     ret = xmlMalloc(sizeof(xmlTextReader));
   5343     if (ret == NULL) {
   5344         xmlGenericError(xmlGenericErrorContext,
   5345 		"xmlNewTextReader : malloc failed\n");
   5346 	return(NULL);
   5347     }
   5348     memset(ret, 0, sizeof(xmlTextReader));
   5349     ret->entNr = 0;
   5350     ret->input = NULL;
   5351     ret->mode = XML_TEXTREADER_MODE_INITIAL;
   5352     ret->node = NULL;
   5353     ret->curnode = NULL;
   5354     ret->base = 0;
   5355     ret->cur = 0;
   5356     ret->allocs = XML_TEXTREADER_CTXT;
   5357     ret->doc = doc;
   5358     ret->state = XML_TEXTREADER_START;
   5359     ret->dict = xmlDictCreate();
   5360     return(ret);
   5361 }
   5362 
   5363 /**
   5364  * xmlReaderForDoc:
   5365  * @cur:  a pointer to a zero terminated string
   5366  * @URL:  the base URL to use for the document
   5367  * @encoding:  the document encoding, or NULL
   5368  * @options:  a combination of xmlParserOption
   5369  *
   5370  * Create an xmltextReader for an XML in-memory document.
   5371  * The parsing flags @options are a combination of xmlParserOption.
   5372  *
   5373  * Returns the new reader or NULL in case of error.
   5374  */
   5375 xmlTextReaderPtr
   5376 xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
   5377                 int options)
   5378 {
   5379     int len;
   5380 
   5381     if (cur == NULL)
   5382         return (NULL);
   5383     len = xmlStrlen(cur);
   5384 
   5385     return (xmlReaderForMemory
   5386             ((const char *) cur, len, URL, encoding, options));
   5387 }
   5388 
   5389 /**
   5390  * xmlReaderForFile:
   5391  * @filename:  a file or URL
   5392  * @encoding:  the document encoding, or NULL
   5393  * @options:  a combination of xmlParserOption
   5394  *
   5395  * parse an XML file from the filesystem or the network.
   5396  * The parsing flags @options are a combination of xmlParserOption.
   5397  *
   5398  * Returns the new reader or NULL in case of error.
   5399  */
   5400 xmlTextReaderPtr
   5401 xmlReaderForFile(const char *filename, const char *encoding, int options)
   5402 {
   5403     xmlTextReaderPtr reader;
   5404 
   5405     reader = xmlNewTextReaderFilename(filename);
   5406     if (reader == NULL)
   5407         return (NULL);
   5408     xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
   5409     return (reader);
   5410 }
   5411 
   5412 /**
   5413  * xmlReaderForMemory:
   5414  * @buffer:  a pointer to a char array
   5415  * @size:  the size of the array
   5416  * @URL:  the base URL to use for the document
   5417  * @encoding:  the document encoding, or NULL
   5418  * @options:  a combination of xmlParserOption
   5419  *
   5420  * Create an xmltextReader for an XML in-memory document.
   5421  * The parsing flags @options are a combination of xmlParserOption.
   5422  *
   5423  * Returns the new reader or NULL in case of error.
   5424  */
   5425 xmlTextReaderPtr
   5426 xmlReaderForMemory(const char *buffer, int size, const char *URL,
   5427                    const char *encoding, int options)
   5428 {
   5429     xmlTextReaderPtr reader;
   5430     xmlParserInputBufferPtr buf;
   5431 
   5432     buf = xmlParserInputBufferCreateStatic(buffer, size,
   5433                                       XML_CHAR_ENCODING_NONE);
   5434     if (buf == NULL) {
   5435         return (NULL);
   5436     }
   5437     reader = xmlNewTextReader(buf, URL);
   5438     if (reader == NULL) {
   5439         xmlFreeParserInputBuffer(buf);
   5440         return (NULL);
   5441     }
   5442     reader->allocs |= XML_TEXTREADER_INPUT;
   5443     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
   5444     return (reader);
   5445 }
   5446 
   5447 /**
   5448  * xmlReaderForFd:
   5449  * @fd:  an open file descriptor
   5450  * @URL:  the base URL to use for the document
   5451  * @encoding:  the document encoding, or NULL
   5452  * @options:  a combination of xmlParserOption
   5453  *
   5454  * Create an xmltextReader for an XML from a file descriptor.
   5455  * The parsing flags @options are a combination of xmlParserOption.
   5456  * NOTE that the file descriptor will not be closed when the
   5457  *      reader is closed or reset.
   5458  *
   5459  * Returns the new reader or NULL in case of error.
   5460  */
   5461 xmlTextReaderPtr
   5462 xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
   5463 {
   5464     xmlTextReaderPtr reader;
   5465     xmlParserInputBufferPtr input;
   5466 
   5467     if (fd < 0)
   5468         return (NULL);
   5469 
   5470     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
   5471     if (input == NULL)
   5472         return (NULL);
   5473     input->closecallback = NULL;
   5474     reader = xmlNewTextReader(input, URL);
   5475     if (reader == NULL) {
   5476         xmlFreeParserInputBuffer(input);
   5477         return (NULL);
   5478     }
   5479     reader->allocs |= XML_TEXTREADER_INPUT;
   5480     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
   5481     return (reader);
   5482 }
   5483 
   5484 /**
   5485  * xmlReaderForIO:
   5486  * @ioread:  an I/O read function
   5487  * @ioclose:  an I/O close function
   5488  * @ioctx:  an I/O handler
   5489  * @URL:  the base URL to use for the document
   5490  * @encoding:  the document encoding, or NULL
   5491  * @options:  a combination of xmlParserOption
   5492  *
   5493  * Create an xmltextReader for an XML document from I/O functions and source.
   5494  * The parsing flags @options are a combination of xmlParserOption.
   5495  *
   5496  * Returns the new reader or NULL in case of error.
   5497  */
   5498 xmlTextReaderPtr
   5499 xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
   5500                void *ioctx, const char *URL, const char *encoding,
   5501                int options)
   5502 {
   5503     xmlTextReaderPtr reader;
   5504     xmlParserInputBufferPtr input;
   5505 
   5506     if (ioread == NULL)
   5507         return (NULL);
   5508 
   5509     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
   5510                                          XML_CHAR_ENCODING_NONE);
   5511     if (input == NULL) {
   5512         if (ioclose != NULL)
   5513             ioclose(ioctx);
   5514         return (NULL);
   5515     }
   5516     reader = xmlNewTextReader(input, URL);
   5517     if (reader == NULL) {
   5518         xmlFreeParserInputBuffer(input);
   5519         return (NULL);
   5520     }
   5521     reader->allocs |= XML_TEXTREADER_INPUT;
   5522     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
   5523     return (reader);
   5524 }
   5525 
   5526 /**
   5527  * xmlReaderNewWalker:
   5528  * @reader:  an XML reader
   5529  * @doc:  a preparsed document
   5530  *
   5531  * Setup an xmltextReader to parse a preparsed XML document.
   5532  * This reuses the existing @reader xmlTextReader.
   5533  *
   5534  * Returns 0 in case of success and -1 in case of error
   5535  */
   5536 int
   5537 xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
   5538 {
   5539     if (doc == NULL)
   5540         return (-1);
   5541     if (reader == NULL)
   5542         return (-1);
   5543 
   5544     if (reader->input != NULL) {
   5545         xmlFreeParserInputBuffer(reader->input);
   5546     }
   5547     if (reader->ctxt != NULL) {
   5548 	xmlCtxtReset(reader->ctxt);
   5549     }
   5550 
   5551     reader->entNr = 0;
   5552     reader->input = NULL;
   5553     reader->mode = XML_TEXTREADER_MODE_INITIAL;
   5554     reader->node = NULL;
   5555     reader->curnode = NULL;
   5556     reader->base = 0;
   5557     reader->cur = 0;
   5558     reader->allocs = XML_TEXTREADER_CTXT;
   5559     reader->doc = doc;
   5560     reader->state = XML_TEXTREADER_START;
   5561     if (reader->dict == NULL) {
   5562         if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
   5563 	    reader->dict = reader->ctxt->dict;
   5564 	else
   5565 	    reader->dict = xmlDictCreate();
   5566     }
   5567     return(0);
   5568 }
   5569 
   5570 /**
   5571  * xmlReaderNewDoc:
   5572  * @reader:  an XML reader
   5573  * @cur:  a pointer to a zero terminated string
   5574  * @URL:  the base URL to use for the document
   5575  * @encoding:  the document encoding, or NULL
   5576  * @options:  a combination of xmlParserOption
   5577  *
   5578  * Setup an xmltextReader to parse an XML in-memory document.
   5579  * The parsing flags @options are a combination of xmlParserOption.
   5580  * This reuses the existing @reader xmlTextReader.
   5581  *
   5582  * Returns 0 in case of success and -1 in case of error
   5583  */
   5584 int
   5585 xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
   5586                 const char *URL, const char *encoding, int options)
   5587 {
   5588 
   5589     int len;
   5590 
   5591     if (cur == NULL)
   5592         return (-1);
   5593     if (reader == NULL)
   5594         return (-1);
   5595 
   5596     len = xmlStrlen(cur);
   5597     return (xmlReaderNewMemory(reader, (const char *)cur, len,
   5598                                URL, encoding, options));
   5599 }
   5600 
   5601 /**
   5602  * xmlReaderNewFile:
   5603  * @reader:  an XML reader
   5604  * @filename:  a file or URL
   5605  * @encoding:  the document encoding, or NULL
   5606  * @options:  a combination of xmlParserOption
   5607  *
   5608  * parse an XML file from the filesystem or the network.
   5609  * The parsing flags @options are a combination of xmlParserOption.
   5610  * This reuses the existing @reader xmlTextReader.
   5611  *
   5612  * Returns 0 in case of success and -1 in case of error
   5613  */
   5614 int
   5615 xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
   5616                  const char *encoding, int options)
   5617 {
   5618     xmlParserInputBufferPtr input;
   5619 
   5620     if (filename == NULL)
   5621         return (-1);
   5622     if (reader == NULL)
   5623         return (-1);
   5624 
   5625     input =
   5626         xmlParserInputBufferCreateFilename(filename,
   5627                                            XML_CHAR_ENCODING_NONE);
   5628     if (input == NULL)
   5629         return (-1);
   5630     return (xmlTextReaderSetup(reader, input, filename, encoding, options));
   5631 }
   5632 
   5633 /**
   5634  * xmlReaderNewMemory:
   5635  * @reader:  an XML reader
   5636  * @buffer:  a pointer to a char array
   5637  * @size:  the size of the array
   5638  * @URL:  the base URL to use for the document
   5639  * @encoding:  the document encoding, or NULL
   5640  * @options:  a combination of xmlParserOption
   5641  *
   5642  * Setup an xmltextReader to parse an XML in-memory document.
   5643  * The parsing flags @options are a combination of xmlParserOption.
   5644  * This reuses the existing @reader xmlTextReader.
   5645  *
   5646  * Returns 0 in case of success and -1 in case of error
   5647  */
   5648 int
   5649 xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
   5650                    const char *URL, const char *encoding, int options)
   5651 {
   5652     xmlParserInputBufferPtr input;
   5653 
   5654     if (reader == NULL)
   5655         return (-1);
   5656     if (buffer == NULL)
   5657         return (-1);
   5658 
   5659     input = xmlParserInputBufferCreateStatic(buffer, size,
   5660                                       XML_CHAR_ENCODING_NONE);
   5661     if (input == NULL) {
   5662         return (-1);
   5663     }
   5664     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
   5665 }
   5666 
   5667 /**
   5668  * xmlReaderNewFd:
   5669  * @reader:  an XML reader
   5670  * @fd:  an open file descriptor
   5671  * @URL:  the base URL to use for the document
   5672  * @encoding:  the document encoding, or NULL
   5673  * @options:  a combination of xmlParserOption
   5674  *
   5675  * Setup an xmltextReader to parse an XML from a file descriptor.
   5676  * NOTE that the file descriptor will not be closed when the
   5677  *      reader is closed or reset.
   5678  * The parsing flags @options are a combination of xmlParserOption.
   5679  * This reuses the existing @reader xmlTextReader.
   5680  *
   5681  * Returns 0 in case of success and -1 in case of error
   5682  */
   5683 int
   5684 xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
   5685                const char *URL, const char *encoding, int options)
   5686 {
   5687     xmlParserInputBufferPtr input;
   5688 
   5689     if (fd < 0)
   5690         return (-1);
   5691     if (reader == NULL)
   5692         return (-1);
   5693 
   5694     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
   5695     if (input == NULL)
   5696         return (-1);
   5697     input->closecallback = NULL;
   5698     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
   5699 }
   5700 
   5701 /**
   5702  * xmlReaderNewIO:
   5703  * @reader:  an XML reader
   5704  * @ioread:  an I/O read function
   5705  * @ioclose:  an I/O close function
   5706  * @ioctx:  an I/O handler
   5707  * @URL:  the base URL to use for the document
   5708  * @encoding:  the document encoding, or NULL
   5709  * @options:  a combination of xmlParserOption
   5710  *
   5711  * Setup an xmltextReader to parse an XML document from I/O functions
   5712  * and source.
   5713  * The parsing flags @options are a combination of xmlParserOption.
   5714  * This reuses the existing @reader xmlTextReader.
   5715  *
   5716  * Returns 0 in case of success and -1 in case of error
   5717  */
   5718 int
   5719 xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
   5720                xmlInputCloseCallback ioclose, void *ioctx,
   5721                const char *URL, const char *encoding, int options)
   5722 {
   5723     xmlParserInputBufferPtr input;
   5724 
   5725     if (ioread == NULL)
   5726         return (-1);
   5727     if (reader == NULL)
   5728         return (-1);
   5729 
   5730     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
   5731                                          XML_CHAR_ENCODING_NONE);
   5732     if (input == NULL) {
   5733         if (ioclose != NULL)
   5734             ioclose(ioctx);
   5735         return (-1);
   5736     }
   5737     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
   5738 }
   5739 
   5740 /************************************************************************
   5741  *									*
   5742  *			Utilities					*
   5743  *									*
   5744  ************************************************************************/
   5745 #ifdef NOT_USED_YET
   5746 
   5747 /**
   5748  * xmlBase64Decode:
   5749  * @in:  the input buffer
   5750  * @inlen:  the size of the input (in), the size read from it (out)
   5751  * @to:  the output buffer
   5752  * @tolen:  the size of the output (in), the size written to (out)
   5753  *
   5754  * Base64 decoder, reads from @in and save in @to
   5755  * TODO: tell jody when this is actually exported
   5756  *
   5757  * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
   5758  *         2 if there wasn't enough space on the output or -1 in case of error.
   5759  */
   5760 static int
   5761 xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
   5762                 unsigned char *to, unsigned long *tolen)
   5763 {
   5764     unsigned long incur;        /* current index in in[] */
   5765 
   5766     unsigned long inblk;        /* last block index in in[] */
   5767 
   5768     unsigned long outcur;       /* current index in out[] */
   5769 
   5770     unsigned long inmax;        /* size of in[] */
   5771 
   5772     unsigned long outmax;       /* size of out[] */
   5773 
   5774     unsigned char cur;          /* the current value read from in[] */
   5775 
   5776     unsigned char intmp[4], outtmp[4];  /* temporary buffers for the convert */
   5777 
   5778     int nbintmp;                /* number of byte in intmp[] */
   5779 
   5780     int is_ignore;              /* cur should be ignored */
   5781 
   5782     int is_end = 0;             /* the end of the base64 was found */
   5783 
   5784     int retval = 1;
   5785 
   5786     int i;
   5787 
   5788     if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
   5789         return (-1);
   5790 
   5791     incur = 0;
   5792     inblk = 0;
   5793     outcur = 0;
   5794     inmax = *inlen;
   5795     outmax = *tolen;
   5796     nbintmp = 0;
   5797 
   5798     while (1) {
   5799         if (incur >= inmax)
   5800             break;
   5801         cur = in[incur++];
   5802         is_ignore = 0;
   5803         if ((cur >= 'A') && (cur <= 'Z'))
   5804             cur = cur - 'A';
   5805         else if ((cur >= 'a') && (cur <= 'z'))
   5806             cur = cur - 'a' + 26;
   5807         else if ((cur >= '0') && (cur <= '9'))
   5808             cur = cur - '0' + 52;
   5809         else if (cur == '+')
   5810             cur = 62;
   5811         else if (cur == '/')
   5812             cur = 63;
   5813         else if (cur == '.')
   5814             cur = 0;
   5815         else if (cur == '=')    /*no op , end of the base64 stream */
   5816             is_end = 1;
   5817         else {
   5818             is_ignore = 1;
   5819             if (nbintmp == 0)
   5820                 inblk = incur;
   5821         }
   5822 
   5823         if (!is_ignore) {
   5824             int nbouttmp = 3;
   5825 
   5826             int is_break = 0;
   5827 
   5828             if (is_end) {
   5829                 if (nbintmp == 0)
   5830                     break;
   5831                 if ((nbintmp == 1) || (nbintmp == 2))
   5832                     nbouttmp = 1;
   5833                 else
   5834                     nbouttmp = 2;
   5835                 nbintmp = 3;
   5836                 is_break = 1;
   5837             }
   5838             intmp[nbintmp++] = cur;
   5839             /*
   5840              * if intmp is full, push the 4byte sequence as a 3 byte
   5841              * sequence out
   5842              */
   5843             if (nbintmp == 4) {
   5844                 nbintmp = 0;
   5845                 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
   5846                 outtmp[1] =
   5847                     ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
   5848                 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
   5849                 if (outcur + 3 >= outmax) {
   5850                     retval = 2;
   5851                     break;
   5852                 }
   5853 
   5854                 for (i = 0; i < nbouttmp; i++)
   5855                     to[outcur++] = outtmp[i];
   5856                 inblk = incur;
   5857             }
   5858 
   5859             if (is_break) {
   5860                 retval = 0;
   5861                 break;
   5862             }
   5863         }
   5864     }
   5865 
   5866     *tolen = outcur;
   5867     *inlen = inblk;
   5868     return (retval);
   5869 }
   5870 
   5871 /*
   5872  * Test routine for the xmlBase64Decode function
   5873  */
   5874 #if 0
   5875 int
   5876 main(int argc, char **argv)
   5877 {
   5878     char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
   5879 
   5880     char output[100];
   5881 
   5882     char output2[100];
   5883 
   5884     char output3[100];
   5885 
   5886     unsigned long inlen = strlen(input);
   5887 
   5888     unsigned long outlen = 100;
   5889 
   5890     int ret;
   5891 
   5892     unsigned long cons, tmp, tmp2, prod;
   5893 
   5894     /*
   5895      * Direct
   5896      */
   5897     ret = xmlBase64Decode(input, &inlen, output, &outlen);
   5898 
   5899     output[outlen] = 0;
   5900     printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen,
   5901            outlen, output)indent: Standard input:179: Error:Unmatched #endif
   5902 ;
   5903 
   5904     /*
   5905      * output chunking
   5906      */
   5907     cons = 0;
   5908     prod = 0;
   5909     while (cons < inlen) {
   5910         tmp = 5;
   5911         tmp2 = inlen - cons;
   5912 
   5913         printf("%ld %ld\n", cons, prod);
   5914         ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
   5915         cons += tmp2;
   5916         prod += tmp;
   5917         printf("%ld %ld\n", cons, prod);
   5918     }
   5919     output2[outlen] = 0;
   5920     printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
   5921            prod, output2);
   5922 
   5923     /*
   5924      * input chunking
   5925      */
   5926     cons = 0;
   5927     prod = 0;
   5928     while (cons < inlen) {
   5929         tmp = 100 - prod;
   5930         tmp2 = inlen - cons;
   5931         if (tmp2 > 5)
   5932             tmp2 = 5;
   5933 
   5934         printf("%ld %ld\n", cons, prod);
   5935         ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
   5936         cons += tmp2;
   5937         prod += tmp;
   5938         printf("%ld %ld\n", cons, prod);
   5939     }
   5940     output3[outlen] = 0;
   5941     printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
   5942            prod, output3);
   5943     return (0);
   5944 
   5945 }
   5946 #endif
   5947 #endif /* NOT_USED_YET */
   5948 #define bottom_xmlreader
   5949 #include "elfgcchack.h"
   5950 #endif /* LIBXML_READER_ENABLED */
   5951