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