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