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