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@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
104typedef 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
115typedef 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
122struct _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
201static int xmlTextReaderReadTree(xmlTextReaderPtr reader);
202static 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
221static void xmlTextReaderFreeNode(xmlTextReaderPtr reader, xmlNodePtr cur);
222static 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 */
230static void
231xmlFreeID(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 */
253static int
254xmlTextReaderRemoveID(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 */
285static void
286xmlTextReaderFreeProp(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 */
326static void
327xmlTextReaderFreePropList(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 */
345static void
346xmlTextReaderFreeNodeList(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 */
426static void
427xmlTextReaderFreeNode(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 */
500static void
501xmlTextReaderFreeIDTable(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 */
512static void
513xmlTextReaderFreeDoc(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
561static void
562xmlTextReaderDebug(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 */
597static int
598xmlTextReaderEntPush(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 */
633static xmlNodePtr
634xmlTextReaderEntPop(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 */
658static void
659xmlTextReaderStartElement(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 */
685static void
686xmlTextReaderEndElement(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 */
713static void
714xmlTextReaderStartElementNs(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 */
752static void
753xmlTextReaderEndElementNs(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 */
778static void
779xmlTextReaderCharacters(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 */
800static void
801xmlTextReaderCDataBlock(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 */
823static int
824xmlTextReaderPushData(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 */
942static void
943xmlTextReaderValidatePush(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) {
981printf("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 */
1004static void
1005xmlTextReaderValidateCData(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 */
1033static void
1034xmlTextReaderValidatePop(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 */
1084static void
1085xmlTextReaderValidateEntity(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 */
1181static xmlNodePtr
1182xmlTextReaderGetSuccessor(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 */
1204static int
1205xmlTextReaderDoExpand(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 */
1238static xmlChar *
1239xmlTextReaderCollectSiblings(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 */
1285int
1286xmlTextReaderRead(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
1345get_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
1495node_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);
1610node_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 */
1623int
1624xmlTextReaderReadState(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 */
1640xmlNodePtr
1641xmlTextReaderExpand(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 */
1663int
1664xmlTextReaderNext(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 */
1698xmlChar *
1699xmlTextReaderReadInnerXml(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 */
1744xmlChar *
1745xmlTextReaderReadOuterXml(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 */
1788xmlChar *
1789xmlTextReaderReadString(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 */
1831int
1832xmlTextReaderReadBase64(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 */
1861int
1862xmlTextReaderReadBinHex(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 ************************************************************************/
1883static int
1884xmlTextReaderNextTree(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 */
1957static int
1958xmlTextReaderReadTree(xmlTextReaderPtr reader) {
1959    if (reader->state == XML_TEXTREADER_END)
1960        return(0);
1961
1962next_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
2012found_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 */
2031int
2032xmlTextReaderNextSibling(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 */
2069xmlTextReaderPtr
2070xmlNewTextReader(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 */
2183xmlTextReaderPtr
2184xmlNewTextReaderFilename(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 */
2213void
2214xmlFreeTextReader(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 */
2302int
2303xmlTextReaderClose(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 */
2335xmlChar *
2336xmlTextReaderGetAttributeNo(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 */
2384xmlChar *
2385xmlTextReaderGetAttribute(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 */
2456xmlChar *
2457xmlTextReaderGetAttributeNs(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 */
2506xmlParserInputBufferPtr
2507xmlTextReaderGetRemainder(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 */
2554xmlChar *
2555xmlTextReaderLookupNamespace(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 */
2580int
2581xmlTextReaderMoveToAttributeNo(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 */
2629int
2630xmlTextReaderMoveToAttribute(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    }
2707not_found:
2708    if (localname != NULL)
2709        xmlFree(localname);
2710    if (prefix != NULL)
2711        xmlFree(prefix);
2712    return(0);
2713
2714found:
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 */
2733int
2734xmlTextReaderMoveToAttributeNs(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 */
2792int
2793xmlTextReaderMoveToFirstAttribute(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 */
2821int
2822xmlTextReaderMoveToNextAttribute(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 */
2860int
2861xmlTextReaderMoveToElement(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 */
2885int
2886xmlTextReaderReadAttributeValue(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 */
2928const xmlChar *
2929xmlTextReaderConstEncoding(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 */
2960int
2961xmlTextReaderAttributeCount(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 */
3006int
3007xmlTextReaderNodeType(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 */
3078int
3079xmlTextReaderIsEmptyElement(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 */
3108xmlChar *
3109xmlTextReaderLocalName(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 */
3139const xmlChar *
3140xmlTextReaderConstLocalName(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 */
3170xmlChar *
3171xmlTextReaderName(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 */
3246const xmlChar *
3247xmlTextReaderConstName(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 */
3314xmlChar *
3315xmlTextReaderPrefix(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 */
3346const xmlChar *
3347xmlTextReaderConstPrefix(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 */
3378xmlChar *
3379xmlTextReaderNamespaceUri(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 */
3406const xmlChar *
3407xmlTextReaderConstNamespaceUri(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 */
3434xmlChar *
3435xmlTextReaderBaseUri(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 */
3450const xmlChar *
3451xmlTextReaderConstBaseUri(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 */
3473int
3474xmlTextReaderDepth(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 */
3497int
3498xmlTextReaderHasAttributes(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 */
3524int
3525xmlTextReaderHasValue(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 */
3559xmlChar *
3560xmlTextReaderValue(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 */
3605const xmlChar *
3606xmlTextReaderConstValue(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 */
3674int
3675xmlTextReaderIsDefault(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 */
3689int
3690xmlTextReaderQuoteChar(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 */
3706xmlChar *
3707xmlTextReaderXmlLang(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 */
3723const xmlChar *
3724xmlTextReaderConstXmlLang(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 */
3751const xmlChar *
3752xmlTextReaderConstString(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 */
3770int
3771xmlTextReaderNormalization(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 */
3795int
3796xmlTextReaderSetParserProp(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 */
3852int
3853xmlTextReaderGetParserProp(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 */
3887int
3888xmlTextReaderGetParserLineNumber(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 */
3905int
3906xmlTextReaderGetParserColumnNumber(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 */
3925xmlNodePtr
3926xmlTextReaderCurrentNode(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 */
3945xmlNodePtr
3946xmlTextReaderPreserve(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 */
3987int
3988xmlTextReaderPreservePattern(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 */
4039xmlDocPtr
4040xmlTextReaderCurrentDoc(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
4053static char *xmlTextReaderBuildMessage(const char *msg, va_list ap);
4054
4055static void XMLCDECL
4056xmlTextReaderValidityError(void *ctxt, const char *msg, ...);
4057
4058static void XMLCDECL
4059xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);
4060
4061static void XMLCDECL
4062xmlTextReaderValidityErrorRelay(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
4084static void XMLCDECL
4085xmlTextReaderValidityWarningRelay(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
4107static void
4108  xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
4109
4110static void
4111xmlTextReaderValidityStructuredRelay(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 */
4135int
4136xmlTextReaderRelaxNGSetSchema(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 */
4195static int
4196xmlTextReaderLocator(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 */
4252int
4253xmlTextReaderSetSchema(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 */
4339static int
4340xmlTextReaderRelaxNGValidateInternal(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 */
4442static int
4443xmlTextReaderSchemaValidateInternal(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 */
4561int
4562xmlTextReaderSchemaValidateCtxt(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 */
4581int
4582xmlTextReaderSchemaValidate(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 */
4600int
4601xmlTextReaderRelaxNGValidateCtxt(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 */
4620int
4621xmlTextReaderRelaxNGValidate(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 */
4639int
4640xmlTextReaderIsNamespaceDecl(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 */
4666const xmlChar *
4667xmlTextReaderConstXmlVersion(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 */
4694int
4695xmlTextReaderStandalone(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 */
4716static char *
4717xmlTextReaderBuildMessage(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 */
4760int
4761xmlTextReaderLocatorLineNumber(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 */
4797xmlChar *
4798xmlTextReaderLocatorBaseURI(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
4825static void
4826xmlTextReaderGenericError(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
4841static void
4842xmlTextReaderStructuredError(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
4853static void XMLCDECL
4854xmlTextReaderError(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
4866static void XMLCDECL
4867xmlTextReaderWarning(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
4878static void XMLCDECL
4879xmlTextReaderValidityError(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
4898static void XMLCDECL
4899xmlTextReaderValidityWarning(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 */
4928void
4929xmlTextReaderSetErrorHandler(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 */
4995void
4996xmlTextReaderSetStructuredErrorHandler(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 */
5059int
5060xmlTextReaderIsValid(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 */
5083void
5084xmlTextReaderGetErrorHandler(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 */
5111int
5112xmlTextReaderSetup(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 */
5318long
5319xmlTextReaderByteConsumed(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 */
5334xmlTextReaderPtr
5335xmlReaderWalker(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 */
5375xmlTextReaderPtr
5376xmlReaderForDoc(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 */
5400xmlTextReaderPtr
5401xmlReaderForFile(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 */
5425xmlTextReaderPtr
5426xmlReaderForMemory(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 */
5461xmlTextReaderPtr
5462xmlReaderForFd(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 */
5498xmlTextReaderPtr
5499xmlReaderForIO(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 */
5536int
5537xmlReaderNewWalker(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 */
5584int
5585xmlReaderNewDoc(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 */
5614int
5615xmlReaderNewFile(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 */
5648int
5649xmlReaderNewMemory(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 */
5683int
5684xmlReaderNewFd(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 */
5718int
5719xmlReaderNewIO(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 */
5760static int
5761xmlBase64Decode(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
5875int
5876main(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