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