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