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