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