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