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