xmlreader.c revision 5821806d5e7f356e8fa4b058a389a808ea183019
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	    (reader->entNr == 0)) {
1397	    xmlNodePtr tmp = reader->node->prev;
1398	    if ((tmp->extra & NODE_IS_PRESERVED) == 0) {
1399		xmlUnlinkNode(tmp);
1400		xmlTextReaderFreeNode(reader, tmp);
1401	    }
1402	}
1403
1404	goto node_found;
1405    }
1406    if ((oldstate == XML_TEXTREADER_ELEMENT) &&
1407	(reader->node->type == XML_ELEMENT_NODE) &&
1408	(reader->node->children == NULL) &&
1409	((reader->node->extra & NODE_IS_EMPTY) == 0)) {;
1410	reader->state = XML_TEXTREADER_END;
1411	goto node_found;
1412    }
1413#ifdef LIBXML_REGEXP_ENABLED
1414    if ((reader->validate) && (reader->node->type == XML_ELEMENT_NODE))
1415	xmlTextReaderValidatePop(reader);
1416#endif /* LIBXML_REGEXP_ENABLED */
1417    if ((reader->preserves > 0) &&
1418	(reader->node->extra & NODE_IS_SPRESERVED))
1419	reader->preserves--;
1420    reader->node = reader->node->parent;
1421    if ((reader->node == NULL) ||
1422	(reader->node->type == XML_DOCUMENT_NODE) ||
1423#ifdef LIBXML_DOCB_ENABLED
1424	(reader->node->type == XML_DOCB_DOCUMENT_NODE) ||
1425#endif
1426	(reader->node->type == XML_HTML_DOCUMENT_NODE)) {
1427	if (reader->mode != XML_TEXTREADER_MODE_EOF) {
1428	    val = xmlParseChunk(reader->ctxt, "", 0, 1);
1429	    reader->state = XML_TEXTREADER_DONE;
1430	    if (val != 0)
1431	        return(-1);
1432	}
1433	reader->node = NULL;
1434	reader->depth = -1;
1435
1436	/*
1437	 * Cleanup of the old node
1438	 */
1439	if ((oldnode != NULL) && (reader->preserves == 0) &&
1440#ifdef LIBXML_XINCLUDE_ENABLED
1441	    (reader->in_xinclude == 0) &&
1442#endif
1443	    (reader->entNr == 0) &&
1444	    (oldnode->type != XML_DTD_NODE) &&
1445	    ((oldnode->extra & NODE_IS_PRESERVED) == 0) &&
1446	    (reader->entNr == 0)) {
1447	    xmlUnlinkNode(oldnode);
1448	    xmlTextReaderFreeNode(reader, oldnode);
1449	}
1450
1451	goto node_end;
1452    }
1453    if ((reader->preserves == 0) &&
1454#ifdef LIBXML_XINCLUDE_ENABLED
1455        (reader->in_xinclude == 0) &&
1456#endif
1457	(reader->entNr == 0) &&
1458        (reader->node->last != NULL) &&
1459        ((reader->node->last->extra & NODE_IS_PRESERVED) == 0)) {
1460	xmlNodePtr tmp = reader->node->last;
1461	xmlUnlinkNode(tmp);
1462	xmlTextReaderFreeNode(reader, tmp);
1463    }
1464    reader->depth--;
1465    reader->state = XML_TEXTREADER_BACKTRACK;
1466
1467node_found:
1468    DUMP_READER
1469
1470    /*
1471     * If we are in the middle of a piece of CDATA make sure it's finished
1472     */
1473    if ((reader->node != NULL) &&
1474        (reader->node->next == NULL) &&
1475        ((reader->node->type == XML_TEXT_NODE) ||
1476	 (reader->node->type == XML_CDATA_SECTION_NODE))) {
1477            if (xmlTextReaderExpand(reader) == NULL)
1478	        return -1;
1479    }
1480
1481#ifdef LIBXML_XINCLUDE_ENABLED
1482    /*
1483     * Handle XInclude if asked for
1484     */
1485    if ((reader->xinclude) && (reader->node != NULL) &&
1486	(reader->node->type == XML_ELEMENT_NODE) &&
1487	(reader->node->ns != NULL) &&
1488	((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
1489	 (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
1490	if (reader->xincctxt == NULL) {
1491	    reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
1492	    xmlXIncludeSetFlags(reader->xincctxt,
1493	                        reader->parserFlags & (~XML_PARSE_NOXINCNODE));
1494	}
1495	/*
1496	 * expand that node and process it
1497	 */
1498	if (xmlTextReaderExpand(reader) == NULL)
1499	    return -1;
1500	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
1501    }
1502    if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
1503        reader->in_xinclude++;
1504	goto get_next_node;
1505    }
1506    if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) {
1507        reader->in_xinclude--;
1508	goto get_next_node;
1509    }
1510#endif
1511    /*
1512     * Handle entities enter and exit when in entity replacement mode
1513     */
1514    if ((reader->node != NULL) &&
1515	(reader->node->type == XML_ENTITY_REF_NODE) &&
1516	(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
1517	/*
1518	 * Case where the underlying tree is not availble, lookup the entity
1519	 * and walk it.
1520	 */
1521	if ((reader->node->children == NULL) && (reader->ctxt->sax != NULL) &&
1522	    (reader->ctxt->sax->getEntity != NULL)) {
1523	    reader->node->children = (xmlNodePtr)
1524		reader->ctxt->sax->getEntity(reader->ctxt, reader->node->name);
1525	}
1526
1527	if ((reader->node->children != NULL) &&
1528	    (reader->node->children->type == XML_ENTITY_DECL) &&
1529	    (reader->node->children->children != NULL)) {
1530	    xmlTextReaderEntPush(reader, reader->node);
1531	    reader->node = reader->node->children->children;
1532	}
1533#ifdef LIBXML_REGEXP_ENABLED
1534    } else if ((reader->node != NULL) &&
1535	       (reader->node->type == XML_ENTITY_REF_NODE) &&
1536	       (reader->ctxt != NULL) && (reader->validate)) {
1537	xmlTextReaderValidateEntity(reader);
1538#endif /* LIBXML_REGEXP_ENABLED */
1539    }
1540    if ((reader->node != NULL) &&
1541	(reader->node->type == XML_ENTITY_DECL) &&
1542	(reader->ent != NULL) && (reader->ent->children == reader->node)) {
1543	reader->node = xmlTextReaderEntPop(reader);
1544	reader->depth++;
1545        goto get_next_node;
1546    }
1547#ifdef LIBXML_REGEXP_ENABLED
1548    if ((reader->validate) && (reader->node != NULL)) {
1549	xmlNodePtr node = reader->node;
1550
1551	if ((node->type == XML_ELEMENT_NODE) &&
1552            ((reader->state != XML_TEXTREADER_END) &&
1553	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
1554	    xmlTextReaderValidatePush(reader);
1555	} else if ((node->type == XML_TEXT_NODE) ||
1556		   (node->type == XML_CDATA_SECTION_NODE)) {
1557            xmlTextReaderValidateCData(reader, node->content,
1558	                               xmlStrlen(node->content));
1559	}
1560    }
1561#endif /* LIBXML_REGEXP_ENABLED */
1562#ifdef LIBXML_PATTERN_ENABLED
1563    if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
1564        (reader->state != XML_TEXTREADER_BACKTRACK)) {
1565        int i;
1566	for (i = 0;i < reader->patternNr;i++) {
1567	     if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
1568	         xmlTextReaderPreserve(reader);
1569		 break;
1570             }
1571	}
1572    }
1573#endif /* LIBXML_PATTERN_ENABLED */
1574#ifdef LIBXML_SCHEMAS_ENABLED
1575    if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) &&
1576        (reader->xsdValidErrors == 0) &&
1577	(reader->xsdValidCtxt != NULL)) {
1578	reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt);
1579    }
1580#endif /* LIBXML_PATTERN_ENABLED */
1581    return(1);
1582node_end:
1583    reader->state = XML_TEXTREADER_DONE;
1584    return(0);
1585}
1586
1587/**
1588 * xmlTextReaderReadState:
1589 * @reader:  the xmlTextReaderPtr used
1590 *
1591 * Gets the read state of the reader.
1592 *
1593 * Returns the state value, or -1 in case of error
1594 */
1595int
1596xmlTextReaderReadState(xmlTextReaderPtr reader) {
1597    if (reader == NULL)
1598	return(-1);
1599    return(reader->mode);
1600}
1601
1602/**
1603 * xmlTextReaderExpand:
1604 * @reader:  the xmlTextReaderPtr used
1605 *
1606 * Reads the contents of the current node and the full subtree. It then makes
1607 * the subtree available until the next xmlTextReaderRead() call
1608 *
1609 * Returns a node pointer valid until the next xmlTextReaderRead() call
1610 *         or NULL in case of error.
1611 */
1612xmlNodePtr
1613xmlTextReaderExpand(xmlTextReaderPtr reader) {
1614    if ((reader == NULL) || (reader->node == NULL))
1615        return(NULL);
1616    if (reader->doc != NULL)
1617        return(reader->node);
1618    if (reader->ctxt == NULL)
1619        return(NULL);
1620    if (xmlTextReaderDoExpand(reader) < 0)
1621        return(NULL);
1622    return(reader->node);
1623}
1624
1625/**
1626 * xmlTextReaderNext:
1627 * @reader:  the xmlTextReaderPtr used
1628 *
1629 * Skip to the node following the current one in document order while
1630 * avoiding the subtree if any.
1631 *
1632 * Returns 1 if the node was read successfully, 0 if there is no more
1633 *          nodes to read, or -1 in case of error
1634 */
1635int
1636xmlTextReaderNext(xmlTextReaderPtr reader) {
1637    int ret;
1638    xmlNodePtr cur;
1639
1640    if (reader == NULL)
1641	return(-1);
1642    if (reader->doc != NULL)
1643        return(xmlTextReaderNextTree(reader));
1644    cur = reader->node;
1645    if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1646        return(xmlTextReaderRead(reader));
1647    if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK)
1648        return(xmlTextReaderRead(reader));
1649    if (cur->extra & NODE_IS_EMPTY)
1650        return(xmlTextReaderRead(reader));
1651    do {
1652        ret = xmlTextReaderRead(reader);
1653	if (ret != 1)
1654	    return(ret);
1655    } while (reader->node != cur);
1656    return(xmlTextReaderRead(reader));
1657}
1658
1659#ifdef LIBXML_WRITER_ENABLED
1660/**
1661 * xmlTextReaderReadInnerXml:
1662 * @reader:  the xmlTextReaderPtr used
1663 *
1664 * Reads the contents of the current node, including child nodes and markup.
1665 *
1666 * Returns a string containing the XML content, or NULL if the current node
1667 *         is neither an element nor attribute, or has no child nodes. The
1668 *         string must be deallocated by the caller.
1669 */
1670xmlChar *
1671xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
1672{
1673    xmlChar *resbuf;
1674    xmlNodePtr node, cur_node;
1675    xmlBufferPtr buff, buff2;
1676    xmlDocPtr doc;
1677
1678    if (xmlTextReaderExpand(reader) == NULL) {
1679        return NULL;
1680    }
1681    doc = reader->doc;
1682    buff = xmlBufferCreate();
1683    for (cur_node = reader->node->children; cur_node != NULL;
1684         cur_node = cur_node->next) {
1685        node = xmlDocCopyNode(cur_node, doc, 1);
1686        buff2 = xmlBufferCreate();
1687        if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) {
1688            xmlFreeNode(node);
1689            xmlBufferFree(buff2);
1690            xmlBufferFree(buff);
1691            return NULL;
1692        }
1693        xmlBufferCat(buff, buff2->content);
1694        xmlFreeNode(node);
1695        xmlBufferFree(buff2);
1696    }
1697    resbuf = buff->content;
1698    buff->content = NULL;
1699
1700    xmlBufferFree(buff);
1701    return resbuf;
1702}
1703#endif
1704
1705#ifdef LIBXML_WRITER_ENABLED
1706/**
1707 * xmlTextReaderReadOuterXml:
1708 * @reader:  the xmlTextReaderPtr used
1709 *
1710 * Reads the contents of the current node, including child nodes and markup.
1711 *
1712 * Returns a string containing the XML content, or NULL if the current node
1713 *         is neither an element nor attribute, or has no child nodes. The
1714 *         string must be deallocated by the caller.
1715 */
1716xmlChar *
1717xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
1718{
1719    xmlChar *resbuf;
1720    xmlNodePtr node;
1721    xmlBufferPtr buff;
1722    xmlDocPtr doc;
1723
1724    node = reader->node;
1725    doc = reader->doc;
1726    if (xmlTextReaderExpand(reader) == NULL) {
1727        return NULL;
1728    }
1729    node = xmlDocCopyNode(node, doc, 1);
1730    buff = xmlBufferCreate();
1731    if (xmlNodeDump(buff, doc, node, 0, 0) == -1) {
1732        xmlFreeNode(node);
1733        xmlBufferFree(buff);
1734        return NULL;
1735    }
1736
1737    resbuf = buff->content;
1738    buff->content = NULL;
1739
1740    xmlFreeNode(node);
1741    xmlBufferFree(buff);
1742    return resbuf;
1743}
1744#endif
1745
1746/**
1747 * xmlTextReaderReadString:
1748 * @reader:  the xmlTextReaderPtr used
1749 *
1750 * Reads the contents of an element or a text node as a string.
1751 *
1752 * Returns a string containing the contents of the Element or Text node,
1753 *         or NULL if the reader is positioned on any other type of node.
1754 *         The string must be deallocated by the caller.
1755 */
1756xmlChar *
1757xmlTextReaderReadString(xmlTextReaderPtr reader)
1758{
1759    xmlNodePtr node;
1760
1761    if ((reader == NULL) || (reader->node == NULL))
1762       return(NULL);
1763
1764    node = (reader->curnode != NULL) ? reader->curnode : reader->node;
1765    switch (node->type) {
1766    case XML_TEXT_NODE:
1767       if (node->content != NULL)
1768           return(xmlStrdup(node->content));
1769       break;
1770    case XML_ELEMENT_NODE:
1771	if (xmlTextReaderDoExpand(reader) != -1) {
1772	    return xmlTextReaderCollectSiblings(node->children);
1773	}
1774    case XML_ATTRIBUTE_NODE:
1775	TODO
1776	break;
1777    default:
1778       break;
1779    }
1780    return(NULL);
1781}
1782
1783#if 0
1784/**
1785 * xmlTextReaderReadBase64:
1786 * @reader:  the xmlTextReaderPtr used
1787 * @array:  a byte array to store the content.
1788 * @offset:  the zero-based index into array where the method should
1789 *           begin to write.
1790 * @len:  the number of bytes to write.
1791 *
1792 * Reads and decodes the Base64 encoded contents of an element and
1793 * stores the result in a byte buffer.
1794 *
1795 * Returns the number of bytes written to array, or zero if the current
1796 *         instance is not positioned on an element or -1 in case of error.
1797 */
1798int
1799xmlTextReaderReadBase64(xmlTextReaderPtr reader,
1800                        unsigned char *array ATTRIBUTE_UNUSED,
1801	                int offset ATTRIBUTE_UNUSED,
1802			int len ATTRIBUTE_UNUSED) {
1803    if ((reader == NULL) || (reader->ctxt == NULL))
1804	return(-1);
1805    if (reader->ctxt->wellFormed != 1)
1806	return(-1);
1807
1808    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1809	return(0);
1810    TODO
1811    return(0);
1812}
1813
1814/**
1815 * xmlTextReaderReadBinHex:
1816 * @reader:  the xmlTextReaderPtr used
1817 * @array:  a byte array to store the content.
1818 * @offset:  the zero-based index into array where the method should
1819 *           begin to write.
1820 * @len:  the number of bytes to write.
1821 *
1822 * Reads and decodes the BinHex encoded contents of an element and
1823 * stores the result in a byte buffer.
1824 *
1825 * Returns the number of bytes written to array, or zero if the current
1826 *         instance is not positioned on an element or -1 in case of error.
1827 */
1828int
1829xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
1830                        unsigned char *array ATTRIBUTE_UNUSED,
1831	                int offset ATTRIBUTE_UNUSED,
1832			int len ATTRIBUTE_UNUSED) {
1833    if ((reader == NULL) || (reader->ctxt == NULL))
1834	return(-1);
1835    if (reader->ctxt->wellFormed != 1)
1836	return(-1);
1837
1838    if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1839	return(0);
1840    TODO
1841    return(0);
1842}
1843#endif
1844
1845/************************************************************************
1846 *									*
1847 *			Operating on a preparsed tree			*
1848 *									*
1849 ************************************************************************/
1850static int
1851xmlTextReaderNextTree(xmlTextReaderPtr reader)
1852{
1853    if (reader == NULL)
1854        return(-1);
1855
1856    if (reader->state == XML_TEXTREADER_END)
1857        return(0);
1858
1859    if (reader->node == NULL) {
1860        if (reader->doc->children == NULL) {
1861            reader->state = XML_TEXTREADER_END;
1862            return(0);
1863        }
1864
1865        reader->node = reader->doc->children;
1866        reader->state = XML_TEXTREADER_START;
1867        return(1);
1868    }
1869
1870    if (reader->state != XML_TEXTREADER_BACKTRACK) {
1871	/* Here removed traversal to child, because we want to skip the subtree,
1872	replace with traversal to sibling to skip subtree */
1873        if (reader->node->next != 0) {
1874	    /* Move to sibling if present,skipping sub-tree */
1875            reader->node = reader->node->next;
1876            reader->state = XML_TEXTREADER_START;
1877            return(1);
1878        }
1879
1880	/* if reader->node->next is NULL mean no subtree for current node,
1881	so need to move to sibling of parent node if present */
1882        if ((reader->node->type == XML_ELEMENT_NODE) ||
1883            (reader->node->type == XML_ATTRIBUTE_NODE)) {
1884            reader->state = XML_TEXTREADER_BACKTRACK;
1885	    /* This will move to parent if present */
1886            xmlTextReaderRead(reader);
1887        }
1888    }
1889
1890    if (reader->node->next != 0) {
1891        reader->node = reader->node->next;
1892        reader->state = XML_TEXTREADER_START;
1893        return(1);
1894    }
1895
1896    if (reader->node->parent != 0) {
1897        if (reader->node->parent->type == XML_DOCUMENT_NODE) {
1898            reader->state = XML_TEXTREADER_END;
1899            return(0);
1900        }
1901
1902        reader->node = reader->node->parent;
1903        reader->depth--;
1904        reader->state = XML_TEXTREADER_BACKTRACK;
1905	/* Repeat process to move to sibling of parent node if present */
1906        xmlTextReaderNextTree(reader);
1907    }
1908
1909    reader->state = XML_TEXTREADER_END;
1910
1911    return(1);
1912}
1913
1914/**
1915 * xmlTextReaderReadTree:
1916 * @reader:  the xmlTextReaderPtr used
1917 *
1918 *  Moves the position of the current instance to the next node in
1919 *  the stream, exposing its properties.
1920 *
1921 *  Returns 1 if the node was read successfully, 0 if there is no more
1922 *          nodes to read, or -1 in case of error
1923 */
1924static int
1925xmlTextReaderReadTree(xmlTextReaderPtr reader) {
1926    if (reader->state == XML_TEXTREADER_END)
1927        return(0);
1928
1929next_node:
1930    if (reader->node == NULL) {
1931        if (reader->doc->children == NULL) {
1932            reader->state = XML_TEXTREADER_END;
1933            return(0);
1934        }
1935
1936        reader->node = reader->doc->children;
1937        reader->state = XML_TEXTREADER_START;
1938        goto found_node;
1939    }
1940
1941    if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
1942        (reader->node->type != XML_DTD_NODE) &&
1943        (reader->node->type != XML_XINCLUDE_START) &&
1944	(reader->node->type != XML_ENTITY_REF_NODE)) {
1945        if (reader->node->children != NULL) {
1946            reader->node = reader->node->children;
1947            reader->depth++;
1948            reader->state = XML_TEXTREADER_START;
1949            goto found_node;
1950        }
1951
1952        if (reader->node->type == XML_ATTRIBUTE_NODE) {
1953            reader->state = XML_TEXTREADER_BACKTRACK;
1954            goto found_node;
1955        }
1956    }
1957
1958    if (reader->node->next != NULL) {
1959        reader->node = reader->node->next;
1960        reader->state = XML_TEXTREADER_START;
1961        goto found_node;
1962    }
1963
1964    if (reader->node->parent != NULL) {
1965        if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
1966	    (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
1967            reader->state = XML_TEXTREADER_END;
1968            return(0);
1969        }
1970
1971        reader->node = reader->node->parent;
1972        reader->depth--;
1973        reader->state = XML_TEXTREADER_BACKTRACK;
1974        goto found_node;
1975    }
1976
1977    reader->state = XML_TEXTREADER_END;
1978
1979found_node:
1980    if ((reader->node->type == XML_XINCLUDE_START) ||
1981        (reader->node->type == XML_XINCLUDE_END))
1982	goto next_node;
1983
1984    return(1);
1985}
1986
1987/**
1988 * xmlTextReaderNextSibling:
1989 * @reader:  the xmlTextReaderPtr used
1990 *
1991 * Skip to the node following the current one in document order while
1992 * avoiding the subtree if any.
1993 * Currently implemented only for Readers built on a document
1994 *
1995 * Returns 1 if the node was read successfully, 0 if there is no more
1996 *          nodes to read, or -1 in case of error
1997 */
1998int
1999xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
2000    if (reader == NULL)
2001        return(-1);
2002    if (reader->doc == NULL) {
2003        /* TODO */
2004	return(-1);
2005    }
2006
2007    if (reader->state == XML_TEXTREADER_END)
2008        return(0);
2009
2010    if (reader->node == NULL)
2011        return(xmlTextReaderNextTree(reader));
2012
2013    if (reader->node->next != NULL) {
2014        reader->node = reader->node->next;
2015        reader->state = XML_TEXTREADER_START;
2016        return(1);
2017    }
2018
2019    return(0);
2020}
2021
2022/************************************************************************
2023 *									*
2024 *			Constructor and destructors			*
2025 *									*
2026 ************************************************************************/
2027/**
2028 * xmlNewTextReader:
2029 * @input: the xmlParserInputBufferPtr used to read data
2030 * @URI: the URI information for the source if available
2031 *
2032 * Create an xmlTextReader structure fed with @input
2033 *
2034 * Returns the new xmlTextReaderPtr or NULL in case of error
2035 */
2036xmlTextReaderPtr
2037xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
2038    xmlTextReaderPtr ret;
2039
2040    if (input == NULL)
2041	return(NULL);
2042    ret = xmlMalloc(sizeof(xmlTextReader));
2043    if (ret == NULL) {
2044        xmlGenericError(xmlGenericErrorContext,
2045		"xmlNewTextReader : malloc failed\n");
2046	return(NULL);
2047    }
2048    memset(ret, 0, sizeof(xmlTextReader));
2049    ret->doc = NULL;
2050    ret->entTab = NULL;
2051    ret->entMax = 0;
2052    ret->entNr = 0;
2053    ret->input = input;
2054    ret->buffer = xmlBufferCreateSize(100);
2055    if (ret->buffer == NULL) {
2056        xmlFree(ret);
2057        xmlGenericError(xmlGenericErrorContext,
2058		"xmlNewTextReader : malloc failed\n");
2059	return(NULL);
2060    }
2061    ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
2062    if (ret->sax == NULL) {
2063	xmlBufferFree(ret->buffer);
2064	xmlFree(ret);
2065        xmlGenericError(xmlGenericErrorContext,
2066		"xmlNewTextReader : malloc failed\n");
2067	return(NULL);
2068    }
2069    xmlSAXVersion(ret->sax, 2);
2070    ret->startElement = ret->sax->startElement;
2071    ret->sax->startElement = xmlTextReaderStartElement;
2072    ret->endElement = ret->sax->endElement;
2073    ret->sax->endElement = xmlTextReaderEndElement;
2074#ifdef LIBXML_SAX1_ENABLED
2075    if (ret->sax->initialized == XML_SAX2_MAGIC) {
2076#endif /* LIBXML_SAX1_ENABLED */
2077	ret->startElementNs = ret->sax->startElementNs;
2078	ret->sax->startElementNs = xmlTextReaderStartElementNs;
2079	ret->endElementNs = ret->sax->endElementNs;
2080	ret->sax->endElementNs = xmlTextReaderEndElementNs;
2081#ifdef LIBXML_SAX1_ENABLED
2082    } else {
2083	ret->startElementNs = NULL;
2084	ret->endElementNs = NULL;
2085    }
2086#endif /* LIBXML_SAX1_ENABLED */
2087    ret->characters = ret->sax->characters;
2088    ret->sax->characters = xmlTextReaderCharacters;
2089    ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
2090    ret->cdataBlock = ret->sax->cdataBlock;
2091    ret->sax->cdataBlock = xmlTextReaderCDataBlock;
2092
2093    ret->mode = XML_TEXTREADER_MODE_INITIAL;
2094    ret->node = NULL;
2095    ret->curnode = NULL;
2096    if (ret->input->buffer->use < 4) {
2097	xmlParserInputBufferRead(input, 4);
2098    }
2099    if (ret->input->buffer->use >= 4) {
2100	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
2101			(const char *) ret->input->buffer->content, 4, URI);
2102	ret->base = 0;
2103	ret->cur = 4;
2104    } else {
2105	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
2106	ret->base = 0;
2107	ret->cur = 0;
2108    }
2109
2110    if (ret->ctxt == NULL) {
2111        xmlGenericError(xmlGenericErrorContext,
2112		"xmlNewTextReader : malloc failed\n");
2113	xmlBufferFree(ret->buffer);
2114	xmlFree(ret->sax);
2115	xmlFree(ret);
2116	return(NULL);
2117    }
2118    ret->ctxt->parseMode = XML_PARSE_READER;
2119    ret->ctxt->_private = ret;
2120    ret->ctxt->linenumbers = 1;
2121    ret->ctxt->dictNames = 1;
2122    ret->allocs = XML_TEXTREADER_CTXT;
2123    /*
2124     * use the parser dictionnary to allocate all elements and attributes names
2125     */
2126    ret->ctxt->docdict = 1;
2127    ret->dict = ret->ctxt->dict;
2128#ifdef LIBXML_XINCLUDE_ENABLED
2129    ret->xinclude = 0;
2130#endif
2131#ifdef LIBXML_PATTERN_ENABLED
2132    ret->patternMax = 0;
2133    ret->patternTab = NULL;
2134#endif
2135    return(ret);
2136}
2137
2138/**
2139 * xmlNewTextReaderFilename:
2140 * @URI: the URI of the resource to process
2141 *
2142 * Create an xmlTextReader structure fed with the resource at @URI
2143 *
2144 * Returns the new xmlTextReaderPtr or NULL in case of error
2145 */
2146xmlTextReaderPtr
2147xmlNewTextReaderFilename(const char *URI) {
2148    xmlParserInputBufferPtr input;
2149    xmlTextReaderPtr ret;
2150    char *directory = NULL;
2151
2152    input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
2153    if (input == NULL)
2154	return(NULL);
2155    ret = xmlNewTextReader(input, URI);
2156    if (ret == NULL) {
2157	xmlFreeParserInputBuffer(input);
2158	return(NULL);
2159    }
2160    ret->allocs |= XML_TEXTREADER_INPUT;
2161    if (ret->ctxt->directory == NULL)
2162        directory = xmlParserGetDirectory(URI);
2163    if ((ret->ctxt->directory == NULL) && (directory != NULL))
2164        ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
2165    if (directory != NULL)
2166	xmlFree(directory);
2167    return(ret);
2168}
2169
2170/**
2171 * xmlFreeTextReader:
2172 * @reader:  the xmlTextReaderPtr
2173 *
2174 * Deallocate all the resources associated to the reader
2175 */
2176void
2177xmlFreeTextReader(xmlTextReaderPtr reader) {
2178    if (reader == NULL)
2179	return;
2180#ifdef LIBXML_SCHEMAS_ENABLED
2181    if (reader->rngSchemas != NULL) {
2182	xmlRelaxNGFree(reader->rngSchemas);
2183	reader->rngSchemas = NULL;
2184    }
2185    if (reader->rngValidCtxt != NULL) {
2186	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2187	reader->rngValidCtxt = NULL;
2188    }
2189    if (reader->xsdPlug != NULL) {
2190	xmlSchemaSAXUnplug(reader->xsdPlug);
2191	reader->xsdPlug = NULL;
2192    }
2193    if (reader->xsdValidCtxt != NULL) {
2194	if (! reader->xsdPreserveCtxt)
2195	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
2196	reader->xsdValidCtxt = NULL;
2197    }
2198    if (reader->xsdSchemas != NULL) {
2199	xmlSchemaFree(reader->xsdSchemas);
2200	reader->xsdSchemas = NULL;
2201    }
2202#endif
2203#ifdef LIBXML_XINCLUDE_ENABLED
2204    if (reader->xincctxt != NULL)
2205	xmlXIncludeFreeContext(reader->xincctxt);
2206#endif
2207#ifdef LIBXML_PATTERN_ENABLED
2208    if (reader->patternTab != NULL) {
2209        int i;
2210	for (i = 0;i < reader->patternNr;i++) {
2211	    if (reader->patternTab[i] != NULL)
2212	        xmlFreePattern(reader->patternTab[i]);
2213	}
2214	xmlFree(reader->patternTab);
2215    }
2216#endif
2217    if (reader->faketext != NULL) {
2218	xmlFreeNode(reader->faketext);
2219    }
2220    if (reader->ctxt != NULL) {
2221        if (reader->dict == reader->ctxt->dict)
2222	    reader->dict = NULL;
2223	if (reader->ctxt->myDoc != NULL) {
2224	    if (reader->preserve == 0)
2225		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2226	    reader->ctxt->myDoc = NULL;
2227	}
2228	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
2229	    (reader->ctxt->vctxt.vstateMax > 0)){
2230	    xmlFree(reader->ctxt->vctxt.vstateTab);
2231	    reader->ctxt->vctxt.vstateTab = NULL;
2232	    reader->ctxt->vctxt.vstateMax = 0;
2233	}
2234	if (reader->allocs & XML_TEXTREADER_CTXT)
2235	    xmlFreeParserCtxt(reader->ctxt);
2236    }
2237    if (reader->sax != NULL)
2238	xmlFree(reader->sax);
2239    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
2240	xmlFreeParserInputBuffer(reader->input);
2241    if (reader->buffer != NULL)
2242        xmlBufferFree(reader->buffer);
2243    if (reader->entTab != NULL)
2244	xmlFree(reader->entTab);
2245    if (reader->dict != NULL)
2246        xmlDictFree(reader->dict);
2247    xmlFree(reader);
2248}
2249
2250/************************************************************************
2251 *									*
2252 *			Methods for XmlTextReader			*
2253 *									*
2254 ************************************************************************/
2255/**
2256 * xmlTextReaderClose:
2257 * @reader:  the xmlTextReaderPtr used
2258 *
2259 * This method releases any resources allocated by the current instance
2260 * changes the state to Closed and close any underlying input.
2261 *
2262 * Returns 0 or -1 in case of error
2263 */
2264int
2265xmlTextReaderClose(xmlTextReaderPtr reader) {
2266    if (reader == NULL)
2267	return(-1);
2268    reader->node = NULL;
2269    reader->curnode = NULL;
2270    reader->mode = XML_TEXTREADER_MODE_CLOSED;
2271    if (reader->ctxt != NULL) {
2272	xmlStopParser(reader->ctxt);
2273	if (reader->ctxt->myDoc != NULL) {
2274	    if (reader->preserve == 0)
2275		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2276	    reader->ctxt->myDoc = NULL;
2277	}
2278    }
2279    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
2280	xmlFreeParserInputBuffer(reader->input);
2281	reader->allocs -= XML_TEXTREADER_INPUT;
2282    }
2283    return(0);
2284}
2285
2286/**
2287 * xmlTextReaderGetAttributeNo:
2288 * @reader:  the xmlTextReaderPtr used
2289 * @no: the zero-based index of the attribute relative to the containing element
2290 *
2291 * Provides the value of the attribute with the specified index relative
2292 * to the containing element.
2293 *
2294 * Returns a string containing the value of the specified attribute, or NULL
2295 *    in case of error. The string must be deallocated by the caller.
2296 */
2297xmlChar *
2298xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
2299    xmlChar *ret;
2300    int i;
2301    xmlAttrPtr cur;
2302    xmlNsPtr ns;
2303
2304    if (reader == NULL)
2305	return(NULL);
2306    if (reader->node == NULL)
2307	return(NULL);
2308    if (reader->curnode != NULL)
2309	return(NULL);
2310    /* TODO: handle the xmlDecl */
2311    if (reader->node->type != XML_ELEMENT_NODE)
2312	return(NULL);
2313
2314    ns = reader->node->nsDef;
2315    for (i = 0;(i < no) && (ns != NULL);i++) {
2316	ns = ns->next;
2317    }
2318    if (ns != NULL)
2319	return(xmlStrdup(ns->href));
2320
2321    cur = reader->node->properties;
2322    if (cur == NULL)
2323	return(NULL);
2324    for (;i < no;i++) {
2325	cur = cur->next;
2326	if (cur == NULL)
2327	    return(NULL);
2328    }
2329    /* TODO walk the DTD if present */
2330
2331    ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
2332    if (ret == NULL) return(xmlStrdup((xmlChar *)""));
2333    return(ret);
2334}
2335
2336/**
2337 * xmlTextReaderGetAttribute:
2338 * @reader:  the xmlTextReaderPtr used
2339 * @name: the qualified name of the attribute.
2340 *
2341 * Provides the value of the attribute with the specified qualified name.
2342 *
2343 * Returns a string containing the value of the specified attribute, or NULL
2344 *    in case of error. The string must be deallocated by the caller.
2345 */
2346xmlChar *
2347xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2348    xmlChar *prefix = NULL;
2349    xmlChar *localname;
2350    xmlNsPtr ns;
2351    xmlChar *ret = NULL;
2352
2353    if ((reader == NULL) || (name == NULL))
2354	return(NULL);
2355    if (reader->node == NULL)
2356	return(NULL);
2357    if (reader->curnode != NULL)
2358	return(NULL);
2359
2360    /* TODO: handle the xmlDecl */
2361    if (reader->node->type != XML_ELEMENT_NODE)
2362	return(NULL);
2363
2364    localname = xmlSplitQName2(name, &prefix);
2365    if (localname == NULL) {
2366		/*
2367		 * Namespace default decl
2368		 */
2369		if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2370			ns = reader->node->nsDef;
2371			while (ns != NULL) {
2372				if (ns->prefix == NULL) {
2373					return(xmlStrdup(ns->href));
2374				}
2375				ns = ns->next;
2376			}
2377			return NULL;
2378		}
2379		return(xmlGetNoNsProp(reader->node, name));
2380	}
2381
2382    /*
2383     * Namespace default decl
2384     */
2385    if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2386		ns = reader->node->nsDef;
2387		while (ns != NULL) {
2388			if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2389				ret = xmlStrdup(ns->href);
2390				break;
2391			}
2392			ns = ns->next;
2393		}
2394    } else {
2395		ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
2396		if (ns != NULL)
2397			ret = xmlGetNsProp(reader->node, localname, ns->href);
2398	}
2399
2400    xmlFree(localname);
2401    if (prefix != NULL)
2402        xmlFree(prefix);
2403    return(ret);
2404}
2405
2406
2407/**
2408 * xmlTextReaderGetAttributeNs:
2409 * @reader:  the xmlTextReaderPtr used
2410 * @localName: the local name of the attribute.
2411 * @namespaceURI: the namespace URI of the attribute.
2412 *
2413 * Provides the value of the specified attribute
2414 *
2415 * Returns a string containing the value of the specified attribute, or NULL
2416 *    in case of error. The string must be deallocated by the caller.
2417 */
2418xmlChar *
2419xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
2420			    const xmlChar *namespaceURI) {
2421    xmlChar *prefix = NULL;
2422    xmlNsPtr ns;
2423
2424    if ((reader == NULL) || (localName == NULL))
2425	return(NULL);
2426    if (reader->node == NULL)
2427	return(NULL);
2428    if (reader->curnode != NULL)
2429	return(NULL);
2430
2431    /* TODO: handle the xmlDecl */
2432    if (reader->node->type != XML_ELEMENT_NODE)
2433	return(NULL);
2434
2435    if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
2436		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
2437			prefix = BAD_CAST localName;
2438		}
2439		ns = reader->node->nsDef;
2440		while (ns != NULL) {
2441			if ((prefix == NULL && ns->prefix == NULL) ||
2442				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
2443				return xmlStrdup(ns->href);
2444			}
2445			ns = ns->next;
2446		}
2447		return NULL;
2448    }
2449
2450    return(xmlGetNsProp(reader->node, localName, namespaceURI));
2451}
2452
2453/**
2454 * xmlTextReaderGetRemainder:
2455 * @reader:  the xmlTextReaderPtr used
2456 *
2457 * Method to get the remainder of the buffered XML. this method stops the
2458 * parser, set its state to End Of File and return the input stream with
2459 * what is left that the parser did not use.
2460 *
2461 * The implementation is not good, the parser certainly procgressed past
2462 * what's left in reader->input, and there is an allocation problem. Best
2463 * would be to rewrite it differently.
2464 *
2465 * Returns the xmlParserInputBufferPtr attached to the XML or NULL
2466 *    in case of error.
2467 */
2468xmlParserInputBufferPtr
2469xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
2470    xmlParserInputBufferPtr ret = NULL;
2471
2472    if (reader == NULL)
2473	return(NULL);
2474    if (reader->node == NULL)
2475	return(NULL);
2476
2477    reader->node = NULL;
2478    reader->curnode = NULL;
2479    reader->mode = XML_TEXTREADER_MODE_EOF;
2480    if (reader->ctxt != NULL) {
2481	xmlStopParser(reader->ctxt);
2482	if (reader->ctxt->myDoc != NULL) {
2483	    if (reader->preserve == 0)
2484		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2485	    reader->ctxt->myDoc = NULL;
2486	}
2487    }
2488    if (reader->allocs & XML_TEXTREADER_INPUT) {
2489	ret = reader->input;
2490	reader->input = NULL;
2491	reader->allocs -= XML_TEXTREADER_INPUT;
2492    } else {
2493	/*
2494	 * Hum, one may need to duplicate the data structure because
2495	 * without reference counting the input may be freed twice:
2496	 *   - by the layer which allocated it.
2497	 *   - by the layer to which would have been returned to.
2498	 */
2499	TODO
2500	return(NULL);
2501    }
2502    return(ret);
2503}
2504
2505/**
2506 * xmlTextReaderLookupNamespace:
2507 * @reader:  the xmlTextReaderPtr used
2508 * @prefix: the prefix whose namespace URI is to be resolved. To return
2509 *          the default namespace, specify NULL
2510 *
2511 * Resolves a namespace prefix in the scope of the current element.
2512 *
2513 * Returns a string containing the namespace URI to which the prefix maps
2514 *    or NULL in case of error. The string must be deallocated by the caller.
2515 */
2516xmlChar *
2517xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
2518    xmlNsPtr ns;
2519
2520    if (reader == NULL)
2521	return(NULL);
2522    if (reader->node == NULL)
2523	return(NULL);
2524
2525    ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
2526    if (ns == NULL)
2527	return(NULL);
2528    return(xmlStrdup(ns->href));
2529}
2530
2531/**
2532 * xmlTextReaderMoveToAttributeNo:
2533 * @reader:  the xmlTextReaderPtr used
2534 * @no: the zero-based index of the attribute relative to the containing
2535 *      element.
2536 *
2537 * Moves the position of the current instance to the attribute with
2538 * the specified index relative to the containing element.
2539 *
2540 * Returns 1 in case of success, -1 in case of error, 0 if not found
2541 */
2542int
2543xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
2544    int i;
2545    xmlAttrPtr cur;
2546    xmlNsPtr ns;
2547
2548    if (reader == NULL)
2549	return(-1);
2550    if (reader->node == NULL)
2551	return(-1);
2552    /* TODO: handle the xmlDecl */
2553    if (reader->node->type != XML_ELEMENT_NODE)
2554	return(-1);
2555
2556    reader->curnode = NULL;
2557
2558    ns = reader->node->nsDef;
2559    for (i = 0;(i < no) && (ns != NULL);i++) {
2560	ns = ns->next;
2561    }
2562    if (ns != NULL) {
2563	reader->curnode = (xmlNodePtr) ns;
2564	return(1);
2565    }
2566
2567    cur = reader->node->properties;
2568    if (cur == NULL)
2569	return(0);
2570    for (;i < no;i++) {
2571	cur = cur->next;
2572	if (cur == NULL)
2573	    return(0);
2574    }
2575    /* TODO walk the DTD if present */
2576
2577    reader->curnode = (xmlNodePtr) cur;
2578    return(1);
2579}
2580
2581/**
2582 * xmlTextReaderMoveToAttribute:
2583 * @reader:  the xmlTextReaderPtr used
2584 * @name: the qualified name of the attribute.
2585 *
2586 * Moves the position of the current instance to the attribute with
2587 * the specified qualified name.
2588 *
2589 * Returns 1 in case of success, -1 in case of error, 0 if not found
2590 */
2591int
2592xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2593    xmlChar *prefix = NULL;
2594    xmlChar *localname;
2595    xmlNsPtr ns;
2596    xmlAttrPtr prop;
2597
2598    if ((reader == NULL) || (name == NULL))
2599	return(-1);
2600    if (reader->node == NULL)
2601	return(-1);
2602
2603    /* TODO: handle the xmlDecl */
2604    if (reader->node->type != XML_ELEMENT_NODE)
2605	return(0);
2606
2607    localname = xmlSplitQName2(name, &prefix);
2608    if (localname == NULL) {
2609	/*
2610	 * Namespace default decl
2611	 */
2612	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2613	    ns = reader->node->nsDef;
2614	    while (ns != NULL) {
2615		if (ns->prefix == NULL) {
2616		    reader->curnode = (xmlNodePtr) ns;
2617		    return(1);
2618		}
2619		ns = ns->next;
2620	    }
2621	    return(0);
2622	}
2623
2624	prop = reader->node->properties;
2625	while (prop != NULL) {
2626	    /*
2627	     * One need to have
2628	     *   - same attribute names
2629	     *   - and the attribute carrying that namespace
2630	     */
2631	    if ((xmlStrEqual(prop->name, name)) &&
2632		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
2633		reader->curnode = (xmlNodePtr) prop;
2634		return(1);
2635	    }
2636	    prop = prop->next;
2637	}
2638	return(0);
2639    }
2640
2641    /*
2642     * Namespace default decl
2643     */
2644    if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2645	ns = reader->node->nsDef;
2646	while (ns != NULL) {
2647	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2648		reader->curnode = (xmlNodePtr) ns;
2649		goto found;
2650	    }
2651	    ns = ns->next;
2652	}
2653	goto not_found;
2654    }
2655    prop = reader->node->properties;
2656    while (prop != NULL) {
2657	/*
2658	 * One need to have
2659	 *   - same attribute names
2660	 *   - and the attribute carrying that namespace
2661	 */
2662	if ((xmlStrEqual(prop->name, localname)) &&
2663	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
2664	    reader->curnode = (xmlNodePtr) prop;
2665	    goto found;
2666	}
2667	prop = prop->next;
2668    }
2669not_found:
2670    if (localname != NULL)
2671        xmlFree(localname);
2672    if (prefix != NULL)
2673        xmlFree(prefix);
2674    return(0);
2675
2676found:
2677    if (localname != NULL)
2678        xmlFree(localname);
2679    if (prefix != NULL)
2680        xmlFree(prefix);
2681    return(1);
2682}
2683
2684/**
2685 * xmlTextReaderMoveToAttributeNs:
2686 * @reader:  the xmlTextReaderPtr used
2687 * @localName:  the local name of the attribute.
2688 * @namespaceURI:  the namespace URI of the attribute.
2689 *
2690 * Moves the position of the current instance to the attribute with the
2691 * specified local name and namespace URI.
2692 *
2693 * Returns 1 in case of success, -1 in case of error, 0 if not found
2694 */
2695int
2696xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
2697	const xmlChar *localName, const xmlChar *namespaceURI) {
2698    xmlAttrPtr prop;
2699    xmlNodePtr node;
2700    xmlNsPtr ns;
2701    xmlChar *prefix = NULL;
2702
2703    if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
2704	return(-1);
2705    if (reader->node == NULL)
2706	return(-1);
2707    if (reader->node->type != XML_ELEMENT_NODE)
2708	return(0);
2709    node = reader->node;
2710
2711    if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
2712		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
2713			prefix = BAD_CAST localName;
2714		}
2715		ns = reader->node->nsDef;
2716		while (ns != NULL) {
2717			if ((prefix == NULL && ns->prefix == NULL) ||
2718				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
2719				reader->curnode = (xmlNodePtr) ns;
2720				return(1);
2721			}
2722			ns = ns->next;
2723		}
2724		return(0);
2725    }
2726
2727    prop = node->properties;
2728    while (prop != NULL) {
2729	/*
2730	 * One need to have
2731	 *   - same attribute names
2732	 *   - and the attribute carrying that namespace
2733	 */
2734        if (xmlStrEqual(prop->name, localName) &&
2735	    ((prop->ns != NULL) &&
2736	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
2737	    reader->curnode = (xmlNodePtr) prop;
2738	    return(1);
2739        }
2740	prop = prop->next;
2741    }
2742    return(0);
2743}
2744
2745/**
2746 * xmlTextReaderMoveToFirstAttribute:
2747 * @reader:  the xmlTextReaderPtr used
2748 *
2749 * Moves the position of the current instance to the first attribute
2750 * associated with the current node.
2751 *
2752 * Returns 1 in case of success, -1 in case of error, 0 if not found
2753 */
2754int
2755xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
2756    if (reader == NULL)
2757	return(-1);
2758    if (reader->node == NULL)
2759	return(-1);
2760    if (reader->node->type != XML_ELEMENT_NODE)
2761	return(0);
2762
2763    if (reader->node->nsDef != NULL) {
2764	reader->curnode = (xmlNodePtr) reader->node->nsDef;
2765	return(1);
2766    }
2767    if (reader->node->properties != NULL) {
2768	reader->curnode = (xmlNodePtr) reader->node->properties;
2769	return(1);
2770    }
2771    return(0);
2772}
2773
2774/**
2775 * xmlTextReaderMoveToNextAttribute:
2776 * @reader:  the xmlTextReaderPtr used
2777 *
2778 * Moves the position of the current instance to the next attribute
2779 * associated with the current node.
2780 *
2781 * Returns 1 in case of success, -1 in case of error, 0 if not found
2782 */
2783int
2784xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
2785    if (reader == NULL)
2786	return(-1);
2787    if (reader->node == NULL)
2788	return(-1);
2789    if (reader->node->type != XML_ELEMENT_NODE)
2790	return(0);
2791    if (reader->curnode == NULL)
2792	return(xmlTextReaderMoveToFirstAttribute(reader));
2793
2794    if (reader->curnode->type == XML_NAMESPACE_DECL) {
2795	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2796	if (ns->next != NULL) {
2797	    reader->curnode = (xmlNodePtr) ns->next;
2798	    return(1);
2799	}
2800	if (reader->node->properties != NULL) {
2801	    reader->curnode = (xmlNodePtr) reader->node->properties;
2802	    return(1);
2803	}
2804	return(0);
2805    } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
2806	       (reader->curnode->next != NULL)) {
2807	reader->curnode = reader->curnode->next;
2808	return(1);
2809    }
2810    return(0);
2811}
2812
2813/**
2814 * xmlTextReaderMoveToElement:
2815 * @reader:  the xmlTextReaderPtr used
2816 *
2817 * Moves the position of the current instance to the node that
2818 * contains the current Attribute  node.
2819 *
2820 * Returns 1 in case of success, -1 in case of error, 0 if not moved
2821 */
2822int
2823xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
2824    if (reader == NULL)
2825	return(-1);
2826    if (reader->node == NULL)
2827	return(-1);
2828    if (reader->node->type != XML_ELEMENT_NODE)
2829	return(0);
2830    if (reader->curnode != NULL) {
2831	reader->curnode = NULL;
2832	return(1);
2833    }
2834    return(0);
2835}
2836
2837/**
2838 * xmlTextReaderReadAttributeValue:
2839 * @reader:  the xmlTextReaderPtr used
2840 *
2841 * Parses an attribute value into one or more Text and EntityReference nodes.
2842 *
2843 * Returns 1 in case of success, 0 if the reader was not positionned on an
2844 *         ttribute node or all the attribute values have been read, or -1
2845 *         in case of error.
2846 */
2847int
2848xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
2849    if (reader == NULL)
2850	return(-1);
2851    if (reader->node == NULL)
2852	return(-1);
2853    if (reader->curnode == NULL)
2854	return(0);
2855    if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
2856	if (reader->curnode->children == NULL)
2857	    return(0);
2858	reader->curnode = reader->curnode->children;
2859    } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
2860	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2861
2862	if (reader->faketext == NULL) {
2863	    reader->faketext = xmlNewDocText(reader->node->doc,
2864		                             ns->href);
2865	} else {
2866            if ((reader->faketext->content != NULL) &&
2867	        (reader->faketext->content !=
2868		 (xmlChar *) &(reader->faketext->properties)))
2869		xmlFree(reader->faketext->content);
2870	    reader->faketext->content = xmlStrdup(ns->href);
2871	}
2872	reader->curnode = reader->faketext;
2873    } else {
2874	if (reader->curnode->next == NULL)
2875	    return(0);
2876	reader->curnode = reader->curnode->next;
2877    }
2878    return(1);
2879}
2880
2881/**
2882 * xmlTextReaderConstEncoding:
2883 * @reader:  the xmlTextReaderPtr used
2884 *
2885 * Determine the encoding of the document being read.
2886 *
2887 * Returns a string containing the encoding of the document or NULL in
2888 * case of error.  The string is deallocated with the reader.
2889 */
2890const xmlChar *
2891xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
2892    xmlDocPtr doc = NULL;
2893    if (reader == NULL)
2894	return(NULL);
2895    if (reader->doc != NULL)
2896        doc = reader->doc;
2897    else if (reader->ctxt != NULL)
2898	doc = reader->ctxt->myDoc;
2899    if (doc == NULL)
2900	return(NULL);
2901
2902    if (doc->encoding == NULL)
2903	return(NULL);
2904    else
2905      return(CONSTSTR(doc->encoding));
2906}
2907
2908
2909/************************************************************************
2910 *									*
2911 *			Acces API to the current node			*
2912 *									*
2913 ************************************************************************/
2914/**
2915 * xmlTextReaderAttributeCount:
2916 * @reader:  the xmlTextReaderPtr used
2917 *
2918 * Provides the number of attributes of the current node
2919 *
2920 * Returns 0 i no attributes, -1 in case of error or the attribute count
2921 */
2922int
2923xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
2924    int ret;
2925    xmlAttrPtr attr;
2926    xmlNsPtr ns;
2927    xmlNodePtr node;
2928
2929    if (reader == NULL)
2930	return(-1);
2931    if (reader->node == NULL)
2932	return(0);
2933
2934    if (reader->curnode != NULL)
2935	node = reader->curnode;
2936    else
2937	node = reader->node;
2938
2939    if (node->type != XML_ELEMENT_NODE)
2940	return(0);
2941    if ((reader->state == XML_TEXTREADER_END) ||
2942	(reader->state == XML_TEXTREADER_BACKTRACK))
2943	return(0);
2944    ret = 0;
2945    attr = node->properties;
2946    while (attr != NULL) {
2947	ret++;
2948	attr = attr->next;
2949    }
2950    ns = node->nsDef;
2951    while (ns != NULL) {
2952	ret++;
2953	ns = ns->next;
2954    }
2955    return(ret);
2956}
2957
2958/**
2959 * xmlTextReaderNodeType:
2960 * @reader:  the xmlTextReaderPtr used
2961 *
2962 * Get the node type of the current node
2963 * Reference:
2964 * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html
2965 *
2966 * Returns the xmlNodeType of the current node or -1 in case of error
2967 */
2968int
2969xmlTextReaderNodeType(xmlTextReaderPtr reader) {
2970    xmlNodePtr node;
2971
2972    if (reader == NULL)
2973	return(-1);
2974    if (reader->node == NULL)
2975	return(XML_READER_TYPE_NONE);
2976    if (reader->curnode != NULL)
2977	node = reader->curnode;
2978    else
2979	node = reader->node;
2980    switch (node->type) {
2981        case XML_ELEMENT_NODE:
2982	    if ((reader->state == XML_TEXTREADER_END) ||
2983		(reader->state == XML_TEXTREADER_BACKTRACK))
2984		return(XML_READER_TYPE_END_ELEMENT);
2985	    return(XML_READER_TYPE_ELEMENT);
2986        case XML_NAMESPACE_DECL:
2987        case XML_ATTRIBUTE_NODE:
2988	    return(XML_READER_TYPE_ATTRIBUTE);
2989        case XML_TEXT_NODE:
2990	    if (xmlIsBlankNode(reader->node)) {
2991		if (xmlNodeGetSpacePreserve(reader->node))
2992		    return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
2993		else
2994		    return(XML_READER_TYPE_WHITESPACE);
2995	    } else {
2996		return(XML_READER_TYPE_TEXT);
2997	    }
2998        case XML_CDATA_SECTION_NODE:
2999	    return(XML_READER_TYPE_CDATA);
3000        case XML_ENTITY_REF_NODE:
3001	    return(XML_READER_TYPE_ENTITY_REFERENCE);
3002        case XML_ENTITY_NODE:
3003	    return(XML_READER_TYPE_ENTITY);
3004        case XML_PI_NODE:
3005	    return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
3006        case XML_COMMENT_NODE:
3007	    return(XML_READER_TYPE_COMMENT);
3008        case XML_DOCUMENT_NODE:
3009        case XML_HTML_DOCUMENT_NODE:
3010#ifdef LIBXML_DOCB_ENABLED
3011        case XML_DOCB_DOCUMENT_NODE:
3012#endif
3013	    return(XML_READER_TYPE_DOCUMENT);
3014        case XML_DOCUMENT_FRAG_NODE:
3015	    return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
3016        case XML_NOTATION_NODE:
3017	    return(XML_READER_TYPE_NOTATION);
3018        case XML_DOCUMENT_TYPE_NODE:
3019        case XML_DTD_NODE:
3020	    return(XML_READER_TYPE_DOCUMENT_TYPE);
3021
3022        case XML_ELEMENT_DECL:
3023        case XML_ATTRIBUTE_DECL:
3024        case XML_ENTITY_DECL:
3025        case XML_XINCLUDE_START:
3026        case XML_XINCLUDE_END:
3027	    return(XML_READER_TYPE_NONE);
3028    }
3029    return(-1);
3030}
3031
3032/**
3033 * xmlTextReaderIsEmptyElement:
3034 * @reader:  the xmlTextReaderPtr used
3035 *
3036 * Check if the current node is empty
3037 *
3038 * Returns 1 if empty, 0 if not and -1 in case of error
3039 */
3040int
3041xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
3042    if ((reader == NULL) || (reader->node == NULL))
3043	return(-1);
3044    if (reader->node->type != XML_ELEMENT_NODE)
3045	return(0);
3046    if (reader->curnode != NULL)
3047	return(0);
3048    if (reader->node->children != NULL)
3049	return(0);
3050    if (reader->state == XML_TEXTREADER_END)
3051	return(0);
3052    if (reader->doc != NULL)
3053        return(1);
3054#ifdef LIBXML_XINCLUDE_ENABLED
3055    if (reader->in_xinclude > 0)
3056        return(1);
3057#endif
3058    return((reader->node->extra & NODE_IS_EMPTY) != 0);
3059}
3060
3061/**
3062 * xmlTextReaderLocalName:
3063 * @reader:  the xmlTextReaderPtr used
3064 *
3065 * The local name of the node.
3066 *
3067 * Returns the local name or NULL if not available,
3068 *   if non NULL it need to be freed by the caller.
3069 */
3070xmlChar *
3071xmlTextReaderLocalName(xmlTextReaderPtr reader) {
3072    xmlNodePtr node;
3073    if ((reader == NULL) || (reader->node == NULL))
3074	return(NULL);
3075    if (reader->curnode != NULL)
3076	node = reader->curnode;
3077    else
3078	node = reader->node;
3079    if (node->type == XML_NAMESPACE_DECL) {
3080	xmlNsPtr ns = (xmlNsPtr) node;
3081	if (ns->prefix == NULL)
3082	    return(xmlStrdup(BAD_CAST "xmlns"));
3083	else
3084	    return(xmlStrdup(ns->prefix));
3085    }
3086    if ((node->type != XML_ELEMENT_NODE) &&
3087	(node->type != XML_ATTRIBUTE_NODE))
3088	return(xmlTextReaderName(reader));
3089    return(xmlStrdup(node->name));
3090}
3091
3092/**
3093 * xmlTextReaderConstLocalName:
3094 * @reader:  the xmlTextReaderPtr used
3095 *
3096 * The local name of the node.
3097 *
3098 * Returns the local name or NULL if not available, the
3099 *         string will be deallocated with the reader.
3100 */
3101const xmlChar *
3102xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
3103    xmlNodePtr node;
3104    if ((reader == NULL) || (reader->node == NULL))
3105	return(NULL);
3106    if (reader->curnode != NULL)
3107	node = reader->curnode;
3108    else
3109	node = reader->node;
3110    if (node->type == XML_NAMESPACE_DECL) {
3111	xmlNsPtr ns = (xmlNsPtr) node;
3112	if (ns->prefix == NULL)
3113	    return(CONSTSTR(BAD_CAST "xmlns"));
3114	else
3115	    return(ns->prefix);
3116    }
3117    if ((node->type != XML_ELEMENT_NODE) &&
3118	(node->type != XML_ATTRIBUTE_NODE))
3119	return(xmlTextReaderConstName(reader));
3120    return(node->name);
3121}
3122
3123/**
3124 * xmlTextReaderName:
3125 * @reader:  the xmlTextReaderPtr used
3126 *
3127 * The qualified name of the node, equal to Prefix :LocalName.
3128 *
3129 * Returns the local name or NULL if not available,
3130 *   if non NULL it need to be freed by the caller.
3131 */
3132xmlChar *
3133xmlTextReaderName(xmlTextReaderPtr reader) {
3134    xmlNodePtr node;
3135    xmlChar *ret;
3136
3137    if ((reader == NULL) || (reader->node == NULL))
3138	return(NULL);
3139    if (reader->curnode != NULL)
3140	node = reader->curnode;
3141    else
3142	node = reader->node;
3143    switch (node->type) {
3144        case XML_ELEMENT_NODE:
3145        case XML_ATTRIBUTE_NODE:
3146	    if ((node->ns == NULL) ||
3147		(node->ns->prefix == NULL))
3148		return(xmlStrdup(node->name));
3149
3150	    ret = xmlStrdup(node->ns->prefix);
3151	    ret = xmlStrcat(ret, BAD_CAST ":");
3152	    ret = xmlStrcat(ret, node->name);
3153	    return(ret);
3154        case XML_TEXT_NODE:
3155	    return(xmlStrdup(BAD_CAST "#text"));
3156        case XML_CDATA_SECTION_NODE:
3157	    return(xmlStrdup(BAD_CAST "#cdata-section"));
3158        case XML_ENTITY_NODE:
3159        case XML_ENTITY_REF_NODE:
3160	    return(xmlStrdup(node->name));
3161        case XML_PI_NODE:
3162	    return(xmlStrdup(node->name));
3163        case XML_COMMENT_NODE:
3164	    return(xmlStrdup(BAD_CAST "#comment"));
3165        case XML_DOCUMENT_NODE:
3166        case XML_HTML_DOCUMENT_NODE:
3167#ifdef LIBXML_DOCB_ENABLED
3168        case XML_DOCB_DOCUMENT_NODE:
3169#endif
3170	    return(xmlStrdup(BAD_CAST "#document"));
3171        case XML_DOCUMENT_FRAG_NODE:
3172	    return(xmlStrdup(BAD_CAST "#document-fragment"));
3173        case XML_NOTATION_NODE:
3174	    return(xmlStrdup(node->name));
3175        case XML_DOCUMENT_TYPE_NODE:
3176        case XML_DTD_NODE:
3177	    return(xmlStrdup(node->name));
3178        case XML_NAMESPACE_DECL: {
3179	    xmlNsPtr ns = (xmlNsPtr) node;
3180
3181	    ret = xmlStrdup(BAD_CAST "xmlns");
3182	    if (ns->prefix == NULL)
3183		return(ret);
3184	    ret = xmlStrcat(ret, BAD_CAST ":");
3185	    ret = xmlStrcat(ret, ns->prefix);
3186	    return(ret);
3187	}
3188
3189        case XML_ELEMENT_DECL:
3190        case XML_ATTRIBUTE_DECL:
3191        case XML_ENTITY_DECL:
3192        case XML_XINCLUDE_START:
3193        case XML_XINCLUDE_END:
3194	    return(NULL);
3195    }
3196    return(NULL);
3197}
3198
3199/**
3200 * xmlTextReaderConstName:
3201 * @reader:  the xmlTextReaderPtr used
3202 *
3203 * The qualified name of the node, equal to Prefix :LocalName.
3204 *
3205 * Returns the local name or NULL if not available, the string is
3206 *         deallocated with the reader.
3207 */
3208const xmlChar *
3209xmlTextReaderConstName(xmlTextReaderPtr reader) {
3210    xmlNodePtr node;
3211
3212    if ((reader == NULL) || (reader->node == NULL))
3213	return(NULL);
3214    if (reader->curnode != NULL)
3215	node = reader->curnode;
3216    else
3217	node = reader->node;
3218    switch (node->type) {
3219        case XML_ELEMENT_NODE:
3220        case XML_ATTRIBUTE_NODE:
3221	    if ((node->ns == NULL) ||
3222		(node->ns->prefix == NULL))
3223		return(node->name);
3224	    return(CONSTQSTR(node->ns->prefix, node->name));
3225        case XML_TEXT_NODE:
3226	    return(CONSTSTR(BAD_CAST "#text"));
3227        case XML_CDATA_SECTION_NODE:
3228	    return(CONSTSTR(BAD_CAST "#cdata-section"));
3229        case XML_ENTITY_NODE:
3230        case XML_ENTITY_REF_NODE:
3231	    return(CONSTSTR(node->name));
3232        case XML_PI_NODE:
3233	    return(CONSTSTR(node->name));
3234        case XML_COMMENT_NODE:
3235	    return(CONSTSTR(BAD_CAST "#comment"));
3236        case XML_DOCUMENT_NODE:
3237        case XML_HTML_DOCUMENT_NODE:
3238#ifdef LIBXML_DOCB_ENABLED
3239        case XML_DOCB_DOCUMENT_NODE:
3240#endif
3241	    return(CONSTSTR(BAD_CAST "#document"));
3242        case XML_DOCUMENT_FRAG_NODE:
3243	    return(CONSTSTR(BAD_CAST "#document-fragment"));
3244        case XML_NOTATION_NODE:
3245	    return(CONSTSTR(node->name));
3246        case XML_DOCUMENT_TYPE_NODE:
3247        case XML_DTD_NODE:
3248	    return(CONSTSTR(node->name));
3249        case XML_NAMESPACE_DECL: {
3250	    xmlNsPtr ns = (xmlNsPtr) node;
3251
3252	    if (ns->prefix == NULL)
3253		return(CONSTSTR(BAD_CAST "xmlns"));
3254	    return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
3255	}
3256
3257        case XML_ELEMENT_DECL:
3258        case XML_ATTRIBUTE_DECL:
3259        case XML_ENTITY_DECL:
3260        case XML_XINCLUDE_START:
3261        case XML_XINCLUDE_END:
3262	    return(NULL);
3263    }
3264    return(NULL);
3265}
3266
3267/**
3268 * xmlTextReaderPrefix:
3269 * @reader:  the xmlTextReaderPtr used
3270 *
3271 * A shorthand reference to the namespace associated with the node.
3272 *
3273 * Returns the prefix or NULL if not available,
3274 *    if non NULL it need to be freed by the caller.
3275 */
3276xmlChar *
3277xmlTextReaderPrefix(xmlTextReaderPtr reader) {
3278    xmlNodePtr node;
3279    if ((reader == NULL) || (reader->node == NULL))
3280	return(NULL);
3281    if (reader->curnode != NULL)
3282	node = reader->curnode;
3283    else
3284	node = reader->node;
3285    if (node->type == XML_NAMESPACE_DECL) {
3286	xmlNsPtr ns = (xmlNsPtr) node;
3287	if (ns->prefix == NULL)
3288	    return(NULL);
3289	return(xmlStrdup(BAD_CAST "xmlns"));
3290    }
3291    if ((node->type != XML_ELEMENT_NODE) &&
3292	(node->type != XML_ATTRIBUTE_NODE))
3293	return(NULL);
3294    if ((node->ns != NULL) && (node->ns->prefix != NULL))
3295	return(xmlStrdup(node->ns->prefix));
3296    return(NULL);
3297}
3298
3299/**
3300 * xmlTextReaderConstPrefix:
3301 * @reader:  the xmlTextReaderPtr used
3302 *
3303 * A shorthand reference to the namespace associated with the node.
3304 *
3305 * Returns the prefix or NULL if not available, the string is deallocated
3306 *         with the reader.
3307 */
3308const xmlChar *
3309xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
3310    xmlNodePtr node;
3311    if ((reader == NULL) || (reader->node == NULL))
3312	return(NULL);
3313    if (reader->curnode != NULL)
3314	node = reader->curnode;
3315    else
3316	node = reader->node;
3317    if (node->type == XML_NAMESPACE_DECL) {
3318	xmlNsPtr ns = (xmlNsPtr) node;
3319	if (ns->prefix == NULL)
3320	    return(NULL);
3321	return(CONSTSTR(BAD_CAST "xmlns"));
3322    }
3323    if ((node->type != XML_ELEMENT_NODE) &&
3324	(node->type != XML_ATTRIBUTE_NODE))
3325	return(NULL);
3326    if ((node->ns != NULL) && (node->ns->prefix != NULL))
3327	return(CONSTSTR(node->ns->prefix));
3328    return(NULL);
3329}
3330
3331/**
3332 * xmlTextReaderNamespaceUri:
3333 * @reader:  the xmlTextReaderPtr used
3334 *
3335 * The URI defining the namespace associated with the node.
3336 *
3337 * Returns the namespace URI or NULL if not available,
3338 *    if non NULL it need to be freed by the caller.
3339 */
3340xmlChar *
3341xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
3342    xmlNodePtr node;
3343    if ((reader == NULL) || (reader->node == NULL))
3344	return(NULL);
3345    if (reader->curnode != NULL)
3346	node = reader->curnode;
3347    else
3348	node = reader->node;
3349    if (node->type == XML_NAMESPACE_DECL)
3350	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3351    if ((node->type != XML_ELEMENT_NODE) &&
3352	(node->type != XML_ATTRIBUTE_NODE))
3353	return(NULL);
3354    if (node->ns != NULL)
3355	return(xmlStrdup(node->ns->href));
3356    return(NULL);
3357}
3358
3359/**
3360 * xmlTextReaderConstNamespaceUri:
3361 * @reader:  the xmlTextReaderPtr used
3362 *
3363 * The URI defining the namespace associated with the node.
3364 *
3365 * Returns the namespace URI or NULL if not available, the string
3366 *         will be deallocated with the reader
3367 */
3368const xmlChar *
3369xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
3370    xmlNodePtr node;
3371    if ((reader == NULL) || (reader->node == NULL))
3372	return(NULL);
3373    if (reader->curnode != NULL)
3374	node = reader->curnode;
3375    else
3376	node = reader->node;
3377    if (node->type == XML_NAMESPACE_DECL)
3378	return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3379    if ((node->type != XML_ELEMENT_NODE) &&
3380	(node->type != XML_ATTRIBUTE_NODE))
3381	return(NULL);
3382    if (node->ns != NULL)
3383	return(CONSTSTR(node->ns->href));
3384    return(NULL);
3385}
3386
3387/**
3388 * xmlTextReaderBaseUri:
3389 * @reader:  the xmlTextReaderPtr used
3390 *
3391 * The base URI of the node.
3392 *
3393 * Returns the base URI or NULL if not available,
3394 *    if non NULL it need to be freed by the caller.
3395 */
3396xmlChar *
3397xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
3398    if ((reader == NULL) || (reader->node == NULL))
3399	return(NULL);
3400    return(xmlNodeGetBase(NULL, reader->node));
3401}
3402
3403/**
3404 * xmlTextReaderConstBaseUri:
3405 * @reader:  the xmlTextReaderPtr used
3406 *
3407 * The base URI of the node.
3408 *
3409 * Returns the base URI or NULL if not available, the string
3410 *         will be deallocated with the reader
3411 */
3412const xmlChar *
3413xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
3414    xmlChar *tmp;
3415    const xmlChar *ret;
3416
3417    if ((reader == NULL) || (reader->node == NULL))
3418	return(NULL);
3419    tmp = xmlNodeGetBase(NULL, reader->node);
3420    if (tmp == NULL)
3421        return(NULL);
3422    ret = CONSTSTR(tmp);
3423    xmlFree(tmp);
3424    return(ret);
3425}
3426
3427/**
3428 * xmlTextReaderDepth:
3429 * @reader:  the xmlTextReaderPtr used
3430 *
3431 * The depth of the node in the tree.
3432 *
3433 * Returns the depth or -1 in case of error
3434 */
3435int
3436xmlTextReaderDepth(xmlTextReaderPtr reader) {
3437    if (reader == NULL)
3438	return(-1);
3439    if (reader->node == NULL)
3440	return(0);
3441
3442    if (reader->curnode != NULL) {
3443	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
3444	    (reader->curnode->type == XML_NAMESPACE_DECL))
3445	    return(reader->depth + 1);
3446	return(reader->depth + 2);
3447    }
3448    return(reader->depth);
3449}
3450
3451/**
3452 * xmlTextReaderHasAttributes:
3453 * @reader:  the xmlTextReaderPtr used
3454 *
3455 * Whether the node has attributes.
3456 *
3457 * Returns 1 if true, 0 if false, and -1 in case or error
3458 */
3459int
3460xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
3461    xmlNodePtr node;
3462    if (reader == NULL)
3463	return(-1);
3464    if (reader->node == NULL)
3465	return(0);
3466    if (reader->curnode != NULL)
3467	node = reader->curnode;
3468    else
3469	node = reader->node;
3470
3471    if ((node->type == XML_ELEMENT_NODE) &&
3472	((node->properties != NULL) || (node->nsDef != NULL)))
3473	return(1);
3474    /* TODO: handle the xmlDecl */
3475    return(0);
3476}
3477
3478/**
3479 * xmlTextReaderHasValue:
3480 * @reader:  the xmlTextReaderPtr used
3481 *
3482 * Whether the node can have a text value.
3483 *
3484 * Returns 1 if true, 0 if false, and -1 in case or error
3485 */
3486int
3487xmlTextReaderHasValue(xmlTextReaderPtr reader) {
3488    xmlNodePtr node;
3489    if (reader == NULL)
3490	return(-1);
3491    if (reader->node == NULL)
3492	return(0);
3493    if (reader->curnode != NULL)
3494	node = reader->curnode;
3495    else
3496	node = reader->node;
3497
3498    switch (node->type) {
3499        case XML_ATTRIBUTE_NODE:
3500        case XML_TEXT_NODE:
3501        case XML_CDATA_SECTION_NODE:
3502        case XML_PI_NODE:
3503        case XML_COMMENT_NODE:
3504        case XML_NAMESPACE_DECL:
3505	    return(1);
3506	default:
3507	    break;
3508    }
3509    return(0);
3510}
3511
3512/**
3513 * xmlTextReaderValue:
3514 * @reader:  the xmlTextReaderPtr used
3515 *
3516 * Provides the text value of the node if present
3517 *
3518 * Returns the string or NULL if not available. The result must be deallocated
3519 *     with xmlFree()
3520 */
3521xmlChar *
3522xmlTextReaderValue(xmlTextReaderPtr reader) {
3523    xmlNodePtr node;
3524    if (reader == NULL)
3525	return(NULL);
3526    if (reader->node == NULL)
3527	return(NULL);
3528    if (reader->curnode != NULL)
3529	node = reader->curnode;
3530    else
3531	node = reader->node;
3532
3533    switch (node->type) {
3534        case XML_NAMESPACE_DECL:
3535	    return(xmlStrdup(((xmlNsPtr) node)->href));
3536        case XML_ATTRIBUTE_NODE:{
3537	    xmlAttrPtr attr = (xmlAttrPtr) node;
3538
3539	    if (attr->parent != NULL)
3540		return (xmlNodeListGetString
3541			(attr->parent->doc, attr->children, 1));
3542	    else
3543		return (xmlNodeListGetString(NULL, attr->children, 1));
3544	    break;
3545	}
3546        case XML_TEXT_NODE:
3547        case XML_CDATA_SECTION_NODE:
3548        case XML_PI_NODE:
3549        case XML_COMMENT_NODE:
3550            if (node->content != NULL)
3551                return (xmlStrdup(node->content));
3552	default:
3553	    break;
3554    }
3555    return(NULL);
3556}
3557
3558/**
3559 * xmlTextReaderConstValue:
3560 * @reader:  the xmlTextReaderPtr used
3561 *
3562 * Provides the text value of the node if present
3563 *
3564 * Returns the string or NULL if not available. The result will be
3565 *     deallocated on the next Read() operation.
3566 */
3567const xmlChar *
3568xmlTextReaderConstValue(xmlTextReaderPtr reader) {
3569    xmlNodePtr node;
3570    if (reader == NULL)
3571	return(NULL);
3572    if (reader->node == NULL)
3573	return(NULL);
3574    if (reader->curnode != NULL)
3575	node = reader->curnode;
3576    else
3577	node = reader->node;
3578
3579    switch (node->type) {
3580        case XML_NAMESPACE_DECL:
3581	    return(((xmlNsPtr) node)->href);
3582        case XML_ATTRIBUTE_NODE:{
3583	    xmlAttrPtr attr = (xmlAttrPtr) node;
3584
3585	    if ((attr->children != NULL) &&
3586	        (attr->children->type == XML_TEXT_NODE) &&
3587		(attr->children->next == NULL))
3588		return(attr->children->content);
3589	    else {
3590		if (reader->buffer == NULL)
3591		    reader->buffer = xmlBufferCreateSize(100);
3592		if (reader->buffer == NULL) {
3593		    xmlGenericError(xmlGenericErrorContext,
3594				    "xmlTextReaderSetup : malloc failed\n");
3595		    return (NULL);
3596		}
3597	        reader->buffer->use = 0;
3598	        xmlNodeBufGetContent(reader->buffer, node);
3599		return(reader->buffer->content);
3600	    }
3601	    break;
3602	}
3603        case XML_TEXT_NODE:
3604        case XML_CDATA_SECTION_NODE:
3605        case XML_PI_NODE:
3606        case XML_COMMENT_NODE:
3607	    return(node->content);
3608	default:
3609	    break;
3610    }
3611    return(NULL);
3612}
3613
3614/**
3615 * xmlTextReaderIsDefault:
3616 * @reader:  the xmlTextReaderPtr used
3617 *
3618 * Whether an Attribute  node was generated from the default value
3619 * defined in the DTD or schema.
3620 *
3621 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
3622 */
3623int
3624xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
3625    if (reader == NULL)
3626	return(-1);
3627    return(0);
3628}
3629
3630/**
3631 * xmlTextReaderQuoteChar:
3632 * @reader:  the xmlTextReaderPtr used
3633 *
3634 * The quotation mark character used to enclose the value of an attribute.
3635 *
3636 * Returns " or ' and -1 in case of error
3637 */
3638int
3639xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
3640    if (reader == NULL)
3641	return(-1);
3642    /* TODO maybe lookup the attribute value for " first */
3643    return((int) '"');
3644}
3645
3646/**
3647 * xmlTextReaderXmlLang:
3648 * @reader:  the xmlTextReaderPtr used
3649 *
3650 * The xml:lang scope within which the node resides.
3651 *
3652 * Returns the xml:lang value or NULL if none exists.,
3653 *    if non NULL it need to be freed by the caller.
3654 */
3655xmlChar *
3656xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
3657    if (reader == NULL)
3658	return(NULL);
3659    if (reader->node == NULL)
3660	return(NULL);
3661    return(xmlNodeGetLang(reader->node));
3662}
3663
3664/**
3665 * xmlTextReaderConstXmlLang:
3666 * @reader:  the xmlTextReaderPtr used
3667 *
3668 * The xml:lang scope within which the node resides.
3669 *
3670 * Returns the xml:lang value or NULL if none exists.
3671 */
3672const xmlChar *
3673xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
3674    xmlChar *tmp;
3675    const xmlChar *ret;
3676
3677    if (reader == NULL)
3678	return(NULL);
3679    if (reader->node == NULL)
3680	return(NULL);
3681    tmp = xmlNodeGetLang(reader->node);
3682    if (tmp == NULL)
3683        return(NULL);
3684    ret = CONSTSTR(tmp);
3685    xmlFree(tmp);
3686    return(ret);
3687}
3688
3689/**
3690 * xmlTextReaderConstString:
3691 * @reader:  the xmlTextReaderPtr used
3692 * @str:  the string to intern.
3693 *
3694 * Get an interned string from the reader, allows for example to
3695 * speedup string name comparisons
3696 *
3697 * Returns an interned copy of the string or NULL in case of error. The
3698 *         string will be deallocated with the reader.
3699 */
3700const xmlChar *
3701xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
3702    if (reader == NULL)
3703	return(NULL);
3704    return(CONSTSTR(str));
3705}
3706
3707/**
3708 * xmlTextReaderNormalization:
3709 * @reader:  the xmlTextReaderPtr used
3710 *
3711 * The value indicating whether to normalize white space and attribute values.
3712 * Since attribute value and end of line normalizations are a MUST in the XML
3713 * specification only the value true is accepted. The broken bahaviour of
3714 * accepting out of range character entities like &#0; is of course not
3715 * supported either.
3716 *
3717 * Returns 1 or -1 in case of error.
3718 */
3719int
3720xmlTextReaderNormalization(xmlTextReaderPtr reader) {
3721    if (reader == NULL)
3722	return(-1);
3723    return(1);
3724}
3725
3726/************************************************************************
3727 *									*
3728 *			Extensions to the base APIs			*
3729 *									*
3730 ************************************************************************/
3731
3732/**
3733 * xmlTextReaderSetParserProp:
3734 * @reader:  the xmlTextReaderPtr used
3735 * @prop:  the xmlParserProperties to set
3736 * @value:  usually 0 or 1 to (de)activate it
3737 *
3738 * Change the parser processing behaviour by changing some of its internal
3739 * properties. Note that some properties can only be changed before any
3740 * read has been done.
3741 *
3742 * Returns 0 if the call was successful, or -1 in case of error
3743 */
3744int
3745xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
3746    xmlParserProperties p = (xmlParserProperties) prop;
3747    xmlParserCtxtPtr ctxt;
3748
3749    if ((reader == NULL) || (reader->ctxt == NULL))
3750	return(-1);
3751    ctxt = reader->ctxt;
3752
3753    switch (p) {
3754        case XML_PARSER_LOADDTD:
3755	    if (value != 0) {
3756		if (ctxt->loadsubset == 0) {
3757		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3758			return(-1);
3759		    ctxt->loadsubset = XML_DETECT_IDS;
3760		}
3761	    } else {
3762		ctxt->loadsubset = 0;
3763	    }
3764	    return(0);
3765        case XML_PARSER_DEFAULTATTRS:
3766	    if (value != 0) {
3767		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
3768	    } else {
3769		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3770		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
3771	    }
3772	    return(0);
3773        case XML_PARSER_VALIDATE:
3774	    if (value != 0) {
3775		ctxt->validate = 1;
3776		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
3777	    } else {
3778		ctxt->validate = 0;
3779	    }
3780	    return(0);
3781        case XML_PARSER_SUBST_ENTITIES:
3782	    if (value != 0) {
3783		ctxt->replaceEntities = 1;
3784	    } else {
3785		ctxt->replaceEntities = 0;
3786	    }
3787	    return(0);
3788    }
3789    return(-1);
3790}
3791
3792/**
3793 * xmlTextReaderGetParserProp:
3794 * @reader:  the xmlTextReaderPtr used
3795 * @prop:  the xmlParserProperties to get
3796 *
3797 * Read the parser internal property.
3798 *
3799 * Returns the value, usually 0 or 1, or -1 in case of error.
3800 */
3801int
3802xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
3803    xmlParserProperties p = (xmlParserProperties) prop;
3804    xmlParserCtxtPtr ctxt;
3805
3806    if ((reader == NULL) || (reader->ctxt == NULL))
3807	return(-1);
3808    ctxt = reader->ctxt;
3809
3810    switch (p) {
3811        case XML_PARSER_LOADDTD:
3812	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
3813		return(1);
3814	    return(0);
3815        case XML_PARSER_DEFAULTATTRS:
3816	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3817		return(1);
3818	    return(0);
3819        case XML_PARSER_VALIDATE:
3820	    return(reader->validate);
3821	case XML_PARSER_SUBST_ENTITIES:
3822	    return(ctxt->replaceEntities);
3823    }
3824    return(-1);
3825}
3826
3827
3828/**
3829 * xmlTextReaderGetParserLineNumber:
3830 * @reader: the user data (XML reader context)
3831 *
3832 * Provide the line number of the current parsing point.
3833 *
3834 * Returns an int or 0 if not available
3835 */
3836int
3837xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
3838{
3839    if ((reader == NULL) || (reader->ctxt == NULL) ||
3840        (reader->ctxt->input == NULL)) {
3841        return (0);
3842    }
3843    return (reader->ctxt->input->line);
3844}
3845
3846/**
3847 * xmlTextReaderGetParserColumnNumber:
3848 * @reader: the user data (XML reader context)
3849 *
3850 * Provide the column number of the current parsing point.
3851 *
3852 * Returns an int or 0 if not available
3853 */
3854int
3855xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
3856{
3857    if ((reader == NULL) || (reader->ctxt == NULL) ||
3858        (reader->ctxt->input == NULL)) {
3859        return (0);
3860    }
3861    return (reader->ctxt->input->col);
3862}
3863
3864/**
3865 * xmlTextReaderCurrentNode:
3866 * @reader:  the xmlTextReaderPtr used
3867 *
3868 * Hacking interface allowing to get the xmlNodePtr correponding to the
3869 * current node being accessed by the xmlTextReader. This is dangerous
3870 * because the underlying node may be destroyed on the next Reads.
3871 *
3872 * Returns the xmlNodePtr or NULL in case of error.
3873 */
3874xmlNodePtr
3875xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
3876    if (reader == NULL)
3877	return(NULL);
3878
3879    if (reader->curnode != NULL)
3880	return(reader->curnode);
3881    return(reader->node);
3882}
3883
3884/**
3885 * xmlTextReaderPreserve:
3886 * @reader:  the xmlTextReaderPtr used
3887 *
3888 * This tells the XML Reader to preserve the current node.
3889 * The caller must also use xmlTextReaderCurrentDoc() to
3890 * keep an handle on the resulting document once parsing has finished
3891 *
3892 * Returns the xmlNodePtr or NULL in case of error.
3893 */
3894xmlNodePtr
3895xmlTextReaderPreserve(xmlTextReaderPtr reader) {
3896    xmlNodePtr cur, parent;
3897
3898    if (reader == NULL)
3899	return(NULL);
3900
3901    if (reader->curnode != NULL)
3902        cur = reader->curnode;
3903    else
3904        cur = reader->node;
3905    if (cur == NULL)
3906        return(NULL);
3907
3908    if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
3909	cur->extra |= NODE_IS_PRESERVED;
3910	cur->extra |= NODE_IS_SPRESERVED;
3911    }
3912    reader->preserves++;
3913
3914    parent = cur->parent;;
3915    while (parent != NULL) {
3916        if (parent->type == XML_ELEMENT_NODE)
3917	    parent->extra |= NODE_IS_PRESERVED;
3918	parent = parent->parent;
3919    }
3920    return(cur);
3921}
3922
3923#ifdef LIBXML_PATTERN_ENABLED
3924/**
3925 * xmlTextReaderPreservePattern:
3926 * @reader:  the xmlTextReaderPtr used
3927 * @pattern:  an XPath subset pattern
3928 * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
3929 *
3930 * This tells the XML Reader to preserve all nodes matched by the
3931 * pattern. The caller must also use xmlTextReaderCurrentDoc() to
3932 * keep an handle on the resulting document once parsing has finished
3933 *
3934 * Returns a positive number in case of success and -1 in case of error
3935 */
3936int
3937xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
3938                             const xmlChar **namespaces)
3939{
3940    xmlPatternPtr comp;
3941
3942    if ((reader == NULL) || (pattern == NULL))
3943	return(-1);
3944
3945    comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
3946    if (comp == NULL)
3947        return(-1);
3948
3949    if (reader->patternMax <= 0) {
3950	reader->patternMax = 4;
3951	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
3952					      sizeof(reader->patternTab[0]));
3953        if (reader->patternTab == NULL) {
3954            xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
3955            return (-1);
3956        }
3957    }
3958    if (reader->patternNr >= reader->patternMax) {
3959        xmlPatternPtr *tmp;
3960        reader->patternMax *= 2;
3961	tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
3962                                      reader->patternMax *
3963                                      sizeof(reader->patternTab[0]));
3964        if (tmp == NULL) {
3965            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
3966	    reader->patternMax /= 2;
3967            return (-1);
3968        }
3969	reader->patternTab = tmp;
3970    }
3971    reader->patternTab[reader->patternNr] = comp;
3972    return(reader->patternNr++);
3973}
3974#endif
3975
3976/**
3977 * xmlTextReaderCurrentDoc:
3978 * @reader:  the xmlTextReaderPtr used
3979 *
3980 * Hacking interface allowing to get the xmlDocPtr correponding to the
3981 * current document being accessed by the xmlTextReader.
3982 * NOTE: as a result of this call, the reader will not destroy the
3983 *       associated XML document and calling xmlFreeDoc() on the result
3984 *       is needed once the reader parsing has finished.
3985 *
3986 * Returns the xmlDocPtr or NULL in case of error.
3987 */
3988xmlDocPtr
3989xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
3990    if (reader == NULL)
3991	return(NULL);
3992    if (reader->doc != NULL)
3993        return(reader->doc);
3994    if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
3995	return(NULL);
3996
3997    reader->preserve = 1;
3998    return(reader->ctxt->myDoc);
3999}
4000
4001#ifdef LIBXML_SCHEMAS_ENABLED
4002static char *xmlTextReaderBuildMessage(const char *msg, va_list ap);
4003
4004static void XMLCDECL
4005xmlTextReaderValidityError(void *ctxt, const char *msg, ...);
4006
4007static void XMLCDECL
4008xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);
4009
4010static void XMLCDECL
4011xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
4012{
4013    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4014
4015    char *str;
4016
4017    va_list ap;
4018
4019    va_start(ap, msg);
4020    str = xmlTextReaderBuildMessage(msg, ap);
4021    if (!reader->errorFunc) {
4022        xmlTextReaderValidityError(ctx, "%s", str);
4023    } else {
4024        reader->errorFunc(reader->errorFuncArg, str,
4025                          XML_PARSER_SEVERITY_VALIDITY_ERROR,
4026                          NULL /* locator */ );
4027    }
4028    if (str != NULL)
4029        xmlFree(str);
4030    va_end(ap);
4031}
4032
4033static void XMLCDECL
4034xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
4035{
4036    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4037
4038    char *str;
4039
4040    va_list ap;
4041
4042    va_start(ap, msg);
4043    str = xmlTextReaderBuildMessage(msg, ap);
4044    if (!reader->errorFunc) {
4045        xmlTextReaderValidityWarning(ctx, "%s", str);
4046    } else {
4047        reader->errorFunc(reader->errorFuncArg, str,
4048                          XML_PARSER_SEVERITY_VALIDITY_WARNING,
4049                          NULL /* locator */ );
4050    }
4051    if (str != NULL)
4052        xmlFree(str);
4053    va_end(ap);
4054}
4055
4056static void
4057  xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
4058
4059static void
4060xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error)
4061{
4062    xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
4063
4064    if (reader->sErrorFunc) {
4065        reader->sErrorFunc(reader->errorFuncArg, error);
4066    } else {
4067        xmlTextReaderStructuredError(reader, error);
4068    }
4069}
4070/**
4071 * xmlTextReaderRelaxNGSetSchema:
4072 * @reader:  the xmlTextReaderPtr used
4073 * @schema:  a precompiled RelaxNG schema
4074 *
4075 * Use RelaxNG to validate the document as it is processed.
4076 * Activation is only possible before the first Read().
4077 * if @schema is NULL, then RelaxNG validation is desactivated.
4078 @ The @schema should not be freed until the reader is deallocated
4079 * or its use has been deactivated.
4080 *
4081 * Returns 0 in case the RelaxNG validation could be (des)activated and
4082 *         -1 in case of error.
4083 */
4084int
4085xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
4086    if (reader == NULL)
4087        return(-1);
4088    if (schema == NULL) {
4089        if (reader->rngSchemas != NULL) {
4090	    xmlRelaxNGFree(reader->rngSchemas);
4091	    reader->rngSchemas = NULL;
4092	}
4093        if (reader->rngValidCtxt != NULL) {
4094	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4095	    reader->rngValidCtxt = NULL;
4096        }
4097	return(0);
4098    }
4099    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4100	return(-1);
4101    if (reader->rngSchemas != NULL) {
4102	xmlRelaxNGFree(reader->rngSchemas);
4103	reader->rngSchemas = NULL;
4104    }
4105    if (reader->rngValidCtxt != NULL) {
4106	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4107	reader->rngValidCtxt = NULL;
4108    }
4109    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
4110    if (reader->rngValidCtxt == NULL)
4111        return(-1);
4112    if (reader->errorFunc != NULL) {
4113	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4114			xmlTextReaderValidityErrorRelay,
4115			xmlTextReaderValidityWarningRelay,
4116			reader);
4117    }
4118	if (reader->sErrorFunc != NULL) {
4119		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4120			xmlTextReaderValidityStructuredRelay,
4121			reader);
4122    }
4123    reader->rngValidErrors = 0;
4124    reader->rngFullNode = NULL;
4125    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4126    return(0);
4127}
4128
4129/**
4130 * xmlTextReaderSetSchema:
4131 * @reader:  the xmlTextReaderPtr used
4132 * @schema:  a precompiled Schema schema
4133 *
4134 * Use XSD Schema to validate the document as it is processed.
4135 * Activation is only possible before the first Read().
4136 * if @schema is NULL, then Schema validation is desactivated.
4137 @ The @schema should not be freed until the reader is deallocated
4138 * or its use has been deactivated.
4139 *
4140 * Returns 0 in case the Schema validation could be (des)activated and
4141 *         -1 in case of error.
4142 */
4143int
4144xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
4145    if (reader == NULL)
4146        return(-1);
4147    if (schema == NULL) {
4148	if (reader->xsdPlug != NULL) {
4149	    xmlSchemaSAXUnplug(reader->xsdPlug);
4150	    reader->xsdPlug = NULL;
4151	}
4152        if (reader->xsdValidCtxt != NULL) {
4153	    if (! reader->xsdPreserveCtxt)
4154		xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4155	    reader->xsdValidCtxt = NULL;
4156        }
4157	reader->xsdPreserveCtxt = 0;
4158        if (reader->xsdSchemas != NULL) {
4159	    xmlSchemaFree(reader->xsdSchemas);
4160	    reader->xsdSchemas = NULL;
4161	}
4162	return(0);
4163    }
4164    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4165	return(-1);
4166    if (reader->xsdPlug != NULL) {
4167	xmlSchemaSAXUnplug(reader->xsdPlug);
4168	reader->xsdPlug = NULL;
4169    }
4170    if (reader->xsdValidCtxt != NULL) {
4171	if (! reader->xsdPreserveCtxt)
4172	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4173	reader->xsdValidCtxt = NULL;
4174    }
4175    reader->xsdPreserveCtxt = 0;
4176    if (reader->xsdSchemas != NULL) {
4177	xmlSchemaFree(reader->xsdSchemas);
4178	reader->xsdSchemas = NULL;
4179    }
4180    reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
4181    if (reader->xsdValidCtxt == NULL) {
4182	xmlSchemaFree(reader->xsdSchemas);
4183	reader->xsdSchemas = NULL;
4184        return(-1);
4185    }
4186    reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4187                                       &(reader->ctxt->sax),
4188				       &(reader->ctxt->userData));
4189    if (reader->xsdPlug == NULL) {
4190	xmlSchemaFree(reader->xsdSchemas);
4191	reader->xsdSchemas = NULL;
4192	xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4193	reader->xsdValidCtxt = NULL;
4194	return(-1);
4195    }
4196    if (reader->errorFunc != NULL) {
4197	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4198			xmlTextReaderValidityErrorRelay,
4199			xmlTextReaderValidityWarningRelay,
4200			reader);
4201    }
4202	if (reader->sErrorFunc != NULL) {
4203		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4204			xmlTextReaderValidityStructuredRelay,
4205			reader);
4206    }
4207    reader->xsdValidErrors = 0;
4208    reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4209    return(0);
4210}
4211
4212/**
4213 * xmlTextReaderRelaxNGValidate:
4214 * @reader:  the xmlTextReaderPtr used
4215 * @rng:  the path to a RelaxNG schema or NULL
4216 *
4217 * Use RelaxNG to validate the document as it is processed.
4218 * Activation is only possible before the first Read().
4219 * if @rng is NULL, then RelaxNG validation is deactivated.
4220 *
4221 * Returns 0 in case the RelaxNG validation could be (de)activated and
4222 *         -1 in case of error.
4223 */
4224int
4225xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
4226    xmlRelaxNGParserCtxtPtr ctxt;
4227
4228    if (reader == NULL)
4229        return(-1);
4230
4231    if (rng == NULL) {
4232        if (reader->rngValidCtxt != NULL) {
4233	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4234	    reader->rngValidCtxt = NULL;
4235        }
4236        if (reader->rngSchemas != NULL) {
4237	    xmlRelaxNGFree(reader->rngSchemas);
4238	    reader->rngSchemas = NULL;
4239	}
4240	return(0);
4241    }
4242    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4243	return(-1);
4244    if (reader->rngSchemas != NULL) {
4245	xmlRelaxNGFree(reader->rngSchemas);
4246	reader->rngSchemas = NULL;
4247    }
4248    if (reader->rngValidCtxt != NULL) {
4249	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4250	reader->rngValidCtxt = NULL;
4251    }
4252    ctxt = xmlRelaxNGNewParserCtxt(rng);
4253    if (reader->errorFunc != NULL) {
4254	xmlRelaxNGSetParserErrors(ctxt,
4255			 xmlTextReaderValidityErrorRelay,
4256			 xmlTextReaderValidityWarningRelay,
4257			 reader);
4258    }
4259    if (reader->sErrorFunc != NULL) {
4260	xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4261			xmlTextReaderValidityStructuredRelay,
4262			reader);
4263    }
4264    reader->rngSchemas = xmlRelaxNGParse(ctxt);
4265    xmlRelaxNGFreeParserCtxt(ctxt);
4266    if (reader->rngSchemas == NULL)
4267        return(-1);
4268    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
4269    if (reader->rngValidCtxt == NULL) {
4270	xmlRelaxNGFree(reader->rngSchemas);
4271	reader->rngSchemas = NULL;
4272        return(-1);
4273    }
4274    if (reader->errorFunc != NULL) {
4275	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4276			 xmlTextReaderValidityErrorRelay,
4277			 xmlTextReaderValidityWarningRelay,
4278			 reader);
4279    }
4280	if (reader->sErrorFunc != NULL) {
4281		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4282			xmlTextReaderValidityStructuredRelay,
4283			reader);
4284    }
4285    reader->rngValidErrors = 0;
4286    reader->rngFullNode = NULL;
4287    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4288    return(0);
4289}
4290
4291/**
4292 * xmlTextReaderSchemaValidateInternal:
4293 * @reader:  the xmlTextReaderPtr used
4294 * @xsd:  the path to a W3C XSD schema or NULL
4295 * @ctxt: the XML Schema validation context or NULL
4296 * @options: options (not used yet)
4297 *
4298 * Validate the document as it is processed using XML Schema.
4299 * Activation is only possible before the first Read().
4300 * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
4301 *
4302 * Returns 0 in case the schemas validation could be (de)activated and
4303 *         -1 in case of error.
4304 */
4305static int
4306xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
4307				    const char *xsd,
4308				    xmlSchemaValidCtxtPtr ctxt,
4309				    int options ATTRIBUTE_UNUSED)
4310{
4311    if (reader == NULL)
4312        return(-1);
4313
4314    if ((xsd != NULL) && (ctxt != NULL))
4315	return(-1);
4316
4317    if (((xsd != NULL) || (ctxt != NULL)) &&
4318	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
4319        (reader->ctxt == NULL)))
4320	return(-1);
4321
4322    /* Cleanup previous validation stuff. */
4323    if (reader->xsdPlug != NULL) {
4324	xmlSchemaSAXUnplug(reader->xsdPlug);
4325	reader->xsdPlug = NULL;
4326    }
4327    if (reader->xsdValidCtxt != NULL) {
4328	if (! reader->xsdPreserveCtxt)
4329	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4330	reader->xsdValidCtxt = NULL;
4331    }
4332    reader->xsdPreserveCtxt = 0;
4333    if (reader->xsdSchemas != NULL) {
4334	xmlSchemaFree(reader->xsdSchemas);
4335	reader->xsdSchemas = NULL;
4336    }
4337
4338    if ((xsd == NULL) && (ctxt == NULL)) {
4339	/* We just want to deactivate the validation, so get out. */
4340	return(0);
4341    }
4342
4343    if (xsd != NULL) {
4344	xmlSchemaParserCtxtPtr pctxt;
4345	/* Parse the schema and create validation environment. */
4346	pctxt = xmlSchemaNewParserCtxt(xsd);
4347	if (reader->errorFunc != NULL) {
4348	    xmlSchemaSetParserErrors(pctxt,
4349		xmlTextReaderValidityErrorRelay,
4350		xmlTextReaderValidityWarningRelay,
4351		reader);
4352	}
4353	reader->xsdSchemas = xmlSchemaParse(pctxt);
4354	xmlSchemaFreeParserCtxt(pctxt);
4355	if (reader->xsdSchemas == NULL)
4356	    return(-1);
4357	reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
4358	if (reader->xsdValidCtxt == NULL) {
4359	    xmlSchemaFree(reader->xsdSchemas);
4360	    reader->xsdSchemas = NULL;
4361	    return(-1);
4362	}
4363	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4364	    &(reader->ctxt->sax),
4365	    &(reader->ctxt->userData));
4366	if (reader->xsdPlug == NULL) {
4367	    xmlSchemaFree(reader->xsdSchemas);
4368	    reader->xsdSchemas = NULL;
4369	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4370	    reader->xsdValidCtxt = NULL;
4371	    return(-1);
4372	}
4373    } else {
4374	/* Use the given validation context. */
4375	reader->xsdValidCtxt = ctxt;
4376	reader->xsdPreserveCtxt = 1;
4377	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4378	    &(reader->ctxt->sax),
4379	    &(reader->ctxt->userData));
4380	if (reader->xsdPlug == NULL) {
4381	    reader->xsdValidCtxt = NULL;
4382	    reader->xsdPreserveCtxt = 0;
4383	    return(-1);
4384	}
4385    }
4386    /*
4387    * Redirect the validation context's error channels to use
4388    * the reader channels.
4389    * TODO: In case the user provides the validation context we
4390    *   could make this redirection optional.
4391    */
4392    if (reader->errorFunc != NULL) {
4393	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4394			 xmlTextReaderValidityErrorRelay,
4395			 xmlTextReaderValidityWarningRelay,
4396			 reader);
4397    }
4398	if (reader->sErrorFunc != NULL) {
4399		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4400			xmlTextReaderValidityStructuredRelay,
4401			reader);
4402    }
4403    reader->xsdValidErrors = 0;
4404    reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4405    return(0);
4406}
4407
4408/**
4409 * xmlTextReaderSchemaValidateCtxt:
4410 * @reader:  the xmlTextReaderPtr used
4411 * @ctxt: the XML Schema validation context or NULL
4412 * @options: options (not used yet)
4413 *
4414 * Use W3C XSD schema context to validate the document as it is processed.
4415 * Activation is only possible before the first Read().
4416 * If @ctxt is NULL, then XML Schema validation is deactivated.
4417 *
4418 * Returns 0 in case the schemas validation could be (de)activated and
4419 *         -1 in case of error.
4420 */
4421int
4422xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
4423				    xmlSchemaValidCtxtPtr ctxt,
4424				    int options)
4425{
4426    return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
4427}
4428
4429/**
4430 * xmlTextReaderSchemaValidate:
4431 * @reader:  the xmlTextReaderPtr used
4432 * @xsd:  the path to a W3C XSD schema or NULL
4433 *
4434 * Use W3C XSD schema to validate the document as it is processed.
4435 * Activation is only possible before the first Read().
4436 * If @xsd is NULL, then XML Schema validation is deactivated.
4437 *
4438 * Returns 0 in case the schemas validation could be (de)activated and
4439 *         -1 in case of error.
4440 */
4441int
4442xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
4443{
4444    return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
4445}
4446#endif
4447
4448/**
4449 * xmlTextReaderIsNamespaceDecl:
4450 * @reader: the xmlTextReaderPtr used
4451 *
4452 * Determine whether the current node is a namespace declaration
4453 * rather than a regular attribute.
4454 *
4455 * Returns 1 if the current node is a namespace declaration, 0 if it
4456 * is a regular attribute or other type of node, or -1 in case of
4457 * error.
4458 */
4459int
4460xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
4461    xmlNodePtr node;
4462    if (reader == NULL)
4463	return(-1);
4464    if (reader->node == NULL)
4465	return(-1);
4466    if (reader->curnode != NULL)
4467	node = reader->curnode;
4468    else
4469	node = reader->node;
4470
4471    if (XML_NAMESPACE_DECL == node->type)
4472	return(1);
4473    else
4474	return(0);
4475}
4476
4477/**
4478 * xmlTextReaderConstXmlVersion:
4479 * @reader:  the xmlTextReaderPtr used
4480 *
4481 * Determine the XML version of the document being read.
4482 *
4483 * Returns a string containing the XML version of the document or NULL
4484 * in case of error.  The string is deallocated with the reader.
4485 */
4486const xmlChar *
4487xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
4488    xmlDocPtr doc = NULL;
4489    if (reader == NULL)
4490	return(NULL);
4491    if (reader->doc != NULL)
4492        doc = reader->doc;
4493    else if (reader->ctxt != NULL)
4494	doc = reader->ctxt->myDoc;
4495    if (doc == NULL)
4496	return(NULL);
4497
4498    if (doc->version == NULL)
4499	return(NULL);
4500    else
4501      return(CONSTSTR(doc->version));
4502}
4503
4504/**
4505 * xmlTextReaderStandalone:
4506 * @reader:  the xmlTextReaderPtr used
4507 *
4508 * Determine the standalone status of the document being read.
4509 *
4510 * Returns 1 if the document was declared to be standalone, 0 if it
4511 * was declared to be not standalone, or -1 if the document did not
4512 * specify its standalone status or in case of error.
4513 */
4514int
4515xmlTextReaderStandalone(xmlTextReaderPtr reader) {
4516    xmlDocPtr doc = NULL;
4517    if (reader == NULL)
4518	return(-1);
4519    if (reader->doc != NULL)
4520        doc = reader->doc;
4521    else if (reader->ctxt != NULL)
4522	doc = reader->ctxt->myDoc;
4523    if (doc == NULL)
4524	return(-1);
4525
4526    return(doc->standalone);
4527}
4528
4529/************************************************************************
4530 *									*
4531 *			Error Handling Extensions                       *
4532 *									*
4533 ************************************************************************/
4534
4535/* helper to build a xmlMalloc'ed string from a format and va_list */
4536static char *
4537xmlTextReaderBuildMessage(const char *msg, va_list ap) {
4538    int size = 0;
4539    int chars;
4540    char *larger;
4541    char *str = NULL;
4542    va_list aq;
4543
4544    while (1) {
4545        VA_COPY(aq, ap);
4546        chars = vsnprintf(str, size, msg, aq);
4547        va_end(aq);
4548        if (chars < 0) {
4549	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
4550	    if (str)
4551		xmlFree(str);
4552	    return NULL;
4553	}
4554	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
4555            break;
4556        if (chars < MAX_ERR_MSG_SIZE)
4557	size = chars + 1;
4558	else
4559		size = MAX_ERR_MSG_SIZE;
4560        if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
4561	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
4562	    if (str)
4563                xmlFree(str);
4564            return NULL;
4565        }
4566        str = larger;
4567    }
4568
4569    return str;
4570}
4571
4572/**
4573 * xmlTextReaderLocatorLineNumber:
4574 * @locator: the xmlTextReaderLocatorPtr used
4575 *
4576 * Obtain the line number for the given locator.
4577 *
4578 * Returns the line number or -1 in case of error.
4579 */
4580int
4581xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
4582    /* we know that locator is a xmlParserCtxtPtr */
4583    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4584    int ret = -1;
4585
4586    if (locator == NULL)
4587        return(-1);
4588    if (ctx->node != NULL) {
4589	ret = xmlGetLineNo(ctx->node);
4590    }
4591    else {
4592	/* inspired from error.c */
4593	xmlParserInputPtr input;
4594	input = ctx->input;
4595	if ((input->filename == NULL) && (ctx->inputNr > 1))
4596	    input = ctx->inputTab[ctx->inputNr - 2];
4597	if (input != NULL) {
4598	    ret = input->line;
4599	}
4600	else {
4601	    ret = -1;
4602	}
4603    }
4604
4605    return ret;
4606}
4607
4608/**
4609 * xmlTextReaderLocatorBaseURI:
4610 * @locator: the xmlTextReaderLocatorPtr used
4611 *
4612 * Obtain the base URI for the given locator.
4613 *
4614 * Returns the base URI or NULL in case of error,
4615 *    if non NULL it need to be freed by the caller.
4616 */
4617xmlChar *
4618xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
4619    /* we know that locator is a xmlParserCtxtPtr */
4620    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4621    xmlChar *ret = NULL;
4622
4623    if (locator == NULL)
4624        return(NULL);
4625    if (ctx->node != NULL) {
4626	ret = xmlNodeGetBase(NULL,ctx->node);
4627    }
4628    else {
4629	/* inspired from error.c */
4630	xmlParserInputPtr input;
4631	input = ctx->input;
4632	if ((input->filename == NULL) && (ctx->inputNr > 1))
4633	    input = ctx->inputTab[ctx->inputNr - 2];
4634	if (input != NULL) {
4635	    ret = xmlStrdup(BAD_CAST input->filename);
4636	}
4637	else {
4638	    ret = NULL;
4639	}
4640    }
4641
4642    return ret;
4643}
4644
4645static void
4646xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
4647                          char *str)
4648{
4649    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4650
4651    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4652
4653    if (str != NULL) {
4654        if (reader->errorFunc)
4655            reader->errorFunc(reader->errorFuncArg, str, severity,
4656                              (xmlTextReaderLocatorPtr) ctx);
4657        xmlFree(str);
4658    }
4659}
4660
4661static void
4662xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error)
4663{
4664    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4665
4666    xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4667
4668    if (error && reader->sErrorFunc) {
4669        reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
4670    }
4671}
4672
4673static void XMLCDECL
4674xmlTextReaderError(void *ctxt, const char *msg, ...)
4675{
4676    va_list ap;
4677
4678    va_start(ap, msg);
4679    xmlTextReaderGenericError(ctxt,
4680                              XML_PARSER_SEVERITY_ERROR,
4681                              xmlTextReaderBuildMessage(msg, ap));
4682    va_end(ap);
4683
4684}
4685
4686static void XMLCDECL
4687xmlTextReaderWarning(void *ctxt, const char *msg, ...)
4688{
4689    va_list ap;
4690
4691    va_start(ap, msg);
4692    xmlTextReaderGenericError(ctxt,
4693                              XML_PARSER_SEVERITY_WARNING,
4694                              xmlTextReaderBuildMessage(msg, ap));
4695    va_end(ap);
4696}
4697
4698static void XMLCDECL
4699xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
4700{
4701    va_list ap;
4702
4703    int len = xmlStrlen((const xmlChar *) msg);
4704
4705    if ((len > 1) && (msg[len - 2] != ':')) {
4706        /*
4707         * some callbacks only report locator information:
4708         * skip them (mimicking behaviour in error.c)
4709         */
4710        va_start(ap, msg);
4711        xmlTextReaderGenericError(ctxt,
4712                                  XML_PARSER_SEVERITY_VALIDITY_ERROR,
4713                                  xmlTextReaderBuildMessage(msg, ap));
4714        va_end(ap);
4715    }
4716}
4717
4718static void XMLCDECL
4719xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
4720{
4721    va_list ap;
4722
4723    int len = xmlStrlen((const xmlChar *) msg);
4724
4725    if ((len != 0) && (msg[len - 1] != ':')) {
4726        /*
4727         * some callbacks only report locator information:
4728         * skip them (mimicking behaviour in error.c)
4729         */
4730        va_start(ap, msg);
4731        xmlTextReaderGenericError(ctxt,
4732                                  XML_PARSER_SEVERITY_VALIDITY_WARNING,
4733                                  xmlTextReaderBuildMessage(msg, ap));
4734        va_end(ap);
4735    }
4736}
4737
4738/**
4739 * xmlTextReaderSetErrorHandler:
4740 * @reader:  the xmlTextReaderPtr used
4741 * @f:	the callback function to call on error and warnings
4742 * @arg:    a user argument to pass to the callback function
4743 *
4744 * Register a callback function that will be called on error and warnings.
4745 *
4746 * If @f is NULL, the default error and warning handlers are restored.
4747 */
4748void
4749xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
4750                             xmlTextReaderErrorFunc f, void *arg)
4751{
4752    if (f != NULL) {
4753        reader->ctxt->sax->error = xmlTextReaderError;
4754        reader->ctxt->sax->serror = NULL;
4755        reader->ctxt->vctxt.error = xmlTextReaderValidityError;
4756        reader->ctxt->sax->warning = xmlTextReaderWarning;
4757        reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
4758        reader->errorFunc = f;
4759        reader->sErrorFunc = NULL;
4760        reader->errorFuncArg = arg;
4761#ifdef LIBXML_SCHEMAS_ENABLED
4762        if (reader->rngValidCtxt) {
4763            xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4764                                     xmlTextReaderValidityErrorRelay,
4765                                     xmlTextReaderValidityWarningRelay,
4766                                     reader);
4767            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
4768                                               reader);
4769        }
4770        if (reader->xsdValidCtxt) {
4771            xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4772                                    xmlTextReaderValidityErrorRelay,
4773                                    xmlTextReaderValidityWarningRelay,
4774                                    reader);
4775            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
4776                                              reader);
4777        }
4778#endif
4779    } else {
4780        /* restore defaults */
4781        reader->ctxt->sax->error = xmlParserError;
4782        reader->ctxt->vctxt.error = xmlParserValidityError;
4783        reader->ctxt->sax->warning = xmlParserWarning;
4784        reader->ctxt->vctxt.warning = xmlParserValidityWarning;
4785        reader->errorFunc = NULL;
4786        reader->sErrorFunc = NULL;
4787        reader->errorFuncArg = NULL;
4788#ifdef LIBXML_SCHEMAS_ENABLED
4789        if (reader->rngValidCtxt) {
4790            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
4791                                     reader);
4792            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
4793                                               reader);
4794        }
4795        if (reader->xsdValidCtxt) {
4796            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
4797                                    reader);
4798            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
4799                                              reader);
4800        }
4801#endif
4802    }
4803}
4804
4805/**
4806* xmlTextReaderSetStructuredErrorHandler:
4807 * @reader:  the xmlTextReaderPtr used
4808 * @f:	the callback function to call on error and warnings
4809 * @arg:    a user argument to pass to the callback function
4810 *
4811 * Register a callback function that will be called on error and warnings.
4812 *
4813 * If @f is NULL, the default error and warning handlers are restored.
4814 */
4815void
4816xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
4817                                       xmlStructuredErrorFunc f, void *arg)
4818{
4819    if (f != NULL) {
4820        reader->ctxt->sax->error = NULL;
4821        reader->ctxt->sax->serror = xmlTextReaderStructuredError;
4822        reader->ctxt->vctxt.error = xmlTextReaderValidityError;
4823        reader->ctxt->sax->warning = xmlTextReaderWarning;
4824        reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
4825        reader->sErrorFunc = f;
4826        reader->errorFunc = NULL;
4827        reader->errorFuncArg = arg;
4828#ifdef LIBXML_SCHEMAS_ENABLED
4829        if (reader->rngValidCtxt) {
4830            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
4831                                     reader);
4832            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4833                                        xmlTextReaderValidityStructuredRelay,
4834                                               reader);
4835        }
4836        if (reader->xsdValidCtxt) {
4837            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
4838                                    reader);
4839            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4840                                       xmlTextReaderValidityStructuredRelay,
4841                                              reader);
4842        }
4843#endif
4844    } else {
4845        /* restore defaults */
4846        reader->ctxt->sax->error = xmlParserError;
4847        reader->ctxt->sax->serror = NULL;
4848        reader->ctxt->vctxt.error = xmlParserValidityError;
4849        reader->ctxt->sax->warning = xmlParserWarning;
4850        reader->ctxt->vctxt.warning = xmlParserValidityWarning;
4851        reader->errorFunc = NULL;
4852        reader->sErrorFunc = NULL;
4853        reader->errorFuncArg = NULL;
4854#ifdef LIBXML_SCHEMAS_ENABLED
4855        if (reader->rngValidCtxt) {
4856            xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
4857                                     reader);
4858            xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
4859                                               reader);
4860        }
4861        if (reader->xsdValidCtxt) {
4862            xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
4863                                    reader);
4864            xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
4865                                              reader);
4866        }
4867#endif
4868    }
4869}
4870
4871/**
4872 * xmlTextReaderIsValid:
4873 * @reader:  the xmlTextReaderPtr used
4874 *
4875 * Retrieve the validity status from the parser context
4876 *
4877 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
4878 */
4879int
4880xmlTextReaderIsValid(xmlTextReaderPtr reader)
4881{
4882    if (reader == NULL)
4883        return (-1);
4884#ifdef LIBXML_SCHEMAS_ENABLED
4885    if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
4886        return (reader->rngValidErrors == 0);
4887    if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
4888        return (reader->xsdValidErrors == 0);
4889#endif
4890    if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
4891        return (reader->ctxt->valid);
4892    return (0);
4893}
4894
4895/**
4896 * xmlTextReaderGetErrorHandler:
4897 * @reader:  the xmlTextReaderPtr used
4898 * @f:	the callback function or NULL is no callback has been registered
4899 * @arg:    a user argument
4900 *
4901 * Retrieve the error callback function and user argument.
4902 */
4903void
4904xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
4905                             xmlTextReaderErrorFunc * f, void **arg)
4906{
4907    if (f != NULL)
4908        *f = reader->errorFunc;
4909    if (arg != NULL)
4910        *arg = reader->errorFuncArg;
4911}
4912/************************************************************************
4913 *									*
4914 *	New set (2.6.0) of simpler and more flexible APIs		*
4915 *									*
4916 ************************************************************************/
4917
4918/**
4919 * xmlTextReaderSetup:
4920 * @reader:  an XML reader
4921 * @input: xmlParserInputBufferPtr used to feed the reader, will
4922 *         be destroyed with it.
4923 * @URL:  the base URL to use for the document
4924 * @encoding:  the document encoding, or NULL
4925 * @options:  a combination of xmlParserOption
4926 *
4927 * Setup an XML reader with new options
4928 *
4929 * Returns 0 in case of success and -1 in case of error.
4930 */
4931int
4932xmlTextReaderSetup(xmlTextReaderPtr reader,
4933                   xmlParserInputBufferPtr input, const char *URL,
4934                   const char *encoding, int options)
4935{
4936    if (reader == NULL) {
4937        if (input != NULL)
4938	    xmlFreeParserInputBuffer(input);
4939        return (-1);
4940    }
4941
4942    /*
4943     * we force the generation of compact text nodes on the reader
4944     * since usr applications should never modify the tree
4945     */
4946    options |= XML_PARSE_COMPACT;
4947
4948    reader->doc = NULL;
4949    reader->entNr = 0;
4950    reader->parserFlags = options;
4951    reader->validate = XML_TEXTREADER_NOT_VALIDATE;
4952    if ((input != NULL) && (reader->input != NULL) &&
4953        (reader->allocs & XML_TEXTREADER_INPUT)) {
4954	xmlFreeParserInputBuffer(reader->input);
4955	reader->input = NULL;
4956	reader->allocs -= XML_TEXTREADER_INPUT;
4957    }
4958    if (input != NULL) {
4959	reader->input = input;
4960	reader->allocs |= XML_TEXTREADER_INPUT;
4961    }
4962    if (reader->buffer == NULL)
4963        reader->buffer = xmlBufferCreateSize(100);
4964    if (reader->buffer == NULL) {
4965        xmlGenericError(xmlGenericErrorContext,
4966                        "xmlTextReaderSetup : malloc failed\n");
4967        return (-1);
4968    }
4969    if (reader->sax == NULL)
4970	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
4971    if (reader->sax == NULL) {
4972        xmlGenericError(xmlGenericErrorContext,
4973                        "xmlTextReaderSetup : malloc failed\n");
4974        return (-1);
4975    }
4976    xmlSAXVersion(reader->sax, 2);
4977    reader->startElement = reader->sax->startElement;
4978    reader->sax->startElement = xmlTextReaderStartElement;
4979    reader->endElement = reader->sax->endElement;
4980    reader->sax->endElement = xmlTextReaderEndElement;
4981#ifdef LIBXML_SAX1_ENABLED
4982    if (reader->sax->initialized == XML_SAX2_MAGIC) {
4983#endif /* LIBXML_SAX1_ENABLED */
4984        reader->startElementNs = reader->sax->startElementNs;
4985        reader->sax->startElementNs = xmlTextReaderStartElementNs;
4986        reader->endElementNs = reader->sax->endElementNs;
4987        reader->sax->endElementNs = xmlTextReaderEndElementNs;
4988#ifdef LIBXML_SAX1_ENABLED
4989    } else {
4990        reader->startElementNs = NULL;
4991        reader->endElementNs = NULL;
4992    }
4993#endif /* LIBXML_SAX1_ENABLED */
4994    reader->characters = reader->sax->characters;
4995    reader->sax->characters = xmlTextReaderCharacters;
4996    reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
4997    reader->cdataBlock = reader->sax->cdataBlock;
4998    reader->sax->cdataBlock = xmlTextReaderCDataBlock;
4999
5000    reader->mode = XML_TEXTREADER_MODE_INITIAL;
5001    reader->node = NULL;
5002    reader->curnode = NULL;
5003    if (input != NULL) {
5004        if (reader->input->buffer->use < 4) {
5005            xmlParserInputBufferRead(input, 4);
5006        }
5007        if (reader->ctxt == NULL) {
5008            if (reader->input->buffer->use >= 4) {
5009                reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
5010		       (const char *) reader->input->buffer->content, 4, URL);
5011                reader->base = 0;
5012                reader->cur = 4;
5013            } else {
5014                reader->ctxt =
5015                    xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
5016                reader->base = 0;
5017                reader->cur = 0;
5018            }
5019        } else {
5020	    xmlParserInputPtr inputStream;
5021	    xmlParserInputBufferPtr buf;
5022	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
5023
5024	    xmlCtxtReset(reader->ctxt);
5025	    buf = xmlAllocParserInputBuffer(enc);
5026	    if (buf == NULL) return(-1);
5027	    inputStream = xmlNewInputStream(reader->ctxt);
5028	    if (inputStream == NULL) {
5029		xmlFreeParserInputBuffer(buf);
5030		return(-1);
5031	    }
5032
5033	    if (URL == NULL)
5034		inputStream->filename = NULL;
5035	    else
5036		inputStream->filename = (char *)
5037		    xmlCanonicPath((const xmlChar *) URL);
5038	    inputStream->buf = buf;
5039	    inputStream->base = inputStream->buf->buffer->content;
5040	    inputStream->cur = inputStream->buf->buffer->content;
5041	    inputStream->end =
5042            &inputStream->buf->buffer->content[inputStream->buf->buffer->use];
5043
5044	    inputPush(reader->ctxt, inputStream);
5045	    reader->cur = 0;
5046	}
5047        if (reader->ctxt == NULL) {
5048            xmlGenericError(xmlGenericErrorContext,
5049                            "xmlTextReaderSetup : malloc failed\n");
5050            return (-1);
5051        }
5052    }
5053    if (reader->dict != NULL) {
5054        if (reader->ctxt->dict != NULL) {
5055	    if (reader->dict != reader->ctxt->dict) {
5056		xmlDictFree(reader->dict);
5057		reader->dict = reader->ctxt->dict;
5058	    }
5059	} else {
5060	    reader->ctxt->dict = reader->dict;
5061	}
5062    } else {
5063	if (reader->ctxt->dict == NULL)
5064	    reader->ctxt->dict = xmlDictCreate();
5065        reader->dict = reader->ctxt->dict;
5066    }
5067    reader->ctxt->_private = reader;
5068    reader->ctxt->linenumbers = 1;
5069    reader->ctxt->dictNames = 1;
5070    /*
5071     * use the parser dictionnary to allocate all elements and attributes names
5072     */
5073    reader->ctxt->docdict = 1;
5074    reader->ctxt->parseMode = XML_PARSE_READER;
5075
5076#ifdef LIBXML_XINCLUDE_ENABLED
5077    if (reader->xincctxt != NULL) {
5078	xmlXIncludeFreeContext(reader->xincctxt);
5079	reader->xincctxt = NULL;
5080    }
5081    if (options & XML_PARSE_XINCLUDE) {
5082        reader->xinclude = 1;
5083	reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
5084	options -= XML_PARSE_XINCLUDE;
5085    } else
5086        reader->xinclude = 0;
5087    reader->in_xinclude = 0;
5088#endif
5089#ifdef LIBXML_PATTERN_ENABLED
5090    if (reader->patternTab == NULL) {
5091        reader->patternNr = 0;
5092	reader->patternMax = 0;
5093    }
5094    while (reader->patternNr > 0) {
5095        reader->patternNr--;
5096	if (reader->patternTab[reader->patternNr] != NULL) {
5097	    xmlFreePattern(reader->patternTab[reader->patternNr]);
5098            reader->patternTab[reader->patternNr] = NULL;
5099	}
5100    }
5101#endif
5102
5103    if (options & XML_PARSE_DTDVALID)
5104        reader->validate = XML_TEXTREADER_VALIDATE_DTD;
5105
5106    xmlCtxtUseOptions(reader->ctxt, options);
5107    if (encoding != NULL) {
5108        xmlCharEncodingHandlerPtr hdlr;
5109
5110        hdlr = xmlFindCharEncodingHandler(encoding);
5111        if (hdlr != NULL)
5112            xmlSwitchToEncoding(reader->ctxt, hdlr);
5113    }
5114    if ((URL != NULL) && (reader->ctxt->input != NULL) &&
5115        (reader->ctxt->input->filename == NULL))
5116        reader->ctxt->input->filename = (char *)
5117            xmlStrdup((const xmlChar *) URL);
5118
5119    reader->doc = NULL;
5120
5121    return (0);
5122}
5123
5124/**
5125 * xmlTextReaderByteConsumed:
5126 * @reader: an XML reader
5127 *
5128 * This function provides the current index of the parser used
5129 * by the reader, relative to the start of the current entity.
5130 * This function actually just wraps a call to xmlBytesConsumed()
5131 * for the parser context associated with the reader.
5132 * See xmlBytesConsumed() for more information.
5133 *
5134 * Returns the index in bytes from the beginning of the entity or -1
5135 *         in case the index could not be computed.
5136 */
5137long
5138xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
5139    if ((reader == NULL) || (reader->ctxt == NULL))
5140        return(-1);
5141    return(xmlByteConsumed(reader->ctxt));
5142}
5143
5144
5145/**
5146 * xmlReaderWalker:
5147 * @doc:  a preparsed document
5148 *
5149 * Create an xmltextReader for a preparsed document.
5150 *
5151 * Returns the new reader or NULL in case of error.
5152 */
5153xmlTextReaderPtr
5154xmlReaderWalker(xmlDocPtr doc)
5155{
5156    xmlTextReaderPtr ret;
5157
5158    if (doc == NULL)
5159        return(NULL);
5160
5161    ret = xmlMalloc(sizeof(xmlTextReader));
5162    if (ret == NULL) {
5163        xmlGenericError(xmlGenericErrorContext,
5164		"xmlNewTextReader : malloc failed\n");
5165	return(NULL);
5166    }
5167    memset(ret, 0, sizeof(xmlTextReader));
5168    ret->entNr = 0;
5169    ret->input = NULL;
5170    ret->mode = XML_TEXTREADER_MODE_INITIAL;
5171    ret->node = NULL;
5172    ret->curnode = NULL;
5173    ret->base = 0;
5174    ret->cur = 0;
5175    ret->allocs = XML_TEXTREADER_CTXT;
5176    ret->doc = doc;
5177    ret->state = XML_TEXTREADER_START;
5178    ret->dict = xmlDictCreate();
5179    return(ret);
5180}
5181
5182/**
5183 * xmlReaderForDoc:
5184 * @cur:  a pointer to a zero terminated string
5185 * @URL:  the base URL to use for the document
5186 * @encoding:  the document encoding, or NULL
5187 * @options:  a combination of xmlParserOption
5188 *
5189 * Create an xmltextReader for an XML in-memory document.
5190 * The parsing flags @options are a combination of xmlParserOption.
5191 *
5192 * Returns the new reader or NULL in case of error.
5193 */
5194xmlTextReaderPtr
5195xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
5196                int options)
5197{
5198    int len;
5199
5200    if (cur == NULL)
5201        return (NULL);
5202    len = xmlStrlen(cur);
5203
5204    return (xmlReaderForMemory
5205            ((const char *) cur, len, URL, encoding, options));
5206}
5207
5208/**
5209 * xmlReaderForFile:
5210 * @filename:  a file or URL
5211 * @encoding:  the document encoding, or NULL
5212 * @options:  a combination of xmlParserOption
5213 *
5214 * parse an XML file from the filesystem or the network.
5215 * The parsing flags @options are a combination of xmlParserOption.
5216 *
5217 * Returns the new reader or NULL in case of error.
5218 */
5219xmlTextReaderPtr
5220xmlReaderForFile(const char *filename, const char *encoding, int options)
5221{
5222    xmlTextReaderPtr reader;
5223
5224    reader = xmlNewTextReaderFilename(filename);
5225    if (reader == NULL)
5226        return (NULL);
5227    xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
5228    return (reader);
5229}
5230
5231/**
5232 * xmlReaderForMemory:
5233 * @buffer:  a pointer to a char array
5234 * @size:  the size of the array
5235 * @URL:  the base URL to use for the document
5236 * @encoding:  the document encoding, or NULL
5237 * @options:  a combination of xmlParserOption
5238 *
5239 * Create an xmltextReader for an XML in-memory document.
5240 * The parsing flags @options are a combination of xmlParserOption.
5241 *
5242 * Returns the new reader or NULL in case of error.
5243 */
5244xmlTextReaderPtr
5245xmlReaderForMemory(const char *buffer, int size, const char *URL,
5246                   const char *encoding, int options)
5247{
5248    xmlTextReaderPtr reader;
5249    xmlParserInputBufferPtr buf;
5250
5251    buf = xmlParserInputBufferCreateStatic(buffer, size,
5252                                      XML_CHAR_ENCODING_NONE);
5253    if (buf == NULL) {
5254        return (NULL);
5255    }
5256    reader = xmlNewTextReader(buf, URL);
5257    if (reader == NULL) {
5258        xmlFreeParserInputBuffer(buf);
5259        return (NULL);
5260    }
5261    reader->allocs |= XML_TEXTREADER_INPUT;
5262    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5263    return (reader);
5264}
5265
5266/**
5267 * xmlReaderForFd:
5268 * @fd:  an open file descriptor
5269 * @URL:  the base URL to use for the document
5270 * @encoding:  the document encoding, or NULL
5271 * @options:  a combination of xmlParserOption
5272 *
5273 * Create an xmltextReader for an XML from a file descriptor.
5274 * The parsing flags @options are a combination of xmlParserOption.
5275 * NOTE that the file descriptor will not be closed when the
5276 *      reader is closed or reset.
5277 *
5278 * Returns the new reader or NULL in case of error.
5279 */
5280xmlTextReaderPtr
5281xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
5282{
5283    xmlTextReaderPtr reader;
5284    xmlParserInputBufferPtr input;
5285
5286    if (fd < 0)
5287        return (NULL);
5288
5289    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5290    if (input == NULL)
5291        return (NULL);
5292    input->closecallback = NULL;
5293    reader = xmlNewTextReader(input, URL);
5294    if (reader == NULL) {
5295        xmlFreeParserInputBuffer(input);
5296        return (NULL);
5297    }
5298    reader->allocs |= XML_TEXTREADER_INPUT;
5299    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5300    return (reader);
5301}
5302
5303/**
5304 * xmlReaderForIO:
5305 * @ioread:  an I/O read function
5306 * @ioclose:  an I/O close function
5307 * @ioctx:  an I/O handler
5308 * @URL:  the base URL to use for the document
5309 * @encoding:  the document encoding, or NULL
5310 * @options:  a combination of xmlParserOption
5311 *
5312 * Create an xmltextReader for an XML document from I/O functions and source.
5313 * The parsing flags @options are a combination of xmlParserOption.
5314 *
5315 * Returns the new reader or NULL in case of error.
5316 */
5317xmlTextReaderPtr
5318xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
5319               void *ioctx, const char *URL, const char *encoding,
5320               int options)
5321{
5322    xmlTextReaderPtr reader;
5323    xmlParserInputBufferPtr input;
5324
5325    if (ioread == NULL)
5326        return (NULL);
5327
5328    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5329                                         XML_CHAR_ENCODING_NONE);
5330    if (input == NULL)
5331        return (NULL);
5332    reader = xmlNewTextReader(input, URL);
5333    if (reader == NULL) {
5334        xmlFreeParserInputBuffer(input);
5335        return (NULL);
5336    }
5337    reader->allocs |= XML_TEXTREADER_INPUT;
5338    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5339    return (reader);
5340}
5341
5342/**
5343 * xmlReaderNewWalker:
5344 * @reader:  an XML reader
5345 * @doc:  a preparsed document
5346 *
5347 * Setup an xmltextReader to parse a preparsed XML document.
5348 * This reuses the existing @reader xmlTextReader.
5349 *
5350 * Returns 0 in case of success and -1 in case of error
5351 */
5352int
5353xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
5354{
5355    if (doc == NULL)
5356        return (-1);
5357    if (reader == NULL)
5358        return (-1);
5359
5360    if (reader->input != NULL) {
5361        xmlFreeParserInputBuffer(reader->input);
5362    }
5363    if (reader->ctxt != NULL) {
5364	xmlCtxtReset(reader->ctxt);
5365    }
5366
5367    reader->entNr = 0;
5368    reader->input = NULL;
5369    reader->mode = XML_TEXTREADER_MODE_INITIAL;
5370    reader->node = NULL;
5371    reader->curnode = NULL;
5372    reader->base = 0;
5373    reader->cur = 0;
5374    reader->allocs = XML_TEXTREADER_CTXT;
5375    reader->doc = doc;
5376    reader->state = XML_TEXTREADER_START;
5377    if (reader->dict == NULL) {
5378        if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
5379	    reader->dict = reader->ctxt->dict;
5380	else
5381	    reader->dict = xmlDictCreate();
5382    }
5383    return(0);
5384}
5385
5386/**
5387 * xmlReaderNewDoc:
5388 * @reader:  an XML reader
5389 * @cur:  a pointer to a zero terminated string
5390 * @URL:  the base URL to use for the document
5391 * @encoding:  the document encoding, or NULL
5392 * @options:  a combination of xmlParserOption
5393 *
5394 * Setup an xmltextReader to parse an XML in-memory document.
5395 * The parsing flags @options are a combination of xmlParserOption.
5396 * This reuses the existing @reader xmlTextReader.
5397 *
5398 * Returns 0 in case of success and -1 in case of error
5399 */
5400int
5401xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
5402                const char *URL, const char *encoding, int options)
5403{
5404
5405    int len;
5406
5407    if (cur == NULL)
5408        return (-1);
5409    if (reader == NULL)
5410        return (-1);
5411
5412    len = xmlStrlen(cur);
5413    return (xmlReaderNewMemory(reader, (const char *)cur, len,
5414                               URL, encoding, options));
5415}
5416
5417/**
5418 * xmlReaderNewFile:
5419 * @reader:  an XML reader
5420 * @filename:  a file or URL
5421 * @encoding:  the document encoding, or NULL
5422 * @options:  a combination of xmlParserOption
5423 *
5424 * parse an XML file from the filesystem or the network.
5425 * The parsing flags @options are a combination of xmlParserOption.
5426 * This reuses the existing @reader xmlTextReader.
5427 *
5428 * Returns 0 in case of success and -1 in case of error
5429 */
5430int
5431xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
5432                 const char *encoding, int options)
5433{
5434    xmlParserInputBufferPtr input;
5435
5436    if (filename == NULL)
5437        return (-1);
5438    if (reader == NULL)
5439        return (-1);
5440
5441    input =
5442        xmlParserInputBufferCreateFilename(filename,
5443                                           XML_CHAR_ENCODING_NONE);
5444    if (input == NULL)
5445        return (-1);
5446    return (xmlTextReaderSetup(reader, input, filename, encoding, options));
5447}
5448
5449/**
5450 * xmlReaderNewMemory:
5451 * @reader:  an XML reader
5452 * @buffer:  a pointer to a char array
5453 * @size:  the size of the array
5454 * @URL:  the base URL to use for the document
5455 * @encoding:  the document encoding, or NULL
5456 * @options:  a combination of xmlParserOption
5457 *
5458 * Setup an xmltextReader to parse an XML in-memory document.
5459 * The parsing flags @options are a combination of xmlParserOption.
5460 * This reuses the existing @reader xmlTextReader.
5461 *
5462 * Returns 0 in case of success and -1 in case of error
5463 */
5464int
5465xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
5466                   const char *URL, const char *encoding, int options)
5467{
5468    xmlParserInputBufferPtr input;
5469
5470    if (reader == NULL)
5471        return (-1);
5472    if (buffer == NULL)
5473        return (-1);
5474
5475    input = xmlParserInputBufferCreateStatic(buffer, size,
5476                                      XML_CHAR_ENCODING_NONE);
5477    if (input == NULL) {
5478        return (-1);
5479    }
5480    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5481}
5482
5483/**
5484 * xmlReaderNewFd:
5485 * @reader:  an XML reader
5486 * @fd:  an open file descriptor
5487 * @URL:  the base URL to use for the document
5488 * @encoding:  the document encoding, or NULL
5489 * @options:  a combination of xmlParserOption
5490 *
5491 * Setup an xmltextReader to parse an XML from a file descriptor.
5492 * NOTE that the file descriptor will not be closed when the
5493 *      reader is closed or reset.
5494 * The parsing flags @options are a combination of xmlParserOption.
5495 * This reuses the existing @reader xmlTextReader.
5496 *
5497 * Returns 0 in case of success and -1 in case of error
5498 */
5499int
5500xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
5501               const char *URL, const char *encoding, int options)
5502{
5503    xmlParserInputBufferPtr input;
5504
5505    if (fd < 0)
5506        return (-1);
5507    if (reader == NULL)
5508        return (-1);
5509
5510    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5511    if (input == NULL)
5512        return (-1);
5513    input->closecallback = NULL;
5514    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5515}
5516
5517/**
5518 * xmlReaderNewIO:
5519 * @reader:  an XML reader
5520 * @ioread:  an I/O read function
5521 * @ioclose:  an I/O close function
5522 * @ioctx:  an I/O handler
5523 * @URL:  the base URL to use for the document
5524 * @encoding:  the document encoding, or NULL
5525 * @options:  a combination of xmlParserOption
5526 *
5527 * Setup an xmltextReader to parse an XML document from I/O functions
5528 * and source.
5529 * The parsing flags @options are a combination of xmlParserOption.
5530 * This reuses the existing @reader xmlTextReader.
5531 *
5532 * Returns 0 in case of success and -1 in case of error
5533 */
5534int
5535xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
5536               xmlInputCloseCallback ioclose, void *ioctx,
5537               const char *URL, const char *encoding, int options)
5538{
5539    xmlParserInputBufferPtr input;
5540
5541    if (ioread == NULL)
5542        return (-1);
5543    if (reader == NULL)
5544        return (-1);
5545
5546    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5547                                         XML_CHAR_ENCODING_NONE);
5548    if (input == NULL)
5549        return (-1);
5550    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5551}
5552/************************************************************************
5553 *									*
5554 *			Utilities					*
5555 *									*
5556 ************************************************************************/
5557#ifdef NOT_USED_YET
5558
5559/**
5560 * xmlBase64Decode:
5561 * @in:  the input buffer
5562 * @inlen:  the size of the input (in), the size read from it (out)
5563 * @to:  the output buffer
5564 * @tolen:  the size of the output (in), the size written to (out)
5565 *
5566 * Base64 decoder, reads from @in and save in @to
5567 * TODO: tell jody when this is actually exported
5568 *
5569 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
5570 *         2 if there wasn't enough space on the output or -1 in case of error.
5571 */
5572static int
5573xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
5574                unsigned char *to, unsigned long *tolen)
5575{
5576    unsigned long incur;        /* current index in in[] */
5577
5578    unsigned long inblk;        /* last block index in in[] */
5579
5580    unsigned long outcur;       /* current index in out[] */
5581
5582    unsigned long inmax;        /* size of in[] */
5583
5584    unsigned long outmax;       /* size of out[] */
5585
5586    unsigned char cur;          /* the current value read from in[] */
5587
5588    unsigned char intmp[4], outtmp[4];  /* temporary buffers for the convert */
5589
5590    int nbintmp;                /* number of byte in intmp[] */
5591
5592    int is_ignore;              /* cur should be ignored */
5593
5594    int is_end = 0;             /* the end of the base64 was found */
5595
5596    int retval = 1;
5597
5598    int i;
5599
5600    if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
5601        return (-1);
5602
5603    incur = 0;
5604    inblk = 0;
5605    outcur = 0;
5606    inmax = *inlen;
5607    outmax = *tolen;
5608    nbintmp = 0;
5609
5610    while (1) {
5611        if (incur >= inmax)
5612            break;
5613        cur = in[incur++];
5614        is_ignore = 0;
5615        if ((cur >= 'A') && (cur <= 'Z'))
5616            cur = cur - 'A';
5617        else if ((cur >= 'a') && (cur <= 'z'))
5618            cur = cur - 'a' + 26;
5619        else if ((cur >= '0') && (cur <= '9'))
5620            cur = cur - '0' + 52;
5621        else if (cur == '+')
5622            cur = 62;
5623        else if (cur == '/')
5624            cur = 63;
5625        else if (cur == '.')
5626            cur = 0;
5627        else if (cur == '=')    /*no op , end of the base64 stream */
5628            is_end = 1;
5629        else {
5630            is_ignore = 1;
5631            if (nbintmp == 0)
5632                inblk = incur;
5633        }
5634
5635        if (!is_ignore) {
5636            int nbouttmp = 3;
5637
5638            int is_break = 0;
5639
5640            if (is_end) {
5641                if (nbintmp == 0)
5642                    break;
5643                if ((nbintmp == 1) || (nbintmp == 2))
5644                    nbouttmp = 1;
5645                else
5646                    nbouttmp = 2;
5647                nbintmp = 3;
5648                is_break = 1;
5649            }
5650            intmp[nbintmp++] = cur;
5651            /*
5652             * if intmp is full, push the 4byte sequence as a 3 byte
5653             * sequence out
5654             */
5655            if (nbintmp == 4) {
5656                nbintmp = 0;
5657                outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
5658                outtmp[1] =
5659                    ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
5660                outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
5661                if (outcur + 3 >= outmax) {
5662                    retval = 2;
5663                    break;
5664                }
5665
5666                for (i = 0; i < nbouttmp; i++)
5667                    to[outcur++] = outtmp[i];
5668                inblk = incur;
5669            }
5670
5671            if (is_break) {
5672                retval = 0;
5673                break;
5674            }
5675        }
5676    }
5677
5678    *tolen = outcur;
5679    *inlen = inblk;
5680    return (retval);
5681}
5682
5683/*
5684 * Test routine for the xmlBase64Decode function
5685 */
5686#if 0
5687int
5688main(int argc, char **argv)
5689{
5690    char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
5691
5692    char output[100];
5693
5694    char output2[100];
5695
5696    char output3[100];
5697
5698    unsigned long inlen = strlen(input);
5699
5700    unsigned long outlen = 100;
5701
5702    int ret;
5703
5704    unsigned long cons, tmp, tmp2, prod;
5705
5706    /*
5707     * Direct
5708     */
5709    ret = xmlBase64Decode(input, &inlen, output, &outlen);
5710
5711    output[outlen] = 0;
5712    printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen,
5713           outlen, output)indent: Standard input:179: Error:Unmatched #endif
5714;
5715
5716    /*
5717     * output chunking
5718     */
5719    cons = 0;
5720    prod = 0;
5721    while (cons < inlen) {
5722        tmp = 5;
5723        tmp2 = inlen - cons;
5724
5725        printf("%ld %ld\n", cons, prod);
5726        ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
5727        cons += tmp2;
5728        prod += tmp;
5729        printf("%ld %ld\n", cons, prod);
5730    }
5731    output2[outlen] = 0;
5732    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
5733           prod, output2);
5734
5735    /*
5736     * input chunking
5737     */
5738    cons = 0;
5739    prod = 0;
5740    while (cons < inlen) {
5741        tmp = 100 - prod;
5742        tmp2 = inlen - cons;
5743        if (tmp2 > 5)
5744            tmp2 = 5;
5745
5746        printf("%ld %ld\n", cons, prod);
5747        ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
5748        cons += tmp2;
5749        prod += tmp;
5750        printf("%ld %ld\n", cons, prod);
5751    }
5752    output3[outlen] = 0;
5753    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
5754           prod, output3);
5755    return (0);
5756
5757}
5758#endif
5759#endif /* NOT_USED_YET */
5760#define bottom_xmlreader
5761#include "elfgcchack.h"
5762#endif /* LIBXML_READER_ENABLED */
5763