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