xmlreader.c revision 7e65fad1e3a60c2a550a046ac58d99bc06760a77
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 ((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->ctxt != NULL) {
2218        if (reader->dict == reader->ctxt->dict)
2219	    reader->dict = NULL;
2220	if (reader->ctxt->myDoc != NULL) {
2221	    if (reader->preserve == 0)
2222		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2223	    reader->ctxt->myDoc = NULL;
2224	}
2225	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
2226	    (reader->ctxt->vctxt.vstateMax > 0)){
2227	    xmlFree(reader->ctxt->vctxt.vstateTab);
2228	    reader->ctxt->vctxt.vstateTab = NULL;
2229	    reader->ctxt->vctxt.vstateMax = 0;
2230	}
2231	if (reader->allocs & XML_TEXTREADER_CTXT)
2232	    xmlFreeParserCtxt(reader->ctxt);
2233    }
2234    if (reader->sax != NULL)
2235	xmlFree(reader->sax);
2236    if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
2237	xmlFreeParserInputBuffer(reader->input);
2238    if (reader->faketext != NULL) {
2239	xmlFreeNode(reader->faketext);
2240    }
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 */
3069xmlChar *
3070xmlTextReaderLocalName(xmlTextReaderPtr reader) {
3071    xmlNodePtr node;
3072    if ((reader == NULL) || (reader->node == NULL))
3073	return(NULL);
3074    if (reader->curnode != NULL)
3075	node = reader->curnode;
3076    else
3077	node = reader->node;
3078    if (node->type == XML_NAMESPACE_DECL) {
3079	xmlNsPtr ns = (xmlNsPtr) node;
3080	if (ns->prefix == NULL)
3081	    return(xmlStrdup(BAD_CAST "xmlns"));
3082	else
3083	    return(xmlStrdup(ns->prefix));
3084    }
3085    if ((node->type != XML_ELEMENT_NODE) &&
3086	(node->type != XML_ATTRIBUTE_NODE))
3087	return(xmlTextReaderName(reader));
3088    return(xmlStrdup(node->name));
3089}
3090
3091/**
3092 * xmlTextReaderConstLocalName:
3093 * @reader:  the xmlTextReaderPtr used
3094 *
3095 * The local name of the node.
3096 *
3097 * Returns the local name or NULL if not available, the
3098 *         string will be deallocated with the reader.
3099 */
3100const xmlChar *
3101xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
3102    xmlNodePtr node;
3103    if ((reader == NULL) || (reader->node == NULL))
3104	return(NULL);
3105    if (reader->curnode != NULL)
3106	node = reader->curnode;
3107    else
3108	node = reader->node;
3109    if (node->type == XML_NAMESPACE_DECL) {
3110	xmlNsPtr ns = (xmlNsPtr) node;
3111	if (ns->prefix == NULL)
3112	    return(CONSTSTR(BAD_CAST "xmlns"));
3113	else
3114	    return(ns->prefix);
3115    }
3116    if ((node->type != XML_ELEMENT_NODE) &&
3117	(node->type != XML_ATTRIBUTE_NODE))
3118	return(xmlTextReaderConstName(reader));
3119    return(node->name);
3120}
3121
3122/**
3123 * xmlTextReaderName:
3124 * @reader:  the xmlTextReaderPtr used
3125 *
3126 * The qualified name of the node, equal to Prefix :LocalName.
3127 *
3128 * Returns the local name or NULL if not available
3129 */
3130xmlChar *
3131xmlTextReaderName(xmlTextReaderPtr reader) {
3132    xmlNodePtr node;
3133    xmlChar *ret;
3134
3135    if ((reader == NULL) || (reader->node == NULL))
3136	return(NULL);
3137    if (reader->curnode != NULL)
3138	node = reader->curnode;
3139    else
3140	node = reader->node;
3141    switch (node->type) {
3142        case XML_ELEMENT_NODE:
3143        case XML_ATTRIBUTE_NODE:
3144	    if ((node->ns == NULL) ||
3145		(node->ns->prefix == NULL))
3146		return(xmlStrdup(node->name));
3147
3148	    ret = xmlStrdup(node->ns->prefix);
3149	    ret = xmlStrcat(ret, BAD_CAST ":");
3150	    ret = xmlStrcat(ret, node->name);
3151	    return(ret);
3152        case XML_TEXT_NODE:
3153	    return(xmlStrdup(BAD_CAST "#text"));
3154        case XML_CDATA_SECTION_NODE:
3155	    return(xmlStrdup(BAD_CAST "#cdata-section"));
3156        case XML_ENTITY_NODE:
3157        case XML_ENTITY_REF_NODE:
3158	    return(xmlStrdup(node->name));
3159        case XML_PI_NODE:
3160	    return(xmlStrdup(node->name));
3161        case XML_COMMENT_NODE:
3162	    return(xmlStrdup(BAD_CAST "#comment"));
3163        case XML_DOCUMENT_NODE:
3164        case XML_HTML_DOCUMENT_NODE:
3165#ifdef LIBXML_DOCB_ENABLED
3166        case XML_DOCB_DOCUMENT_NODE:
3167#endif
3168	    return(xmlStrdup(BAD_CAST "#document"));
3169        case XML_DOCUMENT_FRAG_NODE:
3170	    return(xmlStrdup(BAD_CAST "#document-fragment"));
3171        case XML_NOTATION_NODE:
3172	    return(xmlStrdup(node->name));
3173        case XML_DOCUMENT_TYPE_NODE:
3174        case XML_DTD_NODE:
3175	    return(xmlStrdup(node->name));
3176        case XML_NAMESPACE_DECL: {
3177	    xmlNsPtr ns = (xmlNsPtr) node;
3178
3179	    ret = xmlStrdup(BAD_CAST "xmlns");
3180	    if (ns->prefix == NULL)
3181		return(ret);
3182	    ret = xmlStrcat(ret, BAD_CAST ":");
3183	    ret = xmlStrcat(ret, ns->prefix);
3184	    return(ret);
3185	}
3186
3187        case XML_ELEMENT_DECL:
3188        case XML_ATTRIBUTE_DECL:
3189        case XML_ENTITY_DECL:
3190        case XML_XINCLUDE_START:
3191        case XML_XINCLUDE_END:
3192	    return(NULL);
3193    }
3194    return(NULL);
3195}
3196
3197/**
3198 * xmlTextReaderConstName:
3199 * @reader:  the xmlTextReaderPtr used
3200 *
3201 * The qualified name of the node, equal to Prefix :LocalName.
3202 *
3203 * Returns the local name or NULL if not available, the string is
3204 *         deallocated with the reader.
3205 */
3206const xmlChar *
3207xmlTextReaderConstName(xmlTextReaderPtr reader) {
3208    xmlNodePtr node;
3209
3210    if ((reader == NULL) || (reader->node == NULL))
3211	return(NULL);
3212    if (reader->curnode != NULL)
3213	node = reader->curnode;
3214    else
3215	node = reader->node;
3216    switch (node->type) {
3217        case XML_ELEMENT_NODE:
3218        case XML_ATTRIBUTE_NODE:
3219	    if ((node->ns == NULL) ||
3220		(node->ns->prefix == NULL))
3221		return(node->name);
3222	    return(CONSTQSTR(node->ns->prefix, node->name));
3223        case XML_TEXT_NODE:
3224	    return(CONSTSTR(BAD_CAST "#text"));
3225        case XML_CDATA_SECTION_NODE:
3226	    return(CONSTSTR(BAD_CAST "#cdata-section"));
3227        case XML_ENTITY_NODE:
3228        case XML_ENTITY_REF_NODE:
3229	    return(CONSTSTR(node->name));
3230        case XML_PI_NODE:
3231	    return(CONSTSTR(node->name));
3232        case XML_COMMENT_NODE:
3233	    return(CONSTSTR(BAD_CAST "#comment"));
3234        case XML_DOCUMENT_NODE:
3235        case XML_HTML_DOCUMENT_NODE:
3236#ifdef LIBXML_DOCB_ENABLED
3237        case XML_DOCB_DOCUMENT_NODE:
3238#endif
3239	    return(CONSTSTR(BAD_CAST "#document"));
3240        case XML_DOCUMENT_FRAG_NODE:
3241	    return(CONSTSTR(BAD_CAST "#document-fragment"));
3242        case XML_NOTATION_NODE:
3243	    return(CONSTSTR(node->name));
3244        case XML_DOCUMENT_TYPE_NODE:
3245        case XML_DTD_NODE:
3246	    return(CONSTSTR(node->name));
3247        case XML_NAMESPACE_DECL: {
3248	    xmlNsPtr ns = (xmlNsPtr) node;
3249
3250	    if (ns->prefix == NULL)
3251		return(CONSTSTR(BAD_CAST "xmlns"));
3252	    return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
3253	}
3254
3255        case XML_ELEMENT_DECL:
3256        case XML_ATTRIBUTE_DECL:
3257        case XML_ENTITY_DECL:
3258        case XML_XINCLUDE_START:
3259        case XML_XINCLUDE_END:
3260	    return(NULL);
3261    }
3262    return(NULL);
3263}
3264
3265/**
3266 * xmlTextReaderPrefix:
3267 * @reader:  the xmlTextReaderPtr used
3268 *
3269 * A shorthand reference to the namespace associated with the node.
3270 *
3271 * Returns the prefix or NULL if not available
3272 */
3273xmlChar *
3274xmlTextReaderPrefix(xmlTextReaderPtr reader) {
3275    xmlNodePtr node;
3276    if ((reader == NULL) || (reader->node == NULL))
3277	return(NULL);
3278    if (reader->curnode != NULL)
3279	node = reader->curnode;
3280    else
3281	node = reader->node;
3282    if (node->type == XML_NAMESPACE_DECL) {
3283	xmlNsPtr ns = (xmlNsPtr) node;
3284	if (ns->prefix == NULL)
3285	    return(NULL);
3286	return(xmlStrdup(BAD_CAST "xmlns"));
3287    }
3288    if ((node->type != XML_ELEMENT_NODE) &&
3289	(node->type != XML_ATTRIBUTE_NODE))
3290	return(NULL);
3291    if ((node->ns != NULL) && (node->ns->prefix != NULL))
3292	return(xmlStrdup(node->ns->prefix));
3293    return(NULL);
3294}
3295
3296/**
3297 * xmlTextReaderConstPrefix:
3298 * @reader:  the xmlTextReaderPtr used
3299 *
3300 * A shorthand reference to the namespace associated with the node.
3301 *
3302 * Returns the prefix or NULL if not available, the string is deallocated
3303 *         with the reader.
3304 */
3305const xmlChar *
3306xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
3307    xmlNodePtr node;
3308    if ((reader == NULL) || (reader->node == NULL))
3309	return(NULL);
3310    if (reader->curnode != NULL)
3311	node = reader->curnode;
3312    else
3313	node = reader->node;
3314    if (node->type == XML_NAMESPACE_DECL) {
3315	xmlNsPtr ns = (xmlNsPtr) node;
3316	if (ns->prefix == NULL)
3317	    return(NULL);
3318	return(CONSTSTR(BAD_CAST "xmlns"));
3319    }
3320    if ((node->type != XML_ELEMENT_NODE) &&
3321	(node->type != XML_ATTRIBUTE_NODE))
3322	return(NULL);
3323    if ((node->ns != NULL) && (node->ns->prefix != NULL))
3324	return(CONSTSTR(node->ns->prefix));
3325    return(NULL);
3326}
3327
3328/**
3329 * xmlTextReaderNamespaceUri:
3330 * @reader:  the xmlTextReaderPtr used
3331 *
3332 * The URI defining the namespace associated with the node.
3333 *
3334 * Returns the namespace URI or NULL if not available
3335 */
3336xmlChar *
3337xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
3338    xmlNodePtr node;
3339    if ((reader == NULL) || (reader->node == NULL))
3340	return(NULL);
3341    if (reader->curnode != NULL)
3342	node = reader->curnode;
3343    else
3344	node = reader->node;
3345    if (node->type == XML_NAMESPACE_DECL)
3346	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3347    if ((node->type != XML_ELEMENT_NODE) &&
3348	(node->type != XML_ATTRIBUTE_NODE))
3349	return(NULL);
3350    if (node->ns != NULL)
3351	return(xmlStrdup(node->ns->href));
3352    return(NULL);
3353}
3354
3355/**
3356 * xmlTextReaderConstNamespaceUri:
3357 * @reader:  the xmlTextReaderPtr used
3358 *
3359 * The URI defining the namespace associated with the node.
3360 *
3361 * Returns the namespace URI or NULL if not available, the string
3362 *         will be deallocated with the reader
3363 */
3364const xmlChar *
3365xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
3366    xmlNodePtr node;
3367    if ((reader == NULL) || (reader->node == NULL))
3368	return(NULL);
3369    if (reader->curnode != NULL)
3370	node = reader->curnode;
3371    else
3372	node = reader->node;
3373    if (node->type == XML_NAMESPACE_DECL)
3374	return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3375    if ((node->type != XML_ELEMENT_NODE) &&
3376	(node->type != XML_ATTRIBUTE_NODE))
3377	return(NULL);
3378    if (node->ns != NULL)
3379	return(CONSTSTR(node->ns->href));
3380    return(NULL);
3381}
3382
3383/**
3384 * xmlTextReaderBaseUri:
3385 * @reader:  the xmlTextReaderPtr used
3386 *
3387 * The base URI of the node.
3388 *
3389 * Returns the base URI or NULL if not available
3390 */
3391xmlChar *
3392xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
3393    if ((reader == NULL) || (reader->node == NULL))
3394	return(NULL);
3395    return(xmlNodeGetBase(NULL, reader->node));
3396}
3397
3398/**
3399 * xmlTextReaderConstBaseUri:
3400 * @reader:  the xmlTextReaderPtr used
3401 *
3402 * The base URI of the node.
3403 *
3404 * Returns the base URI or NULL if not available, the string
3405 *         will be deallocated with the reader
3406 */
3407const xmlChar *
3408xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
3409    xmlChar *tmp;
3410    const xmlChar *ret;
3411
3412    if ((reader == NULL) || (reader->node == NULL))
3413	return(NULL);
3414    tmp = xmlNodeGetBase(NULL, reader->node);
3415    if (tmp == NULL)
3416        return(NULL);
3417    ret = CONSTSTR(tmp);
3418    xmlFree(tmp);
3419    return(ret);
3420}
3421
3422/**
3423 * xmlTextReaderDepth:
3424 * @reader:  the xmlTextReaderPtr used
3425 *
3426 * The depth of the node in the tree.
3427 *
3428 * Returns the depth or -1 in case of error
3429 */
3430int
3431xmlTextReaderDepth(xmlTextReaderPtr reader) {
3432    if (reader == NULL)
3433	return(-1);
3434    if (reader->node == NULL)
3435	return(0);
3436
3437    if (reader->curnode != NULL) {
3438	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
3439	    (reader->curnode->type == XML_NAMESPACE_DECL))
3440	    return(reader->depth + 1);
3441	return(reader->depth + 2);
3442    }
3443    return(reader->depth);
3444}
3445
3446/**
3447 * xmlTextReaderHasAttributes:
3448 * @reader:  the xmlTextReaderPtr used
3449 *
3450 * Whether the node has attributes.
3451 *
3452 * Returns 1 if true, 0 if false, and -1 in case or error
3453 */
3454int
3455xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
3456    xmlNodePtr node;
3457    if (reader == NULL)
3458	return(-1);
3459    if (reader->node == NULL)
3460	return(0);
3461    if (reader->curnode != NULL)
3462	node = reader->curnode;
3463    else
3464	node = reader->node;
3465
3466    if ((node->type == XML_ELEMENT_NODE) &&
3467	((node->properties != NULL) || (node->nsDef != NULL)))
3468	return(1);
3469    /* TODO: handle the xmlDecl */
3470    return(0);
3471}
3472
3473/**
3474 * xmlTextReaderHasValue:
3475 * @reader:  the xmlTextReaderPtr used
3476 *
3477 * Whether the node can have a text value.
3478 *
3479 * Returns 1 if true, 0 if false, and -1 in case or error
3480 */
3481int
3482xmlTextReaderHasValue(xmlTextReaderPtr reader) {
3483    xmlNodePtr node;
3484    if (reader == NULL)
3485	return(-1);
3486    if (reader->node == NULL)
3487	return(0);
3488    if (reader->curnode != NULL)
3489	node = reader->curnode;
3490    else
3491	node = reader->node;
3492
3493    switch (node->type) {
3494        case XML_ATTRIBUTE_NODE:
3495        case XML_TEXT_NODE:
3496        case XML_CDATA_SECTION_NODE:
3497        case XML_PI_NODE:
3498        case XML_COMMENT_NODE:
3499        case XML_NAMESPACE_DECL:
3500	    return(1);
3501	default:
3502	    break;
3503    }
3504    return(0);
3505}
3506
3507/**
3508 * xmlTextReaderValue:
3509 * @reader:  the xmlTextReaderPtr used
3510 *
3511 * Provides the text value of the node if present
3512 *
3513 * Returns the string or NULL if not available. The result must be deallocated
3514 *     with xmlFree()
3515 */
3516xmlChar *
3517xmlTextReaderValue(xmlTextReaderPtr reader) {
3518    xmlNodePtr node;
3519    if (reader == NULL)
3520	return(NULL);
3521    if (reader->node == NULL)
3522	return(NULL);
3523    if (reader->curnode != NULL)
3524	node = reader->curnode;
3525    else
3526	node = reader->node;
3527
3528    switch (node->type) {
3529        case XML_NAMESPACE_DECL:
3530	    return(xmlStrdup(((xmlNsPtr) node)->href));
3531        case XML_ATTRIBUTE_NODE:{
3532	    xmlAttrPtr attr = (xmlAttrPtr) node;
3533
3534	    if (attr->parent != NULL)
3535		return (xmlNodeListGetString
3536			(attr->parent->doc, attr->children, 1));
3537	    else
3538		return (xmlNodeListGetString(NULL, attr->children, 1));
3539	    break;
3540	}
3541        case XML_TEXT_NODE:
3542        case XML_CDATA_SECTION_NODE:
3543        case XML_PI_NODE:
3544        case XML_COMMENT_NODE:
3545            if (node->content != NULL)
3546                return (xmlStrdup(node->content));
3547	default:
3548	    break;
3549    }
3550    return(NULL);
3551}
3552
3553/**
3554 * xmlTextReaderConstValue:
3555 * @reader:  the xmlTextReaderPtr used
3556 *
3557 * Provides the text value of the node if present
3558 *
3559 * Returns the string or NULL if not available. The result will be
3560 *     deallocated on the next Read() operation.
3561 */
3562const xmlChar *
3563xmlTextReaderConstValue(xmlTextReaderPtr reader) {
3564    xmlNodePtr node;
3565    if (reader == NULL)
3566	return(NULL);
3567    if (reader->node == NULL)
3568	return(NULL);
3569    if (reader->curnode != NULL)
3570	node = reader->curnode;
3571    else
3572	node = reader->node;
3573
3574    switch (node->type) {
3575        case XML_NAMESPACE_DECL:
3576	    return(((xmlNsPtr) node)->href);
3577        case XML_ATTRIBUTE_NODE:{
3578	    xmlAttrPtr attr = (xmlAttrPtr) node;
3579
3580	    if ((attr->children != NULL) &&
3581	        (attr->children->type == XML_TEXT_NODE) &&
3582		(attr->children->next == NULL))
3583		return(attr->children->content);
3584	    else {
3585		if (reader->buffer == NULL)
3586		    reader->buffer = xmlBufferCreateSize(100);
3587		if (reader->buffer == NULL) {
3588		    xmlGenericError(xmlGenericErrorContext,
3589				    "xmlTextReaderSetup : malloc failed\n");
3590		    return (NULL);
3591		}
3592	        reader->buffer->use = 0;
3593	        xmlNodeBufGetContent(reader->buffer, node);
3594		return(reader->buffer->content);
3595	    }
3596	    break;
3597	}
3598        case XML_TEXT_NODE:
3599        case XML_CDATA_SECTION_NODE:
3600        case XML_PI_NODE:
3601        case XML_COMMENT_NODE:
3602	    return(node->content);
3603	default:
3604	    break;
3605    }
3606    return(NULL);
3607}
3608
3609/**
3610 * xmlTextReaderIsDefault:
3611 * @reader:  the xmlTextReaderPtr used
3612 *
3613 * Whether an Attribute  node was generated from the default value
3614 * defined in the DTD or schema.
3615 *
3616 * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
3617 */
3618int
3619xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
3620    if (reader == NULL)
3621	return(-1);
3622    return(0);
3623}
3624
3625/**
3626 * xmlTextReaderQuoteChar:
3627 * @reader:  the xmlTextReaderPtr used
3628 *
3629 * The quotation mark character used to enclose the value of an attribute.
3630 *
3631 * Returns " or ' and -1 in case of error
3632 */
3633int
3634xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
3635    if (reader == NULL)
3636	return(-1);
3637    /* TODO maybe lookup the attribute value for " first */
3638    return((int) '"');
3639}
3640
3641/**
3642 * xmlTextReaderXmlLang:
3643 * @reader:  the xmlTextReaderPtr used
3644 *
3645 * The xml:lang scope within which the node resides.
3646 *
3647 * Returns the xml:lang value or NULL if none exists.
3648 */
3649xmlChar *
3650xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
3651    if (reader == NULL)
3652	return(NULL);
3653    if (reader->node == NULL)
3654	return(NULL);
3655    return(xmlNodeGetLang(reader->node));
3656}
3657
3658/**
3659 * xmlTextReaderConstXmlLang:
3660 * @reader:  the xmlTextReaderPtr used
3661 *
3662 * The xml:lang scope within which the node resides.
3663 *
3664 * Returns the xml:lang value or NULL if none exists.
3665 */
3666const xmlChar *
3667xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
3668    xmlChar *tmp;
3669    const xmlChar *ret;
3670
3671    if (reader == NULL)
3672	return(NULL);
3673    if (reader->node == NULL)
3674	return(NULL);
3675    tmp = xmlNodeGetLang(reader->node);
3676    if (tmp == NULL)
3677        return(NULL);
3678    ret = CONSTSTR(tmp);
3679    xmlFree(tmp);
3680    return(ret);
3681}
3682
3683/**
3684 * xmlTextReaderConstString:
3685 * @reader:  the xmlTextReaderPtr used
3686 * @str:  the string to intern.
3687 *
3688 * Get an interned string from the reader, allows for example to
3689 * speedup string name comparisons
3690 *
3691 * Returns an interned copy of the string or NULL in case of error. The
3692 *         string will be deallocated with the reader.
3693 */
3694const xmlChar *
3695xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
3696    if (reader == NULL)
3697	return(NULL);
3698    return(CONSTSTR(str));
3699}
3700
3701/**
3702 * xmlTextReaderNormalization:
3703 * @reader:  the xmlTextReaderPtr used
3704 *
3705 * The value indicating whether to normalize white space and attribute values.
3706 * Since attribute value and end of line normalizations are a MUST in the XML
3707 * specification only the value true is accepted. The broken bahaviour of
3708 * accepting out of range character entities like &#0; is of course not
3709 * supported either.
3710 *
3711 * Returns 1 or -1 in case of error.
3712 */
3713int
3714xmlTextReaderNormalization(xmlTextReaderPtr reader) {
3715    if (reader == NULL)
3716	return(-1);
3717    return(1);
3718}
3719
3720/************************************************************************
3721 *									*
3722 *			Extensions to the base APIs			*
3723 *									*
3724 ************************************************************************/
3725
3726/**
3727 * xmlTextReaderSetParserProp:
3728 * @reader:  the xmlTextReaderPtr used
3729 * @prop:  the xmlParserProperties to set
3730 * @value:  usually 0 or 1 to (de)activate it
3731 *
3732 * Change the parser processing behaviour by changing some of its internal
3733 * properties. Note that some properties can only be changed before any
3734 * read has been done.
3735 *
3736 * Returns 0 if the call was successful, or -1 in case of error
3737 */
3738int
3739xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
3740    xmlParserProperties p = (xmlParserProperties) prop;
3741    xmlParserCtxtPtr ctxt;
3742
3743    if ((reader == NULL) || (reader->ctxt == NULL))
3744	return(-1);
3745    ctxt = reader->ctxt;
3746
3747    switch (p) {
3748        case XML_PARSER_LOADDTD:
3749	    if (value != 0) {
3750		if (ctxt->loadsubset == 0) {
3751		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3752			return(-1);
3753		    ctxt->loadsubset = XML_DETECT_IDS;
3754		}
3755	    } else {
3756		ctxt->loadsubset = 0;
3757	    }
3758	    return(0);
3759        case XML_PARSER_DEFAULTATTRS:
3760	    if (value != 0) {
3761		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
3762	    } else {
3763		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3764		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
3765	    }
3766	    return(0);
3767        case XML_PARSER_VALIDATE:
3768	    if (value != 0) {
3769		ctxt->validate = 1;
3770		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
3771	    } else {
3772		ctxt->validate = 0;
3773	    }
3774	    return(0);
3775        case XML_PARSER_SUBST_ENTITIES:
3776	    if (value != 0) {
3777		ctxt->replaceEntities = 1;
3778	    } else {
3779		ctxt->replaceEntities = 0;
3780	    }
3781	    return(0);
3782    }
3783    return(-1);
3784}
3785
3786/**
3787 * xmlTextReaderGetParserProp:
3788 * @reader:  the xmlTextReaderPtr used
3789 * @prop:  the xmlParserProperties to get
3790 *
3791 * Read the parser internal property.
3792 *
3793 * Returns the value, usually 0 or 1, or -1 in case of error.
3794 */
3795int
3796xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
3797    xmlParserProperties p = (xmlParserProperties) prop;
3798    xmlParserCtxtPtr ctxt;
3799
3800    if ((reader == NULL) || (reader->ctxt == NULL))
3801	return(-1);
3802    ctxt = reader->ctxt;
3803
3804    switch (p) {
3805        case XML_PARSER_LOADDTD:
3806	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
3807		return(1);
3808	    return(0);
3809        case XML_PARSER_DEFAULTATTRS:
3810	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3811		return(1);
3812	    return(0);
3813        case XML_PARSER_VALIDATE:
3814	    return(reader->validate);
3815	case XML_PARSER_SUBST_ENTITIES:
3816	    return(ctxt->replaceEntities);
3817    }
3818    return(-1);
3819}
3820
3821
3822/**
3823 * xmlTextReaderGetParserLineNumber:
3824 * @reader: the user data (XML reader context)
3825 *
3826 * Provide the line number of the current parsing point.
3827 *
3828 * Returns an int or 0 if not available
3829 */
3830int
3831xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
3832{
3833    if ((reader == NULL) || (reader->ctxt == NULL) ||
3834        (reader->ctxt->input == NULL)) {
3835        return (0);
3836    }
3837    return (reader->ctxt->input->line);
3838}
3839
3840/**
3841 * xmlTextReaderGetParserColumnNumber:
3842 * @reader: the user data (XML reader context)
3843 *
3844 * Provide the column number of the current parsing point.
3845 *
3846 * Returns an int or 0 if not available
3847 */
3848int
3849xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
3850{
3851    if ((reader == NULL) || (reader->ctxt == NULL) ||
3852        (reader->ctxt->input == NULL)) {
3853        return (0);
3854    }
3855    return (reader->ctxt->input->col);
3856}
3857
3858/**
3859 * xmlTextReaderCurrentNode:
3860 * @reader:  the xmlTextReaderPtr used
3861 *
3862 * Hacking interface allowing to get the xmlNodePtr correponding to the
3863 * current node being accessed by the xmlTextReader. This is dangerous
3864 * because the underlying node may be destroyed on the next Reads.
3865 *
3866 * Returns the xmlNodePtr or NULL in case of error.
3867 */
3868xmlNodePtr
3869xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
3870    if (reader == NULL)
3871	return(NULL);
3872
3873    if (reader->curnode != NULL)
3874	return(reader->curnode);
3875    return(reader->node);
3876}
3877
3878/**
3879 * xmlTextReaderPreserve:
3880 * @reader:  the xmlTextReaderPtr used
3881 *
3882 * This tells the XML Reader to preserve the current node.
3883 * The caller must also use xmlTextReaderCurrentDoc() to
3884 * keep an handle on the resulting document once parsing has finished
3885 *
3886 * Returns the xmlNodePtr or NULL in case of error.
3887 */
3888xmlNodePtr
3889xmlTextReaderPreserve(xmlTextReaderPtr reader) {
3890    xmlNodePtr cur, parent;
3891
3892    if (reader == NULL)
3893	return(NULL);
3894
3895    if (reader->curnode != NULL)
3896        cur = reader->curnode;
3897    else
3898        cur = reader->node;
3899    if (cur == NULL)
3900        return(NULL);
3901
3902    if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
3903	cur->extra |= NODE_IS_PRESERVED;
3904	cur->extra |= NODE_IS_SPRESERVED;
3905    }
3906    reader->preserves++;
3907
3908    parent = cur->parent;;
3909    while (parent != NULL) {
3910        if (parent->type == XML_ELEMENT_NODE)
3911	    parent->extra |= NODE_IS_PRESERVED;
3912	parent = parent->parent;
3913    }
3914    return(cur);
3915}
3916
3917#ifdef LIBXML_PATTERN_ENABLED
3918/**
3919 * xmlTextReaderPreservePattern:
3920 * @reader:  the xmlTextReaderPtr used
3921 * @pattern:  an XPath subset pattern
3922 * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
3923 *
3924 * This tells the XML Reader to preserve all nodes matched by the
3925 * pattern. The caller must also use xmlTextReaderCurrentDoc() to
3926 * keep an handle on the resulting document once parsing has finished
3927 *
3928 * Returns a positive number in case of success and -1 in case of error
3929 */
3930int
3931xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
3932                             const xmlChar **namespaces)
3933{
3934    xmlPatternPtr comp;
3935
3936    if ((reader == NULL) || (pattern == NULL))
3937	return(-1);
3938
3939    comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
3940    if (comp == NULL)
3941        return(-1);
3942
3943    if (reader->patternMax <= 0) {
3944	reader->patternMax = 4;
3945	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
3946					      sizeof(reader->patternTab[0]));
3947        if (reader->patternTab == NULL) {
3948            xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
3949            return (-1);
3950        }
3951    }
3952    if (reader->patternNr >= reader->patternMax) {
3953        xmlPatternPtr *tmp;
3954        reader->patternMax *= 2;
3955	tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
3956                                      reader->patternMax *
3957                                      sizeof(reader->patternTab[0]));
3958        if (tmp == NULL) {
3959            xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
3960	    reader->patternMax /= 2;
3961            return (-1);
3962        }
3963	reader->patternTab = tmp;
3964    }
3965    reader->patternTab[reader->patternNr] = comp;
3966    return(reader->patternNr++);
3967}
3968#endif
3969
3970/**
3971 * xmlTextReaderCurrentDoc:
3972 * @reader:  the xmlTextReaderPtr used
3973 *
3974 * Hacking interface allowing to get the xmlDocPtr correponding to the
3975 * current document being accessed by the xmlTextReader.
3976 * NOTE: as a result of this call, the reader will not destroy the
3977 *       associated XML document and calling xmlFreeDoc() on the result
3978 *       is needed once the reader parsing has finished.
3979 *
3980 * Returns the xmlDocPtr or NULL in case of error.
3981 */
3982xmlDocPtr
3983xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
3984    if (reader == NULL)
3985	return(NULL);
3986    if (reader->doc != NULL)
3987        return(reader->doc);
3988    if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
3989	return(NULL);
3990
3991    reader->preserve = 1;
3992    return(reader->ctxt->myDoc);
3993}
3994
3995#ifdef LIBXML_SCHEMAS_ENABLED
3996
3997static char *
3998xmlTextReaderBuildMessage(const char *msg, va_list ap);
3999
4000static void XMLCDECL
4001xmlTextReaderValidityError(void *ctxt, const char *msg, ...);
4002
4003static void XMLCDECL
4004xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...);
4005
4006static void XMLCDECL xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
4007{
4008	xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4009	char * str;
4010	va_list ap;
4011
4012	va_start(ap,msg);
4013	str = xmlTextReaderBuildMessage(msg,ap);
4014	if (!reader->errorFunc) {
4015		xmlTextReaderValidityError(ctx, "%s", str);
4016	} else {
4017		reader->errorFunc(reader->errorFuncArg, str, XML_PARSER_SEVERITY_VALIDITY_ERROR, NULL /* locator */);
4018	}
4019	if (str != NULL)
4020		xmlFree(str);
4021	va_end(ap);
4022}
4023
4024static void XMLCDECL xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
4025{
4026	xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4027	char * str;
4028	va_list ap;
4029
4030	va_start(ap,msg);
4031	str = xmlTextReaderBuildMessage(msg,ap);
4032	if (!reader->errorFunc) {
4033		xmlTextReaderValidityWarning(ctx, "%s", str);
4034	} else {
4035		reader->errorFunc(reader->errorFuncArg, str, XML_PARSER_SEVERITY_VALIDITY_WARNING, NULL /* locator */);
4036	}
4037	if (str != NULL)
4038		xmlFree(str);
4039	va_end(ap);
4040}
4041
4042static void
4043xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
4044
4045static void xmlTextReaderValidityStructuredRelay(void * userData, xmlErrorPtr error)
4046{
4047	xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
4048
4049	if (reader->sErrorFunc) {
4050		reader->sErrorFunc(reader->errorFuncArg, error);
4051	} else {
4052		xmlTextReaderStructuredError(reader, error);
4053	}
4054}
4055
4056/**
4057 * xmlTextReaderRelaxNGSetSchema:
4058 * @reader:  the xmlTextReaderPtr used
4059 * @schema:  a precompiled RelaxNG schema
4060 *
4061 * Use RelaxNG to validate the document as it is processed.
4062 * Activation is only possible before the first Read().
4063 * if @schema is NULL, then RelaxNG validation is desactivated.
4064 @ The @schema should not be freed until the reader is deallocated
4065 * or its use has been deactivated.
4066 *
4067 * Returns 0 in case the RelaxNG validation could be (des)activated and
4068 *         -1 in case of error.
4069 */
4070int
4071xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
4072    if (reader == NULL)
4073        return(-1);
4074    if (schema == NULL) {
4075        if (reader->rngSchemas != NULL) {
4076	    xmlRelaxNGFree(reader->rngSchemas);
4077	    reader->rngSchemas = NULL;
4078	}
4079        if (reader->rngValidCtxt != NULL) {
4080	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4081	    reader->rngValidCtxt = NULL;
4082        }
4083	return(0);
4084    }
4085    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4086	return(-1);
4087    if (reader->rngSchemas != NULL) {
4088	xmlRelaxNGFree(reader->rngSchemas);
4089	reader->rngSchemas = NULL;
4090    }
4091    if (reader->rngValidCtxt != NULL) {
4092	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4093	reader->rngValidCtxt = NULL;
4094    }
4095    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
4096    if (reader->rngValidCtxt == NULL)
4097        return(-1);
4098    if (reader->errorFunc != NULL) {
4099	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4100			xmlTextReaderValidityErrorRelay,
4101			xmlTextReaderValidityWarningRelay,
4102			reader);
4103    }
4104	if (reader->sErrorFunc != NULL) {
4105		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4106			xmlTextReaderValidityStructuredRelay,
4107			reader);
4108    }
4109    reader->rngValidErrors = 0;
4110    reader->rngFullNode = NULL;
4111    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4112    return(0);
4113}
4114
4115/**
4116 * xmlTextReaderSetSchema:
4117 * @reader:  the xmlTextReaderPtr used
4118 * @schema:  a precompiled Schema schema
4119 *
4120 * Use XSD Schema to validate the document as it is processed.
4121 * Activation is only possible before the first Read().
4122 * if @schema is NULL, then Schema validation is desactivated.
4123 @ The @schema should not be freed until the reader is deallocated
4124 * or its use has been deactivated.
4125 *
4126 * Returns 0 in case the Schema validation could be (des)activated and
4127 *         -1 in case of error.
4128 */
4129int
4130xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
4131    if (reader == NULL)
4132        return(-1);
4133    if (schema == NULL) {
4134	if (reader->xsdPlug != NULL) {
4135	    xmlSchemaSAXUnplug(reader->xsdPlug);
4136	    reader->xsdPlug = NULL;
4137	}
4138        if (reader->xsdValidCtxt != NULL) {
4139	    if (! reader->xsdPreserveCtxt)
4140		xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4141	    reader->xsdValidCtxt = NULL;
4142        }
4143	reader->xsdPreserveCtxt = 0;
4144        if (reader->xsdSchemas != NULL) {
4145	    xmlSchemaFree(reader->xsdSchemas);
4146	    reader->xsdSchemas = NULL;
4147	}
4148	return(0);
4149    }
4150    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4151	return(-1);
4152    if (reader->xsdPlug != NULL) {
4153	xmlSchemaSAXUnplug(reader->xsdPlug);
4154	reader->xsdPlug = NULL;
4155    }
4156    if (reader->xsdValidCtxt != NULL) {
4157	if (! reader->xsdPreserveCtxt)
4158	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4159	reader->xsdValidCtxt = NULL;
4160    }
4161    reader->xsdPreserveCtxt = 0;
4162    if (reader->xsdSchemas != NULL) {
4163	xmlSchemaFree(reader->xsdSchemas);
4164	reader->xsdSchemas = NULL;
4165    }
4166    reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
4167    if (reader->xsdValidCtxt == NULL) {
4168	xmlSchemaFree(reader->xsdSchemas);
4169	reader->xsdSchemas = NULL;
4170        return(-1);
4171    }
4172    reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4173                                       &(reader->ctxt->sax),
4174				       &(reader->ctxt->userData));
4175    if (reader->xsdPlug == NULL) {
4176	xmlSchemaFree(reader->xsdSchemas);
4177	reader->xsdSchemas = NULL;
4178	xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4179	reader->xsdValidCtxt = NULL;
4180	return(-1);
4181    }
4182    if (reader->errorFunc != NULL) {
4183	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4184			xmlTextReaderValidityErrorRelay,
4185			xmlTextReaderValidityWarningRelay,
4186			reader);
4187    }
4188	if (reader->sErrorFunc != NULL) {
4189		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4190			xmlTextReaderValidityStructuredRelay,
4191			reader);
4192    }
4193    reader->xsdValidErrors = 0;
4194    reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4195    return(0);
4196}
4197
4198/**
4199 * xmlTextReaderRelaxNGValidate:
4200 * @reader:  the xmlTextReaderPtr used
4201 * @rng:  the path to a RelaxNG schema or NULL
4202 *
4203 * Use RelaxNG to validate the document as it is processed.
4204 * Activation is only possible before the first Read().
4205 * if @rng is NULL, then RelaxNG validation is deactivated.
4206 *
4207 * Returns 0 in case the RelaxNG validation could be (de)activated and
4208 *         -1 in case of error.
4209 */
4210int
4211xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng) {
4212    xmlRelaxNGParserCtxtPtr ctxt;
4213
4214    if (reader == NULL)
4215        return(-1);
4216
4217    if (rng == NULL) {
4218        if (reader->rngValidCtxt != NULL) {
4219	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4220	    reader->rngValidCtxt = NULL;
4221        }
4222        if (reader->rngSchemas != NULL) {
4223	    xmlRelaxNGFree(reader->rngSchemas);
4224	    reader->rngSchemas = NULL;
4225	}
4226	return(0);
4227    }
4228    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4229	return(-1);
4230    if (reader->rngSchemas != NULL) {
4231	xmlRelaxNGFree(reader->rngSchemas);
4232	reader->rngSchemas = NULL;
4233    }
4234    if (reader->rngValidCtxt != NULL) {
4235	xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4236	reader->rngValidCtxt = NULL;
4237    }
4238    ctxt = xmlRelaxNGNewParserCtxt(rng);
4239    if (reader->errorFunc != NULL) {
4240	xmlRelaxNGSetParserErrors(ctxt,
4241			 xmlTextReaderValidityErrorRelay,
4242			 xmlTextReaderValidityWarningRelay,
4243			 reader);
4244    }
4245    if (reader->sErrorFunc != NULL) {
4246	xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4247			xmlTextReaderValidityStructuredRelay,
4248			reader);
4249    }
4250    reader->rngSchemas = xmlRelaxNGParse(ctxt);
4251    xmlRelaxNGFreeParserCtxt(ctxt);
4252    if (reader->rngSchemas == NULL)
4253        return(-1);
4254    reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
4255    if (reader->rngValidCtxt == NULL) {
4256	xmlRelaxNGFree(reader->rngSchemas);
4257	reader->rngSchemas = NULL;
4258        return(-1);
4259    }
4260    if (reader->errorFunc != NULL) {
4261	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4262			 xmlTextReaderValidityErrorRelay,
4263			 xmlTextReaderValidityWarningRelay,
4264			 reader);
4265    }
4266	if (reader->sErrorFunc != NULL) {
4267		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4268			xmlTextReaderValidityStructuredRelay,
4269			reader);
4270    }
4271    reader->rngValidErrors = 0;
4272    reader->rngFullNode = NULL;
4273    reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4274    return(0);
4275}
4276
4277/**
4278 * xmlTextReaderSchemaValidateInternal:
4279 * @reader:  the xmlTextReaderPtr used
4280 * @xsd:  the path to a W3C XSD schema or NULL
4281 * @ctxt: the XML Schema validation context or NULL
4282 * @options: options (not used yet)
4283 *
4284 * Validate the document as it is processed using XML Schema.
4285 * Activation is only possible before the first Read().
4286 * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
4287 *
4288 * Returns 0 in case the schemas validation could be (de)activated and
4289 *         -1 in case of error.
4290 */
4291static int
4292xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
4293				    const char *xsd,
4294				    xmlSchemaValidCtxtPtr ctxt,
4295				    int options ATTRIBUTE_UNUSED)
4296{
4297    if (reader == NULL)
4298        return(-1);
4299
4300    if ((xsd != NULL) && (ctxt != NULL))
4301	return(-1);
4302
4303    if (((xsd != NULL) || (ctxt != NULL)) &&
4304	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
4305        (reader->ctxt == NULL)))
4306	return(-1);
4307
4308    /* Cleanup previous validation stuff. */
4309    if (reader->xsdPlug != NULL) {
4310	xmlSchemaSAXUnplug(reader->xsdPlug);
4311	reader->xsdPlug = NULL;
4312    }
4313    if (reader->xsdValidCtxt != NULL) {
4314	if (! reader->xsdPreserveCtxt)
4315	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4316	reader->xsdValidCtxt = NULL;
4317    }
4318    reader->xsdPreserveCtxt = 0;
4319    if (reader->xsdSchemas != NULL) {
4320	xmlSchemaFree(reader->xsdSchemas);
4321	reader->xsdSchemas = NULL;
4322    }
4323
4324    if ((xsd == NULL) && (ctxt == NULL)) {
4325	/* We just want to deactivate the validation, so get out. */
4326	return(0);
4327    }
4328
4329    if (xsd != NULL) {
4330	xmlSchemaParserCtxtPtr pctxt;
4331	/* Parse the schema and create validation environment. */
4332	pctxt = xmlSchemaNewParserCtxt(xsd);
4333	if (reader->errorFunc != NULL) {
4334	    xmlSchemaSetParserErrors(pctxt,
4335		xmlTextReaderValidityErrorRelay,
4336		xmlTextReaderValidityWarningRelay,
4337		reader);
4338	}
4339	reader->xsdSchemas = xmlSchemaParse(pctxt);
4340	xmlSchemaFreeParserCtxt(pctxt);
4341	if (reader->xsdSchemas == NULL)
4342	    return(-1);
4343	reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
4344	if (reader->xsdValidCtxt == NULL) {
4345	    xmlSchemaFree(reader->xsdSchemas);
4346	    reader->xsdSchemas = NULL;
4347	    return(-1);
4348	}
4349	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4350	    &(reader->ctxt->sax),
4351	    &(reader->ctxt->userData));
4352	if (reader->xsdPlug == NULL) {
4353	    xmlSchemaFree(reader->xsdSchemas);
4354	    reader->xsdSchemas = NULL;
4355	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4356	    reader->xsdValidCtxt = NULL;
4357	    return(-1);
4358	}
4359    } else {
4360	/* Use the given validation context. */
4361	reader->xsdValidCtxt = ctxt;
4362	reader->xsdPreserveCtxt = 1;
4363	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4364	    &(reader->ctxt->sax),
4365	    &(reader->ctxt->userData));
4366	if (reader->xsdPlug == NULL) {
4367	    reader->xsdValidCtxt = NULL;
4368	    reader->xsdPreserveCtxt = 0;
4369	    return(-1);
4370	}
4371    }
4372    /*
4373    * Redirect the validation context's error channels to use
4374    * the reader channels.
4375    * TODO: In case the user provides the validation context we
4376    *   could make this redirection optional.
4377    */
4378    if (reader->errorFunc != NULL) {
4379	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4380			 xmlTextReaderValidityErrorRelay,
4381			 xmlTextReaderValidityWarningRelay,
4382			 reader);
4383    }
4384	if (reader->sErrorFunc != NULL) {
4385		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4386			xmlTextReaderValidityStructuredRelay,
4387			reader);
4388    }
4389    reader->xsdValidErrors = 0;
4390    reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4391    return(0);
4392}
4393
4394/**
4395 * xmlTextReaderSchemaValidateCtxt:
4396 * @reader:  the xmlTextReaderPtr used
4397 * @ctxt: the XML Schema validation context or NULL
4398 * @options: options (not used yet)
4399 *
4400 * Use W3C XSD schema context to validate the document as it is processed.
4401 * Activation is only possible before the first Read().
4402 * If @ctxt is NULL, then XML Schema validation is deactivated.
4403 *
4404 * Returns 0 in case the schemas validation could be (de)activated and
4405 *         -1 in case of error.
4406 */
4407int
4408xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
4409				    xmlSchemaValidCtxtPtr ctxt,
4410				    int options)
4411{
4412    return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
4413}
4414
4415/**
4416 * xmlTextReaderSchemaValidate:
4417 * @reader:  the xmlTextReaderPtr used
4418 * @xsd:  the path to a W3C XSD schema or NULL
4419 *
4420 * Use W3C XSD schema to validate the document as it is processed.
4421 * Activation is only possible before the first Read().
4422 * If @xsd is NULL, then XML Schema validation is deactivated.
4423 *
4424 * Returns 0 in case the schemas validation could be (de)activated and
4425 *         -1 in case of error.
4426 */
4427int
4428xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
4429{
4430    return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
4431}
4432#endif
4433
4434/**
4435 * xmlTextReaderIsNamespaceDecl:
4436 * @reader: the xmlTextReaderPtr used
4437 *
4438 * Determine whether the current node is a namespace declaration
4439 * rather than a regular attribute.
4440 *
4441 * Returns 1 if the current node is a namespace declaration, 0 if it
4442 * is a regular attribute or other type of node, or -1 in case of
4443 * error.
4444 */
4445int
4446xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
4447    xmlNodePtr node;
4448    if (reader == NULL)
4449	return(-1);
4450    if (reader->node == NULL)
4451	return(-1);
4452    if (reader->curnode != NULL)
4453	node = reader->curnode;
4454    else
4455	node = reader->node;
4456
4457    if (XML_NAMESPACE_DECL == node->type)
4458	return(1);
4459    else
4460	return(0);
4461}
4462
4463/**
4464 * xmlTextReaderConstXmlVersion:
4465 * @reader:  the xmlTextReaderPtr used
4466 *
4467 * Determine the XML version of the document being read.
4468 *
4469 * Returns a string containing the XML version of the document or NULL
4470 * in case of error.  The string is deallocated with the reader.
4471 */
4472const xmlChar *
4473xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
4474    xmlDocPtr doc = NULL;
4475    if (reader == NULL)
4476	return(NULL);
4477    if (reader->doc != NULL)
4478        doc = reader->doc;
4479    else if (reader->ctxt != NULL)
4480	doc = reader->ctxt->myDoc;
4481    if (doc == NULL)
4482	return(NULL);
4483
4484    if (doc->version == NULL)
4485	return(NULL);
4486    else
4487      return(CONSTSTR(doc->version));
4488}
4489
4490/**
4491 * xmlTextReaderStandalone:
4492 * @reader:  the xmlTextReaderPtr used
4493 *
4494 * Determine the standalone status of the document being read.
4495 *
4496 * Returns 1 if the document was declared to be standalone, 0 if it
4497 * was declared to be not standalone, or -1 if the document did not
4498 * specify its standalone status or in case of error.
4499 */
4500int
4501xmlTextReaderStandalone(xmlTextReaderPtr reader) {
4502    xmlDocPtr doc = NULL;
4503    if (reader == NULL)
4504	return(-1);
4505    if (reader->doc != NULL)
4506        doc = reader->doc;
4507    else if (reader->ctxt != NULL)
4508	doc = reader->ctxt->myDoc;
4509    if (doc == NULL)
4510	return(-1);
4511
4512    return(doc->standalone);
4513}
4514
4515/************************************************************************
4516 *									*
4517 *			Error Handling Extensions                       *
4518 *									*
4519 ************************************************************************/
4520
4521/* helper to build a xmlMalloc'ed string from a format and va_list */
4522static char *
4523xmlTextReaderBuildMessage(const char *msg, va_list ap) {
4524    int size = 0;
4525    int chars;
4526    char *larger;
4527    char *str = NULL;
4528    va_list aq;
4529
4530    while (1) {
4531        VA_COPY(aq, ap);
4532        chars = vsnprintf(str, size, msg, aq);
4533        va_end(aq);
4534        if (chars < 0) {
4535	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
4536	    if (str)
4537	    	xmlFree(str);
4538	    return NULL;
4539	}
4540	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
4541            break;
4542        if (chars < MAX_ERR_MSG_SIZE)
4543        	size = chars + 1;
4544	else
4545		size = MAX_ERR_MSG_SIZE;
4546        if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
4547	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
4548	    if (str)
4549            	xmlFree(str);
4550            return NULL;
4551        }
4552        str = larger;
4553    }
4554
4555    return str;
4556}
4557
4558/**
4559 * xmlTextReaderLocatorLineNumber:
4560 * @locator: the xmlTextReaderLocatorPtr used
4561 *
4562 * Obtain the line number for the given locator.
4563 *
4564 * Returns the line number or -1 in case of error.
4565 */
4566int
4567xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
4568    /* we know that locator is a xmlParserCtxtPtr */
4569    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4570    int ret = -1;
4571
4572    if (locator == NULL)
4573        return(-1);
4574    if (ctx->node != NULL) {
4575	ret = xmlGetLineNo(ctx->node);
4576    }
4577    else {
4578	/* inspired from error.c */
4579	xmlParserInputPtr input;
4580	input = ctx->input;
4581	if ((input->filename == NULL) && (ctx->inputNr > 1))
4582	    input = ctx->inputTab[ctx->inputNr - 2];
4583	if (input != NULL) {
4584	    ret = input->line;
4585	}
4586	else {
4587	    ret = -1;
4588	}
4589    }
4590
4591    return ret;
4592}
4593
4594/**
4595 * xmlTextReaderLocatorBaseURI:
4596 * @locator: the xmlTextReaderLocatorPtr used
4597 *
4598 * Obtain the base URI for the given locator.
4599 *
4600 * Returns the base URI or NULL in case of error.
4601 */
4602xmlChar *
4603xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
4604    /* we know that locator is a xmlParserCtxtPtr */
4605    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4606    xmlChar *ret = NULL;
4607
4608    if (locator == NULL)
4609        return(NULL);
4610    if (ctx->node != NULL) {
4611	ret = xmlNodeGetBase(NULL,ctx->node);
4612    }
4613    else {
4614	/* inspired from error.c */
4615	xmlParserInputPtr input;
4616	input = ctx->input;
4617	if ((input->filename == NULL) && (ctx->inputNr > 1))
4618	    input = ctx->inputTab[ctx->inputNr - 2];
4619	if (input != NULL) {
4620	    ret = xmlStrdup(BAD_CAST input->filename);
4621	}
4622	else {
4623	    ret = NULL;
4624	}
4625    }
4626
4627    return ret;
4628}
4629
4630static void
4631xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity, char *str) {
4632    xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)ctxt;
4633    xmlTextReaderPtr reader = (xmlTextReaderPtr)ctx->_private;
4634
4635    if (str != NULL) {
4636      if (reader->errorFunc)
4637	reader->errorFunc(reader->errorFuncArg,
4638			  str,
4639			  severity,
4640			  (xmlTextReaderLocatorPtr)ctx);
4641	xmlFree(str);
4642    }
4643}
4644
4645static void
4646xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error) {
4647  xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4648  xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4649
4650  if (error && reader->sErrorFunc) {
4651	reader->sErrorFunc(reader->errorFuncArg,
4652			   (xmlErrorPtr) error);
4653  }
4654}
4655
4656static void XMLCDECL
4657xmlTextReaderError(void *ctxt, const char *msg, ...) {
4658    va_list ap;
4659
4660    va_start(ap,msg);
4661    xmlTextReaderGenericError(ctxt,
4662                              XML_PARSER_SEVERITY_ERROR,
4663	                      xmlTextReaderBuildMessage(msg,ap));
4664    va_end(ap);
4665
4666}
4667
4668static void XMLCDECL
4669xmlTextReaderWarning(void *ctxt, const char *msg, ...) {
4670    va_list ap;
4671
4672    va_start(ap,msg);
4673    xmlTextReaderGenericError(ctxt,
4674                              XML_PARSER_SEVERITY_WARNING,
4675	                      xmlTextReaderBuildMessage(msg,ap));
4676    va_end(ap);
4677}
4678
4679static void XMLCDECL
4680xmlTextReaderValidityError(void *ctxt, const char *msg, ...) {
4681    va_list ap;
4682    int len = xmlStrlen((const xmlChar *) msg);
4683
4684    if ((len > 1) && (msg[len - 2] != ':')) {
4685	/*
4686	 * some callbacks only report locator information:
4687	 * skip them (mimicking behaviour in error.c)
4688	 */
4689	va_start(ap,msg);
4690	xmlTextReaderGenericError(ctxt,
4691				  XML_PARSER_SEVERITY_VALIDITY_ERROR,
4692				  xmlTextReaderBuildMessage(msg,ap));
4693	va_end(ap);
4694    }
4695}
4696
4697static void XMLCDECL
4698xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) {
4699    va_list ap;
4700    int len = xmlStrlen((const xmlChar *) msg);
4701
4702    if ((len != 0) && (msg[len - 1] != ':')) {
4703	/*
4704	 * some callbacks only report locator information:
4705	 * skip them (mimicking behaviour in error.c)
4706	 */
4707	va_start(ap,msg);
4708	xmlTextReaderGenericError(ctxt,
4709				  XML_PARSER_SEVERITY_VALIDITY_WARNING,
4710				  xmlTextReaderBuildMessage(msg,ap));
4711	va_end(ap);
4712    }
4713}
4714
4715/**
4716 * xmlTextReaderSetErrorHandler:
4717 * @reader:  the xmlTextReaderPtr used
4718 * @f:	the callback function to call on error and warnings
4719 * @arg:    a user argument to pass to the callback function
4720 *
4721 * Register a callback function that will be called on error and warnings.
4722 *
4723 * If @f is NULL, the default error and warning handlers are restored.
4724 */
4725void
4726xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
4727			     xmlTextReaderErrorFunc f,
4728			     void *arg) {
4729    if (f != NULL) {
4730	reader->ctxt->sax->error = xmlTextReaderError;
4731	reader->ctxt->sax->serror = NULL;
4732	reader->ctxt->vctxt.error = xmlTextReaderValidityError;
4733	reader->ctxt->sax->warning = xmlTextReaderWarning;
4734	reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
4735	reader->errorFunc = f;
4736	reader->sErrorFunc = NULL;
4737	reader->errorFuncArg = arg;
4738#ifdef LIBXML_SCHEMAS_ENABLED
4739		if (reader->rngValidCtxt) {
4740			xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4741				 xmlTextReaderValidityErrorRelay,
4742				 xmlTextReaderValidityWarningRelay,
4743				 reader);
4744			xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, reader);
4745		}
4746		if (reader->xsdValidCtxt) {
4747			xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4748				 xmlTextReaderValidityErrorRelay,
4749				 xmlTextReaderValidityWarningRelay,
4750				 reader);
4751			xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, reader);
4752		}
4753#endif
4754    }
4755    else {
4756	/* restore defaults */
4757	reader->ctxt->sax->error = xmlParserError;
4758	reader->ctxt->vctxt.error = xmlParserValidityError;
4759	reader->ctxt->sax->warning = xmlParserWarning;
4760	reader->ctxt->vctxt.warning = xmlParserValidityWarning;
4761	reader->errorFunc = NULL;
4762	reader->sErrorFunc = NULL;
4763	reader->errorFuncArg = NULL;
4764#ifdef LIBXML_SCHEMAS_ENABLED
4765		if (reader->rngValidCtxt) {
4766			xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, reader);
4767			xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, reader);
4768		}
4769		if (reader->xsdValidCtxt) {
4770			xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, reader);
4771			xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, reader);
4772		}
4773#endif
4774    }
4775}
4776
4777/**
4778* xmlTextReaderSetStructuredErrorHandler:
4779 * @reader:  the xmlTextReaderPtr used
4780 * @f:	the callback function to call on error and warnings
4781 * @arg:    a user argument to pass to the callback function
4782 *
4783 * Register a callback function that will be called on error and warnings.
4784 *
4785 * If @f is NULL, the default error and warning handlers are restored.
4786 */
4787void
4788xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
4789					 xmlStructuredErrorFunc f,
4790					 void *arg) {
4791  if (f != NULL) {
4792	reader->ctxt->sax->error = NULL;
4793	reader->ctxt->sax->serror = xmlTextReaderStructuredError;
4794	reader->ctxt->vctxt.error = xmlTextReaderValidityError;
4795	reader->ctxt->sax->warning = xmlTextReaderWarning;
4796	reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
4797	reader->sErrorFunc = f;
4798	reader->errorFunc = NULL;
4799	reader->errorFuncArg = arg;
4800#ifdef LIBXML_SCHEMAS_ENABLED
4801		if (reader->rngValidCtxt) {
4802			xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, reader);
4803			xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4804				xmlTextReaderValidityStructuredRelay,
4805				reader);
4806		}
4807		if (reader->xsdValidCtxt) {
4808			xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, reader);
4809			xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4810				xmlTextReaderValidityStructuredRelay,
4811				reader);
4812		}
4813#endif
4814  }
4815  else {
4816	/* restore defaults */
4817	reader->ctxt->sax->error = xmlParserError;
4818	reader->ctxt->sax->serror = NULL;
4819	reader->ctxt->vctxt.error = xmlParserValidityError;
4820	reader->ctxt->sax->warning = xmlParserWarning;
4821	reader->ctxt->vctxt.warning = xmlParserValidityWarning;
4822	reader->errorFunc = NULL;
4823	reader->sErrorFunc = NULL;
4824	reader->errorFuncArg = NULL;
4825#ifdef LIBXML_SCHEMAS_ENABLED
4826		if (reader->rngValidCtxt) {
4827			xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL, reader);
4828			xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL, reader);
4829		}
4830		if (reader->xsdValidCtxt) {
4831			xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL, reader);
4832			xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL, reader);
4833		}
4834#endif
4835  }
4836}
4837
4838/**
4839 * xmlTextReaderIsValid:
4840 * @reader:  the xmlTextReaderPtr used
4841 *
4842 * Retrieve the validity status from the parser context
4843 *
4844 * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
4845 */
4846int
4847xmlTextReaderIsValid(xmlTextReaderPtr reader) {
4848    if (reader == NULL) return(-1);
4849#ifdef LIBXML_SCHEMAS_ENABLED
4850    if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
4851        return(reader->rngValidErrors == 0);
4852    if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
4853        return(reader->xsdValidErrors == 0);
4854#endif
4855    if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
4856	return(reader->ctxt->valid);
4857    return(0);
4858}
4859
4860/**
4861 * xmlTextReaderGetErrorHandler:
4862 * @reader:  the xmlTextReaderPtr used
4863 * @f:	the callback function or NULL is no callback has been registered
4864 * @arg:    a user argument
4865 *
4866 * Retrieve the error callback function and user argument.
4867 */
4868void
4869xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
4870			     xmlTextReaderErrorFunc *f,
4871			     void **arg) {
4872    if (f != NULL) *f = reader->errorFunc;
4873    if (arg != NULL) *arg = reader->errorFuncArg;
4874}
4875
4876
4877/************************************************************************
4878 *									*
4879 *	New set (2.6.0) of simpler and more flexible APIs		*
4880 *									*
4881 ************************************************************************/
4882
4883/**
4884 * xmlTextReaderSetup:
4885 * @reader:  an XML reader
4886 * @input: xmlParserInputBufferPtr used to feed the reader, will
4887 *         be destroyed with it.
4888 * @URL:  the base URL to use for the document
4889 * @encoding:  the document encoding, or NULL
4890 * @options:  a combination of xmlParserOption
4891 *
4892 * Setup an XML reader with new options
4893 *
4894 * Returns 0 in case of success and -1 in case of error.
4895 */
4896int
4897xmlTextReaderSetup(xmlTextReaderPtr reader,
4898                   xmlParserInputBufferPtr input, const char *URL,
4899                   const char *encoding, int options)
4900{
4901    if (reader == NULL) {
4902        if (input != NULL)
4903	    xmlFreeParserInputBuffer(input);
4904        return (-1);
4905    }
4906
4907    /*
4908     * we force the generation of compact text nodes on the reader
4909     * since usr applications should never modify the tree
4910     */
4911    options |= XML_PARSE_COMPACT;
4912
4913    reader->doc = NULL;
4914    reader->entNr = 0;
4915    reader->parserFlags = options;
4916    reader->validate = XML_TEXTREADER_NOT_VALIDATE;
4917    if ((input != NULL) && (reader->input != NULL) &&
4918        (reader->allocs & XML_TEXTREADER_INPUT)) {
4919	xmlFreeParserInputBuffer(reader->input);
4920	reader->input = NULL;
4921	reader->allocs -= XML_TEXTREADER_INPUT;
4922    }
4923    if (input != NULL) {
4924	reader->input = input;
4925	reader->allocs |= XML_TEXTREADER_INPUT;
4926    }
4927    if (reader->buffer == NULL)
4928        reader->buffer = xmlBufferCreateSize(100);
4929    if (reader->buffer == NULL) {
4930        xmlGenericError(xmlGenericErrorContext,
4931                        "xmlTextReaderSetup : malloc failed\n");
4932        return (-1);
4933    }
4934    if (reader->sax == NULL)
4935	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
4936    if (reader->sax == NULL) {
4937        xmlGenericError(xmlGenericErrorContext,
4938                        "xmlTextReaderSetup : malloc failed\n");
4939        return (-1);
4940    }
4941    xmlSAXVersion(reader->sax, 2);
4942    reader->startElement = reader->sax->startElement;
4943    reader->sax->startElement = xmlTextReaderStartElement;
4944    reader->endElement = reader->sax->endElement;
4945    reader->sax->endElement = xmlTextReaderEndElement;
4946#ifdef LIBXML_SAX1_ENABLED
4947    if (reader->sax->initialized == XML_SAX2_MAGIC) {
4948#endif /* LIBXML_SAX1_ENABLED */
4949        reader->startElementNs = reader->sax->startElementNs;
4950        reader->sax->startElementNs = xmlTextReaderStartElementNs;
4951        reader->endElementNs = reader->sax->endElementNs;
4952        reader->sax->endElementNs = xmlTextReaderEndElementNs;
4953#ifdef LIBXML_SAX1_ENABLED
4954    } else {
4955        reader->startElementNs = NULL;
4956        reader->endElementNs = NULL;
4957    }
4958#endif /* LIBXML_SAX1_ENABLED */
4959    reader->characters = reader->sax->characters;
4960    reader->sax->characters = xmlTextReaderCharacters;
4961    reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
4962    reader->cdataBlock = reader->sax->cdataBlock;
4963    reader->sax->cdataBlock = xmlTextReaderCDataBlock;
4964
4965    reader->mode = XML_TEXTREADER_MODE_INITIAL;
4966    reader->node = NULL;
4967    reader->curnode = NULL;
4968    if (input != NULL) {
4969        if (reader->input->buffer->use < 4) {
4970            xmlParserInputBufferRead(input, 4);
4971        }
4972        if (reader->ctxt == NULL) {
4973            if (reader->input->buffer->use >= 4) {
4974                reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
4975		       (const char *) reader->input->buffer->content, 4, URL);
4976                reader->base = 0;
4977                reader->cur = 4;
4978            } else {
4979                reader->ctxt =
4980                    xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
4981                reader->base = 0;
4982                reader->cur = 0;
4983            }
4984        } else {
4985	    xmlParserInputPtr inputStream;
4986	    xmlParserInputBufferPtr buf;
4987	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
4988
4989	    xmlCtxtReset(reader->ctxt);
4990	    buf = xmlAllocParserInputBuffer(enc);
4991	    if (buf == NULL) return(-1);
4992	    inputStream = xmlNewInputStream(reader->ctxt);
4993	    if (inputStream == NULL) {
4994		xmlFreeParserInputBuffer(buf);
4995		return(-1);
4996	    }
4997
4998	    if (URL == NULL)
4999		inputStream->filename = NULL;
5000	    else
5001		inputStream->filename = (char *)
5002		    xmlCanonicPath((const xmlChar *) URL);
5003	    inputStream->buf = buf;
5004	    inputStream->base = inputStream->buf->buffer->content;
5005	    inputStream->cur = inputStream->buf->buffer->content;
5006	    inputStream->end =
5007		&inputStream->buf->buffer->content[inputStream->buf->buffer->use];
5008
5009	    inputPush(reader->ctxt, inputStream);
5010	    reader->cur = 0;
5011	}
5012        if (reader->ctxt == NULL) {
5013            xmlGenericError(xmlGenericErrorContext,
5014                            "xmlTextReaderSetup : malloc failed\n");
5015            return (-1);
5016        }
5017    }
5018    if (reader->dict != NULL) {
5019        if (reader->ctxt->dict != NULL) {
5020	    if (reader->dict != reader->ctxt->dict) {
5021		xmlDictFree(reader->dict);
5022		reader->dict = reader->ctxt->dict;
5023	    }
5024	} else {
5025	    reader->ctxt->dict = reader->dict;
5026	}
5027    } else {
5028	if (reader->ctxt->dict == NULL)
5029	    reader->ctxt->dict = xmlDictCreate();
5030        reader->dict = reader->ctxt->dict;
5031    }
5032    reader->ctxt->_private = reader;
5033    reader->ctxt->linenumbers = 1;
5034    reader->ctxt->dictNames = 1;
5035    /*
5036     * use the parser dictionnary to allocate all elements and attributes names
5037     */
5038    reader->ctxt->docdict = 1;
5039    reader->ctxt->parseMode = XML_PARSE_READER;
5040
5041#ifdef LIBXML_XINCLUDE_ENABLED
5042    if (reader->xincctxt != NULL) {
5043	xmlXIncludeFreeContext(reader->xincctxt);
5044	reader->xincctxt = NULL;
5045    }
5046    if (options & XML_PARSE_XINCLUDE) {
5047        reader->xinclude = 1;
5048	reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
5049	options -= XML_PARSE_XINCLUDE;
5050    } else
5051        reader->xinclude = 0;
5052    reader->in_xinclude = 0;
5053#endif
5054#ifdef LIBXML_PATTERN_ENABLED
5055    if (reader->patternTab == NULL) {
5056        reader->patternNr = 0;
5057	reader->patternMax = 0;
5058    }
5059    while (reader->patternNr > 0) {
5060        reader->patternNr--;
5061	if (reader->patternTab[reader->patternNr] != NULL) {
5062	    xmlFreePattern(reader->patternTab[reader->patternNr]);
5063            reader->patternTab[reader->patternNr] = NULL;
5064	}
5065    }
5066#endif
5067
5068    if (options & XML_PARSE_DTDVALID)
5069        reader->validate = XML_TEXTREADER_VALIDATE_DTD;
5070
5071    xmlCtxtUseOptions(reader->ctxt, options);
5072    if (encoding != NULL) {
5073        xmlCharEncodingHandlerPtr hdlr;
5074
5075        hdlr = xmlFindCharEncodingHandler(encoding);
5076        if (hdlr != NULL)
5077            xmlSwitchToEncoding(reader->ctxt, hdlr);
5078    }
5079    if ((URL != NULL) && (reader->ctxt->input != NULL) &&
5080        (reader->ctxt->input->filename == NULL))
5081        reader->ctxt->input->filename = (char *)
5082            xmlStrdup((const xmlChar *) URL);
5083
5084    reader->doc = NULL;
5085
5086    return (0);
5087}
5088
5089/**
5090 * xmlTextReaderByteConsumed:
5091 * @reader: an XML reader
5092 *
5093 * This function provides the current index of the parser used
5094 * by the reader, relative to the start of the current entity.
5095 * This function actually just wraps a call to xmlBytesConsumed()
5096 * for the parser context associated with the reader.
5097 * See xmlBytesConsumed() for more information.
5098 *
5099 * Returns the index in bytes from the beginning of the entity or -1
5100 *         in case the index could not be computed.
5101 */
5102long
5103xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
5104    if ((reader == NULL) || (reader->ctxt == NULL))
5105        return(-1);
5106    return(xmlByteConsumed(reader->ctxt));
5107}
5108
5109
5110/**
5111 * xmlReaderWalker:
5112 * @doc:  a preparsed document
5113 *
5114 * Create an xmltextReader for a preparsed document.
5115 *
5116 * Returns the new reader or NULL in case of error.
5117 */
5118xmlTextReaderPtr
5119xmlReaderWalker(xmlDocPtr doc)
5120{
5121    xmlTextReaderPtr ret;
5122
5123    if (doc == NULL)
5124        return(NULL);
5125
5126    ret = xmlMalloc(sizeof(xmlTextReader));
5127    if (ret == NULL) {
5128        xmlGenericError(xmlGenericErrorContext,
5129		"xmlNewTextReader : malloc failed\n");
5130	return(NULL);
5131    }
5132    memset(ret, 0, sizeof(xmlTextReader));
5133    ret->entNr = 0;
5134    ret->input = NULL;
5135    ret->mode = XML_TEXTREADER_MODE_INITIAL;
5136    ret->node = NULL;
5137    ret->curnode = NULL;
5138    ret->base = 0;
5139    ret->cur = 0;
5140    ret->allocs = XML_TEXTREADER_CTXT;
5141    ret->doc = doc;
5142    ret->state = XML_TEXTREADER_START;
5143    ret->dict = xmlDictCreate();
5144    return(ret);
5145}
5146
5147/**
5148 * xmlReaderForDoc:
5149 * @cur:  a pointer to a zero terminated string
5150 * @URL:  the base URL to use for the document
5151 * @encoding:  the document encoding, or NULL
5152 * @options:  a combination of xmlParserOption
5153 *
5154 * Create an xmltextReader for an XML in-memory document.
5155 * The parsing flags @options are a combination of xmlParserOption.
5156 *
5157 * Returns the new reader or NULL in case of error.
5158 */
5159xmlTextReaderPtr
5160xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
5161                int options)
5162{
5163    int len;
5164
5165    if (cur == NULL)
5166        return (NULL);
5167    len = xmlStrlen(cur);
5168
5169    return (xmlReaderForMemory
5170            ((const char *) cur, len, URL, encoding, options));
5171}
5172
5173/**
5174 * xmlReaderForFile:
5175 * @filename:  a file or URL
5176 * @encoding:  the document encoding, or NULL
5177 * @options:  a combination of xmlParserOption
5178 *
5179 * parse an XML file from the filesystem or the network.
5180 * The parsing flags @options are a combination of xmlParserOption.
5181 *
5182 * Returns the new reader or NULL in case of error.
5183 */
5184xmlTextReaderPtr
5185xmlReaderForFile(const char *filename, const char *encoding, int options)
5186{
5187    xmlTextReaderPtr reader;
5188
5189    reader = xmlNewTextReaderFilename(filename);
5190    if (reader == NULL)
5191        return (NULL);
5192    xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
5193    return (reader);
5194}
5195
5196/**
5197 * xmlReaderForMemory:
5198 * @buffer:  a pointer to a char array
5199 * @size:  the size of the array
5200 * @URL:  the base URL to use for the document
5201 * @encoding:  the document encoding, or NULL
5202 * @options:  a combination of xmlParserOption
5203 *
5204 * Create an xmltextReader for an XML in-memory document.
5205 * The parsing flags @options are a combination of xmlParserOption.
5206 *
5207 * Returns the new reader or NULL in case of error.
5208 */
5209xmlTextReaderPtr
5210xmlReaderForMemory(const char *buffer, int size, const char *URL,
5211                   const char *encoding, int options)
5212{
5213    xmlTextReaderPtr reader;
5214    xmlParserInputBufferPtr buf;
5215
5216    buf = xmlParserInputBufferCreateStatic(buffer, size,
5217                                      XML_CHAR_ENCODING_NONE);
5218    if (buf == NULL) {
5219        return (NULL);
5220    }
5221    reader = xmlNewTextReader(buf, URL);
5222    if (reader == NULL) {
5223        xmlFreeParserInputBuffer(buf);
5224        return (NULL);
5225    }
5226    reader->allocs |= XML_TEXTREADER_INPUT;
5227    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5228    return (reader);
5229}
5230
5231/**
5232 * xmlReaderForFd:
5233 * @fd:  an open file descriptor
5234 * @URL:  the base URL to use for the document
5235 * @encoding:  the document encoding, or NULL
5236 * @options:  a combination of xmlParserOption
5237 *
5238 * Create an xmltextReader for an XML from a file descriptor.
5239 * The parsing flags @options are a combination of xmlParserOption.
5240 * NOTE that the file descriptor will not be closed when the
5241 *      reader is closed or reset.
5242 *
5243 * Returns the new reader or NULL in case of error.
5244 */
5245xmlTextReaderPtr
5246xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
5247{
5248    xmlTextReaderPtr reader;
5249    xmlParserInputBufferPtr input;
5250
5251    if (fd < 0)
5252        return (NULL);
5253
5254    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5255    if (input == NULL)
5256        return (NULL);
5257    input->closecallback = NULL;
5258    reader = xmlNewTextReader(input, URL);
5259    if (reader == NULL) {
5260        xmlFreeParserInputBuffer(input);
5261        return (NULL);
5262    }
5263    reader->allocs |= XML_TEXTREADER_INPUT;
5264    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5265    return (reader);
5266}
5267
5268/**
5269 * xmlReaderForIO:
5270 * @ioread:  an I/O read function
5271 * @ioclose:  an I/O close function
5272 * @ioctx:  an I/O handler
5273 * @URL:  the base URL to use for the document
5274 * @encoding:  the document encoding, or NULL
5275 * @options:  a combination of xmlParserOption
5276 *
5277 * Create an xmltextReader for an XML document from I/O functions and source.
5278 * The parsing flags @options are a combination of xmlParserOption.
5279 *
5280 * Returns the new reader or NULL in case of error.
5281 */
5282xmlTextReaderPtr
5283xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
5284               void *ioctx, const char *URL, const char *encoding,
5285               int options)
5286{
5287    xmlTextReaderPtr reader;
5288    xmlParserInputBufferPtr input;
5289
5290    if (ioread == NULL)
5291        return (NULL);
5292
5293    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5294                                         XML_CHAR_ENCODING_NONE);
5295    if (input == NULL)
5296        return (NULL);
5297    reader = xmlNewTextReader(input, URL);
5298    if (reader == NULL) {
5299        xmlFreeParserInputBuffer(input);
5300        return (NULL);
5301    }
5302    reader->allocs |= XML_TEXTREADER_INPUT;
5303    xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5304    return (reader);
5305}
5306
5307/**
5308 * xmlReaderNewWalker:
5309 * @reader:  an XML reader
5310 * @doc:  a preparsed document
5311 *
5312 * Setup an xmltextReader to parse a preparsed XML document.
5313 * This reuses the existing @reader xmlTextReader.
5314 *
5315 * Returns 0 in case of success and -1 in case of error
5316 */
5317int
5318xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
5319{
5320    if (doc == NULL)
5321        return (-1);
5322    if (reader == NULL)
5323        return (-1);
5324
5325    if (reader->input != NULL) {
5326        xmlFreeParserInputBuffer(reader->input);
5327    }
5328    if (reader->ctxt != NULL) {
5329	xmlCtxtReset(reader->ctxt);
5330    }
5331
5332    reader->entNr = 0;
5333    reader->input = NULL;
5334    reader->mode = XML_TEXTREADER_MODE_INITIAL;
5335    reader->node = NULL;
5336    reader->curnode = NULL;
5337    reader->base = 0;
5338    reader->cur = 0;
5339    reader->allocs = XML_TEXTREADER_CTXT;
5340    reader->doc = doc;
5341    reader->state = XML_TEXTREADER_START;
5342    if (reader->dict == NULL) {
5343        if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
5344	    reader->dict = reader->ctxt->dict;
5345	else
5346	    reader->dict = xmlDictCreate();
5347    }
5348    return(0);
5349}
5350
5351/**
5352 * xmlReaderNewDoc:
5353 * @reader:  an XML reader
5354 * @cur:  a pointer to a zero terminated string
5355 * @URL:  the base URL to use for the document
5356 * @encoding:  the document encoding, or NULL
5357 * @options:  a combination of xmlParserOption
5358 *
5359 * Setup an xmltextReader to parse an XML in-memory document.
5360 * The parsing flags @options are a combination of xmlParserOption.
5361 * This reuses the existing @reader xmlTextReader.
5362 *
5363 * Returns 0 in case of success and -1 in case of error
5364 */
5365int
5366xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
5367                const char *URL, const char *encoding, int options)
5368{
5369
5370    int len;
5371
5372    if (cur == NULL)
5373        return (-1);
5374    if (reader == NULL)
5375        return (-1);
5376
5377    len = xmlStrlen(cur);
5378    return (xmlReaderNewMemory(reader, (const char *)cur, len,
5379                               URL, encoding, options));
5380}
5381
5382/**
5383 * xmlReaderNewFile:
5384 * @reader:  an XML reader
5385 * @filename:  a file or URL
5386 * @encoding:  the document encoding, or NULL
5387 * @options:  a combination of xmlParserOption
5388 *
5389 * parse an XML file from the filesystem or the network.
5390 * The parsing flags @options are a combination of xmlParserOption.
5391 * This reuses the existing @reader xmlTextReader.
5392 *
5393 * Returns 0 in case of success and -1 in case of error
5394 */
5395int
5396xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
5397                 const char *encoding, int options)
5398{
5399    xmlParserInputBufferPtr input;
5400
5401    if (filename == NULL)
5402        return (-1);
5403    if (reader == NULL)
5404        return (-1);
5405
5406    input =
5407        xmlParserInputBufferCreateFilename(filename,
5408                                           XML_CHAR_ENCODING_NONE);
5409    if (input == NULL)
5410        return (-1);
5411    return (xmlTextReaderSetup(reader, input, filename, encoding, options));
5412}
5413
5414/**
5415 * xmlReaderNewMemory:
5416 * @reader:  an XML reader
5417 * @buffer:  a pointer to a char array
5418 * @size:  the size of the array
5419 * @URL:  the base URL to use for the document
5420 * @encoding:  the document encoding, or NULL
5421 * @options:  a combination of xmlParserOption
5422 *
5423 * Setup an xmltextReader to parse an XML in-memory document.
5424 * The parsing flags @options are a combination of xmlParserOption.
5425 * This reuses the existing @reader xmlTextReader.
5426 *
5427 * Returns 0 in case of success and -1 in case of error
5428 */
5429int
5430xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
5431                   const char *URL, const char *encoding, int options)
5432{
5433    xmlParserInputBufferPtr input;
5434
5435    if (reader == NULL)
5436        return (-1);
5437    if (buffer == NULL)
5438        return (-1);
5439
5440    input = xmlParserInputBufferCreateStatic(buffer, size,
5441                                      XML_CHAR_ENCODING_NONE);
5442    if (input == NULL) {
5443        return (-1);
5444    }
5445    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5446}
5447
5448/**
5449 * xmlReaderNewFd:
5450 * @reader:  an XML reader
5451 * @fd:  an open file descriptor
5452 * @URL:  the base URL to use for the document
5453 * @encoding:  the document encoding, or NULL
5454 * @options:  a combination of xmlParserOption
5455 *
5456 * Setup an xmltextReader to parse an XML from a file descriptor.
5457 * NOTE that the file descriptor will not be closed when the
5458 *      reader is closed or reset.
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
5465xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
5466               const char *URL, const char *encoding, int options)
5467{
5468    xmlParserInputBufferPtr input;
5469
5470    if (fd < 0)
5471        return (-1);
5472    if (reader == NULL)
5473        return (-1);
5474
5475    input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5476    if (input == NULL)
5477        return (-1);
5478    input->closecallback = NULL;
5479    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5480}
5481
5482/**
5483 * xmlReaderNewIO:
5484 * @reader:  an XML reader
5485 * @ioread:  an I/O read function
5486 * @ioclose:  an I/O close function
5487 * @ioctx:  an I/O handler
5488 * @URL:  the base URL to use for the document
5489 * @encoding:  the document encoding, or NULL
5490 * @options:  a combination of xmlParserOption
5491 *
5492 * Setup an xmltextReader to parse an XML document from I/O functions
5493 * and source.
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
5500xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
5501               xmlInputCloseCallback ioclose, void *ioctx,
5502               const char *URL, const char *encoding, int options)
5503{
5504    xmlParserInputBufferPtr input;
5505
5506    if (ioread == NULL)
5507        return (-1);
5508    if (reader == NULL)
5509        return (-1);
5510
5511    input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5512                                         XML_CHAR_ENCODING_NONE);
5513    if (input == NULL)
5514        return (-1);
5515    return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5516}
5517/************************************************************************
5518 *									*
5519 *			Utilities					*
5520 *									*
5521 ************************************************************************/
5522#ifdef NOT_USED_YET
5523/**
5524 * xmlBase64Decode:
5525 * @in:  the input buffer
5526 * @inlen:  the size of the input (in), the size read from it (out)
5527 * @to:  the output buffer
5528 * @tolen:  the size of the output (in), the size written to (out)
5529 *
5530 * Base64 decoder, reads from @in and save in @to
5531 * TODO: tell jody when this is actually exported
5532 *
5533 * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
5534 *         2 if there wasn't enough space on the output or -1 in case of error.
5535 */
5536static int
5537xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
5538	        unsigned char *to, unsigned long *tolen) {
5539    unsigned long incur;		/* current index in in[] */
5540    unsigned long inblk;		/* last block index in in[] */
5541    unsigned long outcur;		/* current index in out[] */
5542    unsigned long inmax;		/* size of in[] */
5543    unsigned long outmax;		/* size of out[] */
5544    unsigned char cur;			/* the current value read from in[] */
5545    unsigned char intmp[4], outtmp[4];	/* temporary buffers for the convert */
5546    int nbintmp;			/* number of byte in intmp[] */
5547    int is_ignore;			/* cur should be ignored */
5548    int is_end = 0;			/* the end of the base64 was found */
5549    int retval = 1;
5550    int i;
5551
5552    if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
5553	return(-1);
5554
5555    incur = 0;
5556    inblk = 0;
5557    outcur = 0;
5558    inmax = *inlen;
5559    outmax = *tolen;
5560    nbintmp = 0;
5561
5562    while (1) {
5563        if (incur >= inmax)
5564            break;
5565        cur = in[incur++];
5566        is_ignore = 0;
5567        if ((cur >= 'A') && (cur <= 'Z'))
5568            cur = cur - 'A';
5569        else if ((cur >= 'a') && (cur <= 'z'))
5570            cur = cur - 'a' + 26;
5571        else if ((cur >= '0') && (cur <= '9'))
5572            cur = cur - '0' + 52;
5573        else if (cur == '+')
5574            cur = 62;
5575        else if (cur == '/')
5576            cur = 63;
5577        else if (cur == '.')
5578            cur = 0;
5579        else if (cur == '=') /*no op , end of the base64 stream */
5580            is_end = 1;
5581        else {
5582            is_ignore = 1;
5583	    if (nbintmp == 0)
5584		inblk = incur;
5585	}
5586
5587        if (!is_ignore) {
5588            int nbouttmp = 3;
5589            int is_break = 0;
5590
5591            if (is_end) {
5592                if (nbintmp == 0)
5593                    break;
5594                if ((nbintmp == 1) || (nbintmp == 2))
5595                    nbouttmp = 1;
5596                else
5597                    nbouttmp = 2;
5598                nbintmp = 3;
5599                is_break = 1;
5600            }
5601            intmp[nbintmp++] = cur;
5602	    /*
5603	     * if intmp is full, push the 4byte sequence as a 3 byte
5604	     * sequence out
5605	     */
5606            if (nbintmp == 4) {
5607                nbintmp = 0;
5608                outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
5609                outtmp[1] =
5610                    ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
5611                outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
5612		if (outcur + 3 >= outmax) {
5613		    retval = 2;
5614		    break;
5615		}
5616
5617                for (i = 0; i < nbouttmp; i++)
5618		    to[outcur++] = outtmp[i];
5619		inblk = incur;
5620            }
5621
5622            if (is_break) {
5623		retval = 0;
5624                break;
5625	    }
5626        }
5627    }
5628
5629    *tolen = outcur;
5630    *inlen = inblk;
5631    return (retval);
5632}
5633
5634/*
5635 * Test routine for the xmlBase64Decode function
5636 */
5637#if 0
5638int main(int argc, char **argv) {
5639    char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
5640    char output[100];
5641    char output2[100];
5642    char output3[100];
5643    unsigned long inlen = strlen(input);
5644    unsigned long outlen = 100;
5645    int ret;
5646    unsigned long cons, tmp, tmp2, prod;
5647
5648    /*
5649     * Direct
5650     */
5651    ret = xmlBase64Decode(input, &inlen, output, &outlen);
5652
5653    output[outlen] = 0;
5654    printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen, outlen, output);
5655
5656    /*
5657     * output chunking
5658     */
5659    cons = 0;
5660    prod = 0;
5661    while (cons < inlen) {
5662	tmp = 5;
5663	tmp2 = inlen - cons;
5664
5665	printf("%ld %ld\n", cons, prod);
5666	ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
5667	cons += tmp2;
5668	prod += tmp;
5669	printf("%ld %ld\n", cons, prod);
5670    }
5671    output2[outlen] = 0;
5672    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output2);
5673
5674    /*
5675     * input chunking
5676     */
5677    cons = 0;
5678    prod = 0;
5679    while (cons < inlen) {
5680	tmp = 100 - prod;
5681	tmp2 = inlen - cons;
5682	if (tmp2 > 5)
5683	    tmp2 = 5;
5684
5685	printf("%ld %ld\n", cons, prod);
5686	ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
5687	cons += tmp2;
5688	prod += tmp;
5689	printf("%ld %ld\n", cons, prod);
5690    }
5691    output3[outlen] = 0;
5692    printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons, prod, output3);
5693    return(0);
5694
5695}
5696#endif
5697#endif /* NOT_USED_YET */
5698#define bottom_xmlreader
5699#include "elfgcchack.h"
5700#endif /* LIBXML_READER_ENABLED */
5701