• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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->state != XML_TEXTREADER_BACKTRACK) &&
1590         (reader->node != NULL) &&
1591 	(reader->node->type == XML_ELEMENT_NODE) &&
1592 	(reader->node->ns != NULL) &&
1593 	((xmlStrEqual(reader->node->ns->href, XINCLUDE_NS)) ||
1594 	 (xmlStrEqual(reader->node->ns->href, XINCLUDE_OLD_NS)))) {
1595 	if (reader->xincctxt == NULL) {
1596 	    reader->xincctxt = xmlXIncludeNewContext(reader->ctxt->myDoc);
1597 	    xmlXIncludeSetFlags(reader->xincctxt,
1598 	                        reader->parserFlags & (~XML_PARSE_NOXINCNODE));
1599 	}
1600 	/*
1601 	 * expand that node and process it
1602 	 */
1603 	if (xmlTextReaderExpand(reader) == NULL)
1604 	    return -1;
1605 	xmlXIncludeProcessNode(reader->xincctxt, reader->node);
1606     }
1607     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_START)) {
1608         reader->in_xinclude++;
1609 	goto get_next_node;
1610     }
1611     if ((reader->node != NULL) && (reader->node->type == XML_XINCLUDE_END)) {
1612         reader->in_xinclude--;
1613 	goto get_next_node;
1614     }
1615 #endif
1616     /*
1617      * Handle entities enter and exit when in entity replacement mode
1618      */
1619     if ((reader->node != NULL) &&
1620 	(reader->node->type == XML_ENTITY_REF_NODE) &&
1621 	(reader->ctxt != NULL) && (reader->ctxt->replaceEntities == 1)) {
1622 	if ((reader->node->children != NULL) &&
1623 	    (reader->node->children->type == XML_ENTITY_DECL) &&
1624 	    (reader->node->children->children != NULL)) {
1625 	    xmlTextReaderEntPush(reader, reader->node);
1626 	    reader->node = reader->node->children->children;
1627 	}
1628 #ifdef LIBXML_REGEXP_ENABLED
1629     } else if ((reader->node != NULL) &&
1630 	       (reader->node->type == XML_ENTITY_REF_NODE) &&
1631 	       (reader->ctxt != NULL) && (reader->validate)) {
1632 	xmlTextReaderValidateEntity(reader);
1633 #endif /* LIBXML_REGEXP_ENABLED */
1634     }
1635     if ((reader->node != NULL) &&
1636 	(reader->node->type == XML_ENTITY_DECL) &&
1637 	(reader->ent != NULL) && (reader->ent->children == reader->node)) {
1638 	reader->node = xmlTextReaderEntPop(reader);
1639 	reader->depth++;
1640         goto get_next_node;
1641     }
1642 #ifdef LIBXML_REGEXP_ENABLED
1643     if ((reader->validate != XML_TEXTREADER_NOT_VALIDATE) && (reader->node != NULL)) {
1644 	xmlNodePtr node = reader->node;
1645 
1646 	if ((node->type == XML_ELEMENT_NODE) &&
1647             ((reader->state != XML_TEXTREADER_END) &&
1648 	     (reader->state != XML_TEXTREADER_BACKTRACK))) {
1649 	    xmlTextReaderValidatePush(reader);
1650 	} else if ((node->type == XML_TEXT_NODE) ||
1651 		   (node->type == XML_CDATA_SECTION_NODE)) {
1652             xmlTextReaderValidateCData(reader, node->content,
1653 	                               xmlStrlen(node->content));
1654 	}
1655     }
1656 #endif /* LIBXML_REGEXP_ENABLED */
1657 #ifdef LIBXML_PATTERN_ENABLED
1658     if ((reader->patternNr > 0) && (reader->state != XML_TEXTREADER_END) &&
1659         (reader->state != XML_TEXTREADER_BACKTRACK)) {
1660         int i;
1661 	for (i = 0;i < reader->patternNr;i++) {
1662 	     if (xmlPatternMatch(reader->patternTab[i], reader->node) == 1) {
1663 	         xmlTextReaderPreserve(reader);
1664 		 break;
1665              }
1666 	}
1667     }
1668 #endif /* LIBXML_PATTERN_ENABLED */
1669 #ifdef LIBXML_SCHEMAS_ENABLED
1670     if ((reader->validate == XML_TEXTREADER_VALIDATE_XSD) &&
1671         (reader->xsdValidErrors == 0) &&
1672 	(reader->xsdValidCtxt != NULL)) {
1673 	reader->xsdValidErrors = !xmlSchemaIsValid(reader->xsdValidCtxt);
1674     }
1675 #endif /* LIBXML_PATTERN_ENABLED */
1676     return(1);
1677 node_end:
1678     reader->state = XML_TEXTREADER_DONE;
1679     return(0);
1680 }
1681 
1682 /**
1683  * xmlTextReaderReadState:
1684  * @reader:  the xmlTextReaderPtr used
1685  *
1686  * Gets the read state of the reader.
1687  *
1688  * Returns the state value, or -1 in case of error
1689  */
1690 int
xmlTextReaderReadState(xmlTextReaderPtr reader)1691 xmlTextReaderReadState(xmlTextReaderPtr reader) {
1692     if (reader == NULL)
1693 	return(-1);
1694     return(reader->mode);
1695 }
1696 
1697 /**
1698  * xmlTextReaderExpand:
1699  * @reader:  the xmlTextReaderPtr used
1700  *
1701  * Reads the contents of the current node and the full subtree. It then makes
1702  * the subtree available until the next xmlTextReaderRead() call
1703  *
1704  * Returns a node pointer valid until the next xmlTextReaderRead() call
1705  *         or NULL in case of error.
1706  */
1707 xmlNodePtr
xmlTextReaderExpand(xmlTextReaderPtr reader)1708 xmlTextReaderExpand(xmlTextReaderPtr reader) {
1709     if ((reader == NULL) || (reader->node == NULL))
1710         return(NULL);
1711     if (reader->doc != NULL)
1712         return(reader->node);
1713     if (reader->ctxt == NULL)
1714         return(NULL);
1715     if (xmlTextReaderDoExpand(reader) < 0)
1716         return(NULL);
1717     return(reader->node);
1718 }
1719 
1720 /**
1721  * xmlTextReaderNext:
1722  * @reader:  the xmlTextReaderPtr used
1723  *
1724  * Skip to the node following the current one in document order while
1725  * avoiding the subtree if any.
1726  *
1727  * Returns 1 if the node was read successfully, 0 if there is no more
1728  *          nodes to read, or -1 in case of error
1729  */
1730 int
xmlTextReaderNext(xmlTextReaderPtr reader)1731 xmlTextReaderNext(xmlTextReaderPtr reader) {
1732     int ret;
1733     xmlNodePtr cur;
1734 
1735     if (reader == NULL)
1736 	return(-1);
1737     if (reader->doc != NULL)
1738         return(xmlTextReaderNextTree(reader));
1739     cur = reader->node;
1740     if ((cur == NULL) || (cur->type != XML_ELEMENT_NODE))
1741         return(xmlTextReaderRead(reader));
1742     if (reader->state == XML_TEXTREADER_END || reader->state == XML_TEXTREADER_BACKTRACK)
1743         return(xmlTextReaderRead(reader));
1744     if (cur->extra & NODE_IS_EMPTY)
1745         return(xmlTextReaderRead(reader));
1746     do {
1747         ret = xmlTextReaderRead(reader);
1748 	if (ret != 1)
1749 	    return(ret);
1750     } while (reader->node != cur);
1751     return(xmlTextReaderRead(reader));
1752 }
1753 
1754 #ifdef LIBXML_WRITER_ENABLED
1755 /**
1756  * xmlTextReaderReadInnerXml:
1757  * @reader:  the xmlTextReaderPtr used
1758  *
1759  * Reads the contents of the current node, including child nodes and markup.
1760  *
1761  * Returns a string containing the XML content, or NULL if the current node
1762  *         is neither an element nor attribute, or has no child nodes. The
1763  *         string must be deallocated by the caller.
1764  */
1765 xmlChar *
xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)1766 xmlTextReaderReadInnerXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
1767 {
1768     xmlChar *resbuf;
1769     xmlNodePtr node, cur_node;
1770     xmlBufferPtr buff, buff2;
1771     xmlDocPtr doc;
1772 
1773     if (xmlTextReaderExpand(reader) == NULL) {
1774         return NULL;
1775     }
1776     doc = reader->node->doc;
1777     buff = xmlBufferCreate();
1778     if (buff == NULL)
1779         return NULL;
1780     for (cur_node = reader->node->children; cur_node != NULL;
1781          cur_node = cur_node->next) {
1782         /* XXX: Why is the node copied? */
1783         node = xmlDocCopyNode(cur_node, doc, 1);
1784         buff2 = xmlBufferCreate();
1785         if (xmlNodeDump(buff2, doc, node, 0, 0) == -1) {
1786             xmlFreeNode(node);
1787             xmlBufferFree(buff2);
1788             xmlBufferFree(buff);
1789             return NULL;
1790         }
1791         xmlBufferCat(buff, buff2->content);
1792         xmlFreeNode(node);
1793         xmlBufferFree(buff2);
1794     }
1795     resbuf = buff->content;
1796     buff->content = NULL;
1797 
1798     xmlBufferFree(buff);
1799     return resbuf;
1800 }
1801 #endif
1802 
1803 #ifdef LIBXML_WRITER_ENABLED
1804 /**
1805  * xmlTextReaderReadOuterXml:
1806  * @reader:  the xmlTextReaderPtr used
1807  *
1808  * Reads the contents of the current node, including child nodes and markup.
1809  *
1810  * Returns a string containing the node and any XML content, or NULL if the
1811  *         current node cannot be serialized. The string must be deallocated
1812  *         by the caller.
1813  */
1814 xmlChar *
xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)1815 xmlTextReaderReadOuterXml(xmlTextReaderPtr reader ATTRIBUTE_UNUSED)
1816 {
1817     xmlChar *resbuf;
1818     xmlNodePtr node;
1819     xmlBufferPtr buff;
1820     xmlDocPtr doc;
1821 
1822     if (xmlTextReaderExpand(reader) == NULL) {
1823         return NULL;
1824     }
1825     node = reader->node;
1826     doc = node->doc;
1827     /* XXX: Why is the node copied? */
1828 	if (node->type == XML_DTD_NODE) {
1829 		node = (xmlNodePtr) xmlCopyDtd((xmlDtdPtr) node);
1830 	} else {
1831 		node = xmlDocCopyNode(node, doc, 1);
1832 	}
1833     buff = xmlBufferCreate();
1834     if (xmlNodeDump(buff, doc, node, 0, 0) == -1) {
1835         xmlFreeNode(node);
1836         xmlBufferFree(buff);
1837         return NULL;
1838     }
1839 
1840     resbuf = buff->content;
1841     buff->content = NULL;
1842 
1843     xmlFreeNode(node);
1844     xmlBufferFree(buff);
1845     return resbuf;
1846 }
1847 #endif
1848 
1849 /**
1850  * xmlTextReaderReadString:
1851  * @reader:  the xmlTextReaderPtr used
1852  *
1853  * Reads the contents of an element or a text node as a string.
1854  *
1855  * Returns a string containing the contents of the Element or Text node,
1856  *         or NULL if the reader is positioned on any other type of node.
1857  *         The string must be deallocated by the caller.
1858  */
1859 xmlChar *
xmlTextReaderReadString(xmlTextReaderPtr reader)1860 xmlTextReaderReadString(xmlTextReaderPtr reader)
1861 {
1862     xmlNodePtr node;
1863 
1864     if ((reader == NULL) || (reader->node == NULL))
1865        return(NULL);
1866 
1867     node = (reader->curnode != NULL) ? reader->curnode : reader->node;
1868     switch (node->type) {
1869     case XML_TEXT_NODE:
1870        if (node->content != NULL)
1871            return(xmlStrdup(node->content));
1872        break;
1873     case XML_ELEMENT_NODE:
1874 	if (xmlTextReaderDoExpand(reader) != -1) {
1875 	    return xmlTextReaderCollectSiblings(node->children);
1876 	}
1877 	break;
1878     case XML_ATTRIBUTE_NODE:
1879 	TODO
1880 	break;
1881     default:
1882        break;
1883     }
1884     return(NULL);
1885 }
1886 
1887 #if 0
1888 /**
1889  * xmlTextReaderReadBase64:
1890  * @reader:  the xmlTextReaderPtr used
1891  * @array:  a byte array to store the content.
1892  * @offset:  the zero-based index into array where the method should
1893  *           begin to write.
1894  * @len:  the number of bytes to write.
1895  *
1896  * Reads and decodes the Base64 encoded contents of an element and
1897  * stores the result in a byte buffer.
1898  *
1899  * Returns the number of bytes written to array, or zero if the current
1900  *         instance is not positioned on an element or -1 in case of error.
1901  */
1902 int
1903 xmlTextReaderReadBase64(xmlTextReaderPtr reader,
1904                         unsigned char *array ATTRIBUTE_UNUSED,
1905 	                int offset ATTRIBUTE_UNUSED,
1906 			int len ATTRIBUTE_UNUSED) {
1907     if ((reader == NULL) || (reader->ctxt == NULL))
1908 	return(-1);
1909     if (reader->ctxt->wellFormed != 1)
1910 	return(-1);
1911 
1912     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1913 	return(0);
1914     TODO
1915     return(0);
1916 }
1917 
1918 /**
1919  * xmlTextReaderReadBinHex:
1920  * @reader:  the xmlTextReaderPtr used
1921  * @array:  a byte array to store the content.
1922  * @offset:  the zero-based index into array where the method should
1923  *           begin to write.
1924  * @len:  the number of bytes to write.
1925  *
1926  * Reads and decodes the BinHex encoded contents of an element and
1927  * stores the result in a byte buffer.
1928  *
1929  * Returns the number of bytes written to array, or zero if the current
1930  *         instance is not positioned on an element or -1 in case of error.
1931  */
1932 int
1933 xmlTextReaderReadBinHex(xmlTextReaderPtr reader,
1934                         unsigned char *array ATTRIBUTE_UNUSED,
1935 	                int offset ATTRIBUTE_UNUSED,
1936 			int len ATTRIBUTE_UNUSED) {
1937     if ((reader == NULL) || (reader->ctxt == NULL))
1938 	return(-1);
1939     if (reader->ctxt->wellFormed != 1)
1940 	return(-1);
1941 
1942     if ((reader->node == NULL) || (reader->node->type == XML_ELEMENT_NODE))
1943 	return(0);
1944     TODO
1945     return(0);
1946 }
1947 #endif
1948 
1949 /************************************************************************
1950  *									*
1951  *			Operating on a preparsed tree			*
1952  *									*
1953  ************************************************************************/
1954 static int
xmlTextReaderNextTree(xmlTextReaderPtr reader)1955 xmlTextReaderNextTree(xmlTextReaderPtr reader)
1956 {
1957     if (reader == NULL)
1958         return(-1);
1959 
1960     if (reader->state == XML_TEXTREADER_END)
1961         return(0);
1962 
1963     if (reader->node == NULL) {
1964         if (reader->doc->children == NULL) {
1965             reader->state = XML_TEXTREADER_END;
1966             return(0);
1967         }
1968 
1969         reader->node = reader->doc->children;
1970         reader->state = XML_TEXTREADER_START;
1971         return(1);
1972     }
1973 
1974     if (reader->state != XML_TEXTREADER_BACKTRACK) {
1975 	/* Here removed traversal to child, because we want to skip the subtree,
1976 	replace with traversal to sibling to skip subtree */
1977         if (reader->node->next != 0) {
1978 	    /* Move to sibling if present,skipping sub-tree */
1979             reader->node = reader->node->next;
1980             reader->state = XML_TEXTREADER_START;
1981             return(1);
1982         }
1983 
1984 	/* if reader->node->next is NULL mean no subtree for current node,
1985 	so need to move to sibling of parent node if present */
1986 	reader->state = XML_TEXTREADER_BACKTRACK;
1987 	/* This will move to parent if present */
1988 	xmlTextReaderRead(reader);
1989     }
1990 
1991     if (reader->node->next != 0) {
1992         reader->node = reader->node->next;
1993         reader->state = XML_TEXTREADER_START;
1994         return(1);
1995     }
1996 
1997     if (reader->node->parent != 0) {
1998         if (reader->node->parent->type == XML_DOCUMENT_NODE) {
1999             reader->state = XML_TEXTREADER_END;
2000             return(0);
2001         }
2002 
2003         reader->node = reader->node->parent;
2004         reader->depth--;
2005         reader->state = XML_TEXTREADER_BACKTRACK;
2006 	/* Repeat process to move to sibling of parent node if present */
2007         xmlTextReaderNextTree(reader);
2008     }
2009 
2010     reader->state = XML_TEXTREADER_END;
2011 
2012     return(1);
2013 }
2014 
2015 /**
2016  * xmlTextReaderReadTree:
2017  * @reader:  the xmlTextReaderPtr used
2018  *
2019  *  Moves the position of the current instance to the next node in
2020  *  the stream, exposing its properties.
2021  *
2022  *  Returns 1 if the node was read successfully, 0 if there is no more
2023  *          nodes to read, or -1 in case of error
2024  */
2025 static int
xmlTextReaderReadTree(xmlTextReaderPtr reader)2026 xmlTextReaderReadTree(xmlTextReaderPtr reader) {
2027     if (reader->state == XML_TEXTREADER_END)
2028         return(0);
2029 
2030 next_node:
2031     if (reader->node == NULL) {
2032         if (reader->doc->children == NULL) {
2033             reader->state = XML_TEXTREADER_END;
2034             return(0);
2035         }
2036 
2037         reader->node = reader->doc->children;
2038         reader->state = XML_TEXTREADER_START;
2039         goto found_node;
2040     }
2041 
2042     if ((reader->state != XML_TEXTREADER_BACKTRACK) &&
2043         (reader->node->type != XML_DTD_NODE) &&
2044         (reader->node->type != XML_XINCLUDE_START) &&
2045 	(reader->node->type != XML_ENTITY_REF_NODE)) {
2046         if (reader->node->children != NULL) {
2047             reader->node = reader->node->children;
2048             reader->depth++;
2049             reader->state = XML_TEXTREADER_START;
2050             goto found_node;
2051         }
2052 
2053         if (reader->node->type == XML_ATTRIBUTE_NODE) {
2054             reader->state = XML_TEXTREADER_BACKTRACK;
2055             goto found_node;
2056         }
2057     }
2058 
2059     if (reader->node->next != NULL) {
2060         reader->node = reader->node->next;
2061         reader->state = XML_TEXTREADER_START;
2062         goto found_node;
2063     }
2064 
2065     if (reader->node->parent != NULL) {
2066         if ((reader->node->parent->type == XML_DOCUMENT_NODE) ||
2067 	    (reader->node->parent->type == XML_HTML_DOCUMENT_NODE)) {
2068             reader->state = XML_TEXTREADER_END;
2069             return(0);
2070         }
2071 
2072         reader->node = reader->node->parent;
2073         reader->depth--;
2074         reader->state = XML_TEXTREADER_BACKTRACK;
2075         goto found_node;
2076     }
2077 
2078     reader->state = XML_TEXTREADER_END;
2079 
2080 found_node:
2081     if ((reader->node->type == XML_XINCLUDE_START) ||
2082         (reader->node->type == XML_XINCLUDE_END))
2083 	goto next_node;
2084 
2085     return(1);
2086 }
2087 
2088 /**
2089  * xmlTextReaderNextSibling:
2090  * @reader:  the xmlTextReaderPtr used
2091  *
2092  * Skip to the node following the current one in document order while
2093  * avoiding the subtree if any.
2094  * Currently implemented only for Readers built on a document
2095  *
2096  * Returns 1 if the node was read successfully, 0 if there is no more
2097  *          nodes to read, or -1 in case of error
2098  */
2099 int
xmlTextReaderNextSibling(xmlTextReaderPtr reader)2100 xmlTextReaderNextSibling(xmlTextReaderPtr reader) {
2101     if (reader == NULL)
2102         return(-1);
2103     if (reader->doc == NULL) {
2104         /* TODO */
2105 	return(-1);
2106     }
2107 
2108     if (reader->state == XML_TEXTREADER_END)
2109         return(0);
2110 
2111     if (reader->node == NULL)
2112         return(xmlTextReaderNextTree(reader));
2113 
2114     if (reader->node->next != NULL) {
2115         reader->node = reader->node->next;
2116         reader->state = XML_TEXTREADER_START;
2117         return(1);
2118     }
2119 
2120     return(0);
2121 }
2122 
2123 /************************************************************************
2124  *									*
2125  *			Constructor and destructors			*
2126  *									*
2127  ************************************************************************/
2128 /**
2129  * xmlNewTextReader:
2130  * @input: the xmlParserInputBufferPtr used to read data
2131  * @URI: the URI information for the source if available
2132  *
2133  * Create an xmlTextReader structure fed with @input
2134  *
2135  * Returns the new xmlTextReaderPtr or NULL in case of error
2136  */
2137 xmlTextReaderPtr
xmlNewTextReader(xmlParserInputBufferPtr input,const char * URI)2138 xmlNewTextReader(xmlParserInputBufferPtr input, const char *URI) {
2139     xmlTextReaderPtr ret;
2140 
2141     if (input == NULL)
2142 	return(NULL);
2143     ret = xmlMalloc(sizeof(xmlTextReader));
2144     if (ret == NULL) {
2145         xmlGenericError(xmlGenericErrorContext,
2146 		"xmlNewTextReader : malloc failed\n");
2147 	return(NULL);
2148     }
2149     memset(ret, 0, sizeof(xmlTextReader));
2150     ret->doc = NULL;
2151     ret->entTab = NULL;
2152     ret->entMax = 0;
2153     ret->entNr = 0;
2154     ret->input = input;
2155     ret->buffer = xmlBufCreateSize(100);
2156     if (ret->buffer == NULL) {
2157         xmlFree(ret);
2158         xmlGenericError(xmlGenericErrorContext,
2159 		"xmlNewTextReader : malloc failed\n");
2160 	return(NULL);
2161     }
2162     /* no operation on a reader should require a huge buffer */
2163     xmlBufSetAllocationScheme(ret->buffer,
2164 			      XML_BUFFER_ALLOC_BOUNDED);
2165     ret->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
2166     if (ret->sax == NULL) {
2167 	xmlBufFree(ret->buffer);
2168 	xmlFree(ret);
2169         xmlGenericError(xmlGenericErrorContext,
2170 		"xmlNewTextReader : malloc failed\n");
2171 	return(NULL);
2172     }
2173     xmlSAXVersion(ret->sax, 2);
2174     ret->startElement = ret->sax->startElement;
2175     ret->sax->startElement = xmlTextReaderStartElement;
2176     ret->endElement = ret->sax->endElement;
2177     ret->sax->endElement = xmlTextReaderEndElement;
2178 #ifdef LIBXML_SAX1_ENABLED
2179     if (ret->sax->initialized == XML_SAX2_MAGIC) {
2180 #endif /* LIBXML_SAX1_ENABLED */
2181 	ret->startElementNs = ret->sax->startElementNs;
2182 	ret->sax->startElementNs = xmlTextReaderStartElementNs;
2183 	ret->endElementNs = ret->sax->endElementNs;
2184 	ret->sax->endElementNs = xmlTextReaderEndElementNs;
2185 #ifdef LIBXML_SAX1_ENABLED
2186     } else {
2187 	ret->startElementNs = NULL;
2188 	ret->endElementNs = NULL;
2189     }
2190 #endif /* LIBXML_SAX1_ENABLED */
2191     ret->characters = ret->sax->characters;
2192     ret->sax->characters = xmlTextReaderCharacters;
2193     ret->sax->ignorableWhitespace = xmlTextReaderCharacters;
2194     ret->cdataBlock = ret->sax->cdataBlock;
2195     ret->sax->cdataBlock = xmlTextReaderCDataBlock;
2196 
2197     ret->mode = XML_TEXTREADER_MODE_INITIAL;
2198     ret->node = NULL;
2199     ret->curnode = NULL;
2200     if (xmlBufUse(ret->input->buffer) < 4) {
2201 	xmlParserInputBufferRead(input, 4);
2202     }
2203     if (xmlBufUse(ret->input->buffer) >= 4) {
2204 	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL,
2205 			     (const char *) xmlBufContent(ret->input->buffer),
2206                                             4, URI);
2207 	ret->base = 0;
2208 	ret->cur = 4;
2209     } else {
2210 	ret->ctxt = xmlCreatePushParserCtxt(ret->sax, NULL, NULL, 0, URI);
2211 	ret->base = 0;
2212 	ret->cur = 0;
2213     }
2214 
2215     if (ret->ctxt == NULL) {
2216         xmlGenericError(xmlGenericErrorContext,
2217 		"xmlNewTextReader : malloc failed\n");
2218 	xmlBufFree(ret->buffer);
2219 	xmlFree(ret->sax);
2220 	xmlFree(ret);
2221 	return(NULL);
2222     }
2223     ret->ctxt->parseMode = XML_PARSE_READER;
2224     ret->ctxt->_private = ret;
2225     ret->ctxt->linenumbers = 1;
2226     ret->ctxt->dictNames = 1;
2227     ret->allocs = XML_TEXTREADER_CTXT;
2228     /*
2229      * use the parser dictionary to allocate all elements and attributes names
2230      */
2231     ret->ctxt->docdict = 1;
2232     ret->dict = ret->ctxt->dict;
2233 #ifdef LIBXML_XINCLUDE_ENABLED
2234     ret->xinclude = 0;
2235 #endif
2236 #ifdef LIBXML_PATTERN_ENABLED
2237     ret->patternMax = 0;
2238     ret->patternTab = NULL;
2239 #endif
2240     return(ret);
2241 }
2242 
2243 /**
2244  * xmlNewTextReaderFilename:
2245  * @URI: the URI of the resource to process
2246  *
2247  * Create an xmlTextReader structure fed with the resource at @URI
2248  *
2249  * Returns the new xmlTextReaderPtr or NULL in case of error
2250  */
2251 xmlTextReaderPtr
xmlNewTextReaderFilename(const char * URI)2252 xmlNewTextReaderFilename(const char *URI) {
2253     xmlParserInputBufferPtr input;
2254     xmlTextReaderPtr ret;
2255     char *directory = NULL;
2256 
2257     input = xmlParserInputBufferCreateFilename(URI, XML_CHAR_ENCODING_NONE);
2258     if (input == NULL)
2259 	return(NULL);
2260     ret = xmlNewTextReader(input, URI);
2261     if (ret == NULL) {
2262 	xmlFreeParserInputBuffer(input);
2263 	return(NULL);
2264     }
2265     ret->allocs |= XML_TEXTREADER_INPUT;
2266     if (ret->ctxt->directory == NULL)
2267         directory = xmlParserGetDirectory(URI);
2268     if ((ret->ctxt->directory == NULL) && (directory != NULL))
2269         ret->ctxt->directory = (char *) xmlStrdup((xmlChar *) directory);
2270     if (directory != NULL)
2271 	xmlFree(directory);
2272     return(ret);
2273 }
2274 
2275 /**
2276  * xmlFreeTextReader:
2277  * @reader:  the xmlTextReaderPtr
2278  *
2279  * Deallocate all the resources associated to the reader
2280  */
2281 void
xmlFreeTextReader(xmlTextReaderPtr reader)2282 xmlFreeTextReader(xmlTextReaderPtr reader) {
2283     if (reader == NULL)
2284 	return;
2285 #ifdef LIBXML_SCHEMAS_ENABLED
2286     if (reader->rngSchemas != NULL) {
2287 	xmlRelaxNGFree(reader->rngSchemas);
2288 	reader->rngSchemas = NULL;
2289     }
2290     if (reader->rngValidCtxt != NULL) {
2291 	if (! reader->rngPreserveCtxt)
2292 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
2293 	reader->rngValidCtxt = NULL;
2294     }
2295     if (reader->xsdPlug != NULL) {
2296 	xmlSchemaSAXUnplug(reader->xsdPlug);
2297 	reader->xsdPlug = NULL;
2298     }
2299     if (reader->xsdValidCtxt != NULL) {
2300 	if (! reader->xsdPreserveCtxt)
2301 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
2302 	reader->xsdValidCtxt = NULL;
2303     }
2304     if (reader->xsdSchemas != NULL) {
2305 	xmlSchemaFree(reader->xsdSchemas);
2306 	reader->xsdSchemas = NULL;
2307     }
2308 #endif
2309 #ifdef LIBXML_XINCLUDE_ENABLED
2310     if (reader->xincctxt != NULL)
2311 	xmlXIncludeFreeContext(reader->xincctxt);
2312 #endif
2313 #ifdef LIBXML_PATTERN_ENABLED
2314     if (reader->patternTab != NULL) {
2315         int i;
2316 	for (i = 0;i < reader->patternNr;i++) {
2317 	    if (reader->patternTab[i] != NULL)
2318 	        xmlFreePattern(reader->patternTab[i]);
2319 	}
2320 	xmlFree(reader->patternTab);
2321     }
2322 #endif
2323     if (reader->faketext != NULL) {
2324 	xmlFreeNode(reader->faketext);
2325     }
2326     if (reader->ctxt != NULL) {
2327         if (reader->dict == reader->ctxt->dict)
2328 	    reader->dict = NULL;
2329 #ifdef LIBXML_VALID_ENABLED
2330 	if ((reader->ctxt->vctxt.vstateTab != NULL) &&
2331 	    (reader->ctxt->vctxt.vstateMax > 0)){
2332 #ifdef LIBXML_REGEXP_ENABLED
2333             while (reader->ctxt->vctxt.vstateNr > 0)
2334                 xmlValidatePopElement(&reader->ctxt->vctxt, NULL, NULL, NULL);
2335 #endif /* LIBXML_REGEXP_ENABLED */
2336 	    xmlFree(reader->ctxt->vctxt.vstateTab);
2337 	    reader->ctxt->vctxt.vstateTab = NULL;
2338 	    reader->ctxt->vctxt.vstateMax = 0;
2339 	}
2340 #endif /* LIBXML_VALID_ENABLED */
2341 	if (reader->ctxt->myDoc != NULL) {
2342 	    if (reader->preserve == 0)
2343 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2344 	    reader->ctxt->myDoc = NULL;
2345 	}
2346 	if (reader->allocs & XML_TEXTREADER_CTXT)
2347 	    xmlFreeParserCtxt(reader->ctxt);
2348     }
2349     if (reader->sax != NULL)
2350 	xmlFree(reader->sax);
2351     if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT))
2352 	xmlFreeParserInputBuffer(reader->input);
2353     if (reader->buffer != NULL)
2354         xmlBufFree(reader->buffer);
2355     if (reader->entTab != NULL)
2356 	xmlFree(reader->entTab);
2357     if (reader->dict != NULL)
2358         xmlDictFree(reader->dict);
2359     xmlFree(reader);
2360 }
2361 
2362 /************************************************************************
2363  *									*
2364  *			Methods for XmlTextReader			*
2365  *									*
2366  ************************************************************************/
2367 /**
2368  * xmlTextReaderClose:
2369  * @reader:  the xmlTextReaderPtr used
2370  *
2371  * This method releases any resources allocated by the current instance
2372  * changes the state to Closed and close any underlying input.
2373  *
2374  * Returns 0 or -1 in case of error
2375  */
2376 int
xmlTextReaderClose(xmlTextReaderPtr reader)2377 xmlTextReaderClose(xmlTextReaderPtr reader) {
2378     if (reader == NULL)
2379 	return(-1);
2380     reader->node = NULL;
2381     reader->curnode = NULL;
2382     reader->mode = XML_TEXTREADER_MODE_CLOSED;
2383     if (reader->ctxt != NULL) {
2384 	xmlStopParser(reader->ctxt);
2385 	if (reader->ctxt->myDoc != NULL) {
2386 	    if (reader->preserve == 0)
2387 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2388 	    reader->ctxt->myDoc = NULL;
2389 	}
2390     }
2391     if ((reader->input != NULL)  && (reader->allocs & XML_TEXTREADER_INPUT)) {
2392 	xmlFreeParserInputBuffer(reader->input);
2393 	reader->allocs -= XML_TEXTREADER_INPUT;
2394     }
2395     return(0);
2396 }
2397 
2398 /**
2399  * xmlTextReaderGetAttributeNo:
2400  * @reader:  the xmlTextReaderPtr used
2401  * @no: the zero-based index of the attribute relative to the containing element
2402  *
2403  * Provides the value of the attribute with the specified index relative
2404  * to the containing element.
2405  *
2406  * Returns a string containing the value of the specified attribute, or NULL
2407  *    in case of error. The string must be deallocated by the caller.
2408  */
2409 xmlChar *
xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader,int no)2410 xmlTextReaderGetAttributeNo(xmlTextReaderPtr reader, int no) {
2411     xmlChar *ret;
2412     int i;
2413     xmlAttrPtr cur;
2414     xmlNsPtr ns;
2415 
2416     if (reader == NULL)
2417 	return(NULL);
2418     if (reader->node == NULL)
2419 	return(NULL);
2420     if (reader->curnode != NULL)
2421 	return(NULL);
2422     /* TODO: handle the xmlDecl */
2423     if (reader->node->type != XML_ELEMENT_NODE)
2424 	return(NULL);
2425 
2426     ns = reader->node->nsDef;
2427     for (i = 0;(i < no) && (ns != NULL);i++) {
2428 	ns = ns->next;
2429     }
2430     if (ns != NULL)
2431 	return(xmlStrdup(ns->href));
2432 
2433     cur = reader->node->properties;
2434     if (cur == NULL)
2435 	return(NULL);
2436     for (;i < no;i++) {
2437 	cur = cur->next;
2438 	if (cur == NULL)
2439 	    return(NULL);
2440     }
2441     /* TODO walk the DTD if present */
2442 
2443     ret = xmlNodeListGetString(reader->node->doc, cur->children, 1);
2444     if (ret == NULL) return(xmlStrdup((xmlChar *)""));
2445     return(ret);
2446 }
2447 
2448 /**
2449  * xmlTextReaderGetAttribute:
2450  * @reader:  the xmlTextReaderPtr used
2451  * @name: the qualified name of the attribute.
2452  *
2453  * Provides the value of the attribute with the specified qualified name.
2454  *
2455  * Returns a string containing the value of the specified attribute, or NULL
2456  *    in case of error. The string must be deallocated by the caller.
2457  */
2458 xmlChar *
xmlTextReaderGetAttribute(xmlTextReaderPtr reader,const xmlChar * name)2459 xmlTextReaderGetAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2460     xmlChar *prefix = NULL;
2461     xmlChar *localname;
2462     xmlNsPtr ns;
2463     xmlChar *ret = NULL;
2464 
2465     if ((reader == NULL) || (name == NULL))
2466 	return(NULL);
2467     if (reader->node == NULL)
2468 	return(NULL);
2469     if (reader->curnode != NULL)
2470 	return(NULL);
2471 
2472     /* TODO: handle the xmlDecl */
2473     if (reader->node->type != XML_ELEMENT_NODE)
2474 	return(NULL);
2475 
2476     localname = xmlSplitQName2(name, &prefix);
2477     if (localname == NULL) {
2478 		/*
2479 		 * Namespace default decl
2480 		 */
2481 		if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2482 			ns = reader->node->nsDef;
2483 			while (ns != NULL) {
2484 				if (ns->prefix == NULL) {
2485 					return(xmlStrdup(ns->href));
2486 				}
2487 				ns = ns->next;
2488 			}
2489 			return NULL;
2490 		}
2491 		return(xmlGetNoNsProp(reader->node, name));
2492 	}
2493 
2494     /*
2495      * Namespace default decl
2496      */
2497     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2498 		ns = reader->node->nsDef;
2499 		while (ns != NULL) {
2500 			if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2501 				ret = xmlStrdup(ns->href);
2502 				break;
2503 			}
2504 			ns = ns->next;
2505 		}
2506     } else {
2507 		ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
2508 		if (ns != NULL)
2509 			ret = xmlGetNsProp(reader->node, localname, ns->href);
2510 	}
2511 
2512     xmlFree(localname);
2513     if (prefix != NULL)
2514         xmlFree(prefix);
2515     return(ret);
2516 }
2517 
2518 
2519 /**
2520  * xmlTextReaderGetAttributeNs:
2521  * @reader:  the xmlTextReaderPtr used
2522  * @localName: the local name of the attribute.
2523  * @namespaceURI: the namespace URI of the attribute.
2524  *
2525  * Provides the value of the specified attribute
2526  *
2527  * Returns a string containing the value of the specified attribute, or NULL
2528  *    in case of error. The string must be deallocated by the caller.
2529  */
2530 xmlChar *
xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader,const xmlChar * localName,const xmlChar * namespaceURI)2531 xmlTextReaderGetAttributeNs(xmlTextReaderPtr reader, const xmlChar *localName,
2532 			    const xmlChar *namespaceURI) {
2533     xmlChar *prefix = NULL;
2534     xmlNsPtr ns;
2535 
2536     if ((reader == NULL) || (localName == NULL))
2537 	return(NULL);
2538     if (reader->node == NULL)
2539 	return(NULL);
2540     if (reader->curnode != NULL)
2541 	return(NULL);
2542 
2543     /* TODO: handle the xmlDecl */
2544     if (reader->node->type != XML_ELEMENT_NODE)
2545 	return(NULL);
2546 
2547     if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
2548 		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
2549 			prefix = BAD_CAST localName;
2550 		}
2551 		ns = reader->node->nsDef;
2552 		while (ns != NULL) {
2553 			if ((prefix == NULL && ns->prefix == NULL) ||
2554 				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
2555 				return xmlStrdup(ns->href);
2556 			}
2557 			ns = ns->next;
2558 		}
2559 		return NULL;
2560     }
2561 
2562     return(xmlGetNsProp(reader->node, localName, namespaceURI));
2563 }
2564 
2565 /**
2566  * xmlTextReaderGetRemainder:
2567  * @reader:  the xmlTextReaderPtr used
2568  *
2569  * Method to get the remainder of the buffered XML. this method stops the
2570  * parser, set its state to End Of File and return the input stream with
2571  * what is left that the parser did not use.
2572  *
2573  * The implementation is not good, the parser certainly progressed past
2574  * what's left in reader->input, and there is an allocation problem. Best
2575  * would be to rewrite it differently.
2576  *
2577  * Returns the xmlParserInputBufferPtr attached to the XML or NULL
2578  *    in case of error.
2579  */
2580 xmlParserInputBufferPtr
xmlTextReaderGetRemainder(xmlTextReaderPtr reader)2581 xmlTextReaderGetRemainder(xmlTextReaderPtr reader) {
2582     xmlParserInputBufferPtr ret = NULL;
2583 
2584     if (reader == NULL)
2585 	return(NULL);
2586     if (reader->node == NULL)
2587 	return(NULL);
2588 
2589     reader->node = NULL;
2590     reader->curnode = NULL;
2591     reader->mode = XML_TEXTREADER_MODE_EOF;
2592     if (reader->ctxt != NULL) {
2593 	xmlStopParser(reader->ctxt);
2594 	if (reader->ctxt->myDoc != NULL) {
2595 	    if (reader->preserve == 0)
2596 		xmlTextReaderFreeDoc(reader, reader->ctxt->myDoc);
2597 	    reader->ctxt->myDoc = NULL;
2598 	}
2599     }
2600     if (reader->allocs & XML_TEXTREADER_INPUT) {
2601 	ret = reader->input;
2602 	reader->input = NULL;
2603 	reader->allocs -= XML_TEXTREADER_INPUT;
2604     } else {
2605 	/*
2606 	 * Hum, one may need to duplicate the data structure because
2607 	 * without reference counting the input may be freed twice:
2608 	 *   - by the layer which allocated it.
2609 	 *   - by the layer to which would have been returned to.
2610 	 */
2611 	TODO
2612 	return(NULL);
2613     }
2614     return(ret);
2615 }
2616 
2617 /**
2618  * xmlTextReaderLookupNamespace:
2619  * @reader:  the xmlTextReaderPtr used
2620  * @prefix: the prefix whose namespace URI is to be resolved. To return
2621  *          the default namespace, specify NULL
2622  *
2623  * Resolves a namespace prefix in the scope of the current element.
2624  *
2625  * Returns a string containing the namespace URI to which the prefix maps
2626  *    or NULL in case of error. The string must be deallocated by the caller.
2627  */
2628 xmlChar *
xmlTextReaderLookupNamespace(xmlTextReaderPtr reader,const xmlChar * prefix)2629 xmlTextReaderLookupNamespace(xmlTextReaderPtr reader, const xmlChar *prefix) {
2630     xmlNsPtr ns;
2631 
2632     if (reader == NULL)
2633 	return(NULL);
2634     if (reader->node == NULL)
2635 	return(NULL);
2636 
2637     ns = xmlSearchNs(reader->node->doc, reader->node, prefix);
2638     if (ns == NULL)
2639 	return(NULL);
2640     return(xmlStrdup(ns->href));
2641 }
2642 
2643 /**
2644  * xmlTextReaderMoveToAttributeNo:
2645  * @reader:  the xmlTextReaderPtr used
2646  * @no: the zero-based index of the attribute relative to the containing
2647  *      element.
2648  *
2649  * Moves the position of the current instance to the attribute with
2650  * the specified index relative to the containing element.
2651  *
2652  * Returns 1 in case of success, -1 in case of error, 0 if not found
2653  */
2654 int
xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader,int no)2655 xmlTextReaderMoveToAttributeNo(xmlTextReaderPtr reader, int no) {
2656     int i;
2657     xmlAttrPtr cur;
2658     xmlNsPtr ns;
2659 
2660     if (reader == NULL)
2661 	return(-1);
2662     if (reader->node == NULL)
2663 	return(-1);
2664     /* TODO: handle the xmlDecl */
2665     if (reader->node->type != XML_ELEMENT_NODE)
2666 	return(-1);
2667 
2668     reader->curnode = NULL;
2669 
2670     ns = reader->node->nsDef;
2671     for (i = 0;(i < no) && (ns != NULL);i++) {
2672 	ns = ns->next;
2673     }
2674     if (ns != NULL) {
2675 	reader->curnode = (xmlNodePtr) ns;
2676 	return(1);
2677     }
2678 
2679     cur = reader->node->properties;
2680     if (cur == NULL)
2681 	return(0);
2682     for (;i < no;i++) {
2683 	cur = cur->next;
2684 	if (cur == NULL)
2685 	    return(0);
2686     }
2687     /* TODO walk the DTD if present */
2688 
2689     reader->curnode = (xmlNodePtr) cur;
2690     return(1);
2691 }
2692 
2693 /**
2694  * xmlTextReaderMoveToAttribute:
2695  * @reader:  the xmlTextReaderPtr used
2696  * @name: the qualified name of the attribute.
2697  *
2698  * Moves the position of the current instance to the attribute with
2699  * the specified qualified name.
2700  *
2701  * Returns 1 in case of success, -1 in case of error, 0 if not found
2702  */
2703 int
xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader,const xmlChar * name)2704 xmlTextReaderMoveToAttribute(xmlTextReaderPtr reader, const xmlChar *name) {
2705     xmlChar *prefix = NULL;
2706     xmlChar *localname;
2707     xmlNsPtr ns;
2708     xmlAttrPtr prop;
2709 
2710     if ((reader == NULL) || (name == NULL))
2711 	return(-1);
2712     if (reader->node == NULL)
2713 	return(-1);
2714 
2715     /* TODO: handle the xmlDecl */
2716     if (reader->node->type != XML_ELEMENT_NODE)
2717 	return(0);
2718 
2719     localname = xmlSplitQName2(name, &prefix);
2720     if (localname == NULL) {
2721 	/*
2722 	 * Namespace default decl
2723 	 */
2724 	if (xmlStrEqual(name, BAD_CAST "xmlns")) {
2725 	    ns = reader->node->nsDef;
2726 	    while (ns != NULL) {
2727 		if (ns->prefix == NULL) {
2728 		    reader->curnode = (xmlNodePtr) ns;
2729 		    return(1);
2730 		}
2731 		ns = ns->next;
2732 	    }
2733 	    return(0);
2734 	}
2735 
2736 	prop = reader->node->properties;
2737 	while (prop != NULL) {
2738 	    /*
2739 	     * One need to have
2740 	     *   - same attribute names
2741 	     *   - and the attribute carrying that namespace
2742 	     */
2743 	    if ((xmlStrEqual(prop->name, name)) &&
2744 		((prop->ns == NULL) || (prop->ns->prefix == NULL))) {
2745 		reader->curnode = (xmlNodePtr) prop;
2746 		return(1);
2747 	    }
2748 	    prop = prop->next;
2749 	}
2750 	return(0);
2751     }
2752 
2753     /*
2754      * Namespace default decl
2755      */
2756     if (xmlStrEqual(prefix, BAD_CAST "xmlns")) {
2757 	ns = reader->node->nsDef;
2758 	while (ns != NULL) {
2759 	    if ((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localname))) {
2760 		reader->curnode = (xmlNodePtr) ns;
2761 		goto found;
2762 	    }
2763 	    ns = ns->next;
2764 	}
2765 	goto not_found;
2766     }
2767     prop = reader->node->properties;
2768     while (prop != NULL) {
2769 	/*
2770 	 * One need to have
2771 	 *   - same attribute names
2772 	 *   - and the attribute carrying that namespace
2773 	 */
2774 	if ((xmlStrEqual(prop->name, localname)) &&
2775 	    (prop->ns != NULL) && (xmlStrEqual(prop->ns->prefix, prefix))) {
2776 	    reader->curnode = (xmlNodePtr) prop;
2777 	    goto found;
2778 	}
2779 	prop = prop->next;
2780     }
2781 not_found:
2782     if (localname != NULL)
2783         xmlFree(localname);
2784     if (prefix != NULL)
2785         xmlFree(prefix);
2786     return(0);
2787 
2788 found:
2789     if (localname != NULL)
2790         xmlFree(localname);
2791     if (prefix != NULL)
2792         xmlFree(prefix);
2793     return(1);
2794 }
2795 
2796 /**
2797  * xmlTextReaderMoveToAttributeNs:
2798  * @reader:  the xmlTextReaderPtr used
2799  * @localName:  the local name of the attribute.
2800  * @namespaceURI:  the namespace URI of the attribute.
2801  *
2802  * Moves the position of the current instance to the attribute with the
2803  * specified local name and namespace URI.
2804  *
2805  * Returns 1 in case of success, -1 in case of error, 0 if not found
2806  */
2807 int
xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,const xmlChar * localName,const xmlChar * namespaceURI)2808 xmlTextReaderMoveToAttributeNs(xmlTextReaderPtr reader,
2809 	const xmlChar *localName, const xmlChar *namespaceURI) {
2810     xmlAttrPtr prop;
2811     xmlNodePtr node;
2812     xmlNsPtr ns;
2813     xmlChar *prefix = NULL;
2814 
2815     if ((reader == NULL) || (localName == NULL) || (namespaceURI == NULL))
2816 	return(-1);
2817     if (reader->node == NULL)
2818 	return(-1);
2819     if (reader->node->type != XML_ELEMENT_NODE)
2820 	return(0);
2821     node = reader->node;
2822 
2823     if (xmlStrEqual(namespaceURI, BAD_CAST "http://www.w3.org/2000/xmlns/")) {
2824 		if (! xmlStrEqual(localName, BAD_CAST "xmlns")) {
2825 			prefix = BAD_CAST localName;
2826 		}
2827 		ns = reader->node->nsDef;
2828 		while (ns != NULL) {
2829 			if ((prefix == NULL && ns->prefix == NULL) ||
2830 				((ns->prefix != NULL) && (xmlStrEqual(ns->prefix, localName)))) {
2831 				reader->curnode = (xmlNodePtr) ns;
2832 				return(1);
2833 			}
2834 			ns = ns->next;
2835 		}
2836 		return(0);
2837     }
2838 
2839     prop = node->properties;
2840     while (prop != NULL) {
2841 	/*
2842 	 * One need to have
2843 	 *   - same attribute names
2844 	 *   - and the attribute carrying that namespace
2845 	 */
2846         if (xmlStrEqual(prop->name, localName) &&
2847 	    ((prop->ns != NULL) &&
2848 	     (xmlStrEqual(prop->ns->href, namespaceURI)))) {
2849 	    reader->curnode = (xmlNodePtr) prop;
2850 	    return(1);
2851         }
2852 	prop = prop->next;
2853     }
2854     return(0);
2855 }
2856 
2857 /**
2858  * xmlTextReaderMoveToFirstAttribute:
2859  * @reader:  the xmlTextReaderPtr used
2860  *
2861  * Moves the position of the current instance to the first attribute
2862  * associated with the current node.
2863  *
2864  * Returns 1 in case of success, -1 in case of error, 0 if not found
2865  */
2866 int
xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader)2867 xmlTextReaderMoveToFirstAttribute(xmlTextReaderPtr reader) {
2868     if (reader == NULL)
2869 	return(-1);
2870     if (reader->node == NULL)
2871 	return(-1);
2872     if (reader->node->type != XML_ELEMENT_NODE)
2873 	return(0);
2874 
2875     if (reader->node->nsDef != NULL) {
2876 	reader->curnode = (xmlNodePtr) reader->node->nsDef;
2877 	return(1);
2878     }
2879     if (reader->node->properties != NULL) {
2880 	reader->curnode = (xmlNodePtr) reader->node->properties;
2881 	return(1);
2882     }
2883     return(0);
2884 }
2885 
2886 /**
2887  * xmlTextReaderMoveToNextAttribute:
2888  * @reader:  the xmlTextReaderPtr used
2889  *
2890  * Moves the position of the current instance to the next attribute
2891  * associated with the current node.
2892  *
2893  * Returns 1 in case of success, -1 in case of error, 0 if not found
2894  */
2895 int
xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader)2896 xmlTextReaderMoveToNextAttribute(xmlTextReaderPtr reader) {
2897     if (reader == NULL)
2898 	return(-1);
2899     if (reader->node == NULL)
2900 	return(-1);
2901     if (reader->node->type != XML_ELEMENT_NODE)
2902 	return(0);
2903     if (reader->curnode == NULL)
2904 	return(xmlTextReaderMoveToFirstAttribute(reader));
2905 
2906     if (reader->curnode->type == XML_NAMESPACE_DECL) {
2907 	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2908 	if (ns->next != NULL) {
2909 	    reader->curnode = (xmlNodePtr) ns->next;
2910 	    return(1);
2911 	}
2912 	if (reader->node->properties != NULL) {
2913 	    reader->curnode = (xmlNodePtr) reader->node->properties;
2914 	    return(1);
2915 	}
2916 	return(0);
2917     } else if ((reader->curnode->type == XML_ATTRIBUTE_NODE) &&
2918 	       (reader->curnode->next != NULL)) {
2919 	reader->curnode = reader->curnode->next;
2920 	return(1);
2921     }
2922     return(0);
2923 }
2924 
2925 /**
2926  * xmlTextReaderMoveToElement:
2927  * @reader:  the xmlTextReaderPtr used
2928  *
2929  * Moves the position of the current instance to the node that
2930  * contains the current Attribute  node.
2931  *
2932  * Returns 1 in case of success, -1 in case of error, 0 if not moved
2933  */
2934 int
xmlTextReaderMoveToElement(xmlTextReaderPtr reader)2935 xmlTextReaderMoveToElement(xmlTextReaderPtr reader) {
2936     if (reader == NULL)
2937 	return(-1);
2938     if (reader->node == NULL)
2939 	return(-1);
2940     if (reader->node->type != XML_ELEMENT_NODE)
2941 	return(0);
2942     if (reader->curnode != NULL) {
2943 	reader->curnode = NULL;
2944 	return(1);
2945     }
2946     return(0);
2947 }
2948 
2949 /**
2950  * xmlTextReaderReadAttributeValue:
2951  * @reader:  the xmlTextReaderPtr used
2952  *
2953  * Parses an attribute value into one or more Text and EntityReference nodes.
2954  *
2955  * Returns 1 in case of success, 0 if the reader was not positioned on an
2956  *         attribute node or all the attribute values have been read, or -1
2957  *         in case of error.
2958  */
2959 int
xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader)2960 xmlTextReaderReadAttributeValue(xmlTextReaderPtr reader) {
2961     if (reader == NULL)
2962 	return(-1);
2963     if (reader->node == NULL)
2964 	return(-1);
2965     if (reader->curnode == NULL)
2966 	return(0);
2967     if (reader->curnode->type == XML_ATTRIBUTE_NODE) {
2968 	if (reader->curnode->children == NULL)
2969 	    return(0);
2970 	reader->curnode = reader->curnode->children;
2971     } else if (reader->curnode->type == XML_NAMESPACE_DECL) {
2972 	xmlNsPtr ns = (xmlNsPtr) reader->curnode;
2973 
2974 	if (reader->faketext == NULL) {
2975 	    reader->faketext = xmlNewDocText(reader->node->doc,
2976 		                             ns->href);
2977 	} else {
2978             if ((reader->faketext->content != NULL) &&
2979 	        (reader->faketext->content !=
2980 		 (xmlChar *) &(reader->faketext->properties)))
2981 		xmlFree(reader->faketext->content);
2982 	    reader->faketext->content = xmlStrdup(ns->href);
2983 	}
2984 	reader->curnode = reader->faketext;
2985     } else {
2986 	if (reader->curnode->next == NULL)
2987 	    return(0);
2988 	reader->curnode = reader->curnode->next;
2989     }
2990     return(1);
2991 }
2992 
2993 /**
2994  * xmlTextReaderConstEncoding:
2995  * @reader:  the xmlTextReaderPtr used
2996  *
2997  * Determine the encoding of the document being read.
2998  *
2999  * Returns a string containing the encoding of the document or NULL in
3000  * case of error.  The string is deallocated with the reader.
3001  */
3002 const xmlChar *
xmlTextReaderConstEncoding(xmlTextReaderPtr reader)3003 xmlTextReaderConstEncoding(xmlTextReaderPtr reader) {
3004     xmlDocPtr doc = NULL;
3005     if (reader == NULL)
3006 	return(NULL);
3007     if (reader->doc != NULL)
3008         doc = reader->doc;
3009     else if (reader->ctxt != NULL)
3010 	doc = reader->ctxt->myDoc;
3011     if (doc == NULL)
3012 	return(NULL);
3013 
3014     if (doc->encoding == NULL)
3015 	return(NULL);
3016     else
3017       return(CONSTSTR(doc->encoding));
3018 }
3019 
3020 
3021 /************************************************************************
3022  *									*
3023  *			Access API to the current node			*
3024  *									*
3025  ************************************************************************/
3026 /**
3027  * xmlTextReaderAttributeCount:
3028  * @reader:  the xmlTextReaderPtr used
3029  *
3030  * Provides the number of attributes of the current node
3031  *
3032  * Returns 0 i no attributes, -1 in case of error or the attribute count
3033  */
3034 int
xmlTextReaderAttributeCount(xmlTextReaderPtr reader)3035 xmlTextReaderAttributeCount(xmlTextReaderPtr reader) {
3036     int ret;
3037     xmlAttrPtr attr;
3038     xmlNsPtr ns;
3039     xmlNodePtr node;
3040 
3041     if (reader == NULL)
3042 	return(-1);
3043     if (reader->node == NULL)
3044 	return(0);
3045 
3046     if (reader->curnode != NULL)
3047 	node = reader->curnode;
3048     else
3049 	node = reader->node;
3050 
3051     if (node->type != XML_ELEMENT_NODE)
3052 	return(0);
3053     if ((reader->state == XML_TEXTREADER_END) ||
3054 	(reader->state == XML_TEXTREADER_BACKTRACK))
3055 	return(0);
3056     ret = 0;
3057     attr = node->properties;
3058     while (attr != NULL) {
3059 	ret++;
3060 	attr = attr->next;
3061     }
3062     ns = node->nsDef;
3063     while (ns != NULL) {
3064 	ret++;
3065 	ns = ns->next;
3066     }
3067     return(ret);
3068 }
3069 
3070 /**
3071  * xmlTextReaderNodeType:
3072  * @reader:  the xmlTextReaderPtr used
3073  *
3074  * Get the node type of the current node
3075  * Reference:
3076  * http://www.gnu.org/software/dotgnu/pnetlib-doc/System/Xml/XmlNodeType.html
3077  *
3078  * Returns the xmlReaderTypes of the current node or -1 in case of error
3079  */
3080 int
xmlTextReaderNodeType(xmlTextReaderPtr reader)3081 xmlTextReaderNodeType(xmlTextReaderPtr reader) {
3082     xmlNodePtr node;
3083 
3084     if (reader == NULL)
3085 	return(-1);
3086     if (reader->node == NULL)
3087 	return(XML_READER_TYPE_NONE);
3088     if (reader->curnode != NULL)
3089 	node = reader->curnode;
3090     else
3091 	node = reader->node;
3092     switch (node->type) {
3093         case XML_ELEMENT_NODE:
3094 	    if ((reader->state == XML_TEXTREADER_END) ||
3095 		(reader->state == XML_TEXTREADER_BACKTRACK))
3096 		return(XML_READER_TYPE_END_ELEMENT);
3097 	    return(XML_READER_TYPE_ELEMENT);
3098         case XML_NAMESPACE_DECL:
3099         case XML_ATTRIBUTE_NODE:
3100 	    return(XML_READER_TYPE_ATTRIBUTE);
3101         case XML_TEXT_NODE:
3102 	    if (xmlIsBlankNode(reader->node)) {
3103 		if (xmlNodeGetSpacePreserve(reader->node))
3104 		    return(XML_READER_TYPE_SIGNIFICANT_WHITESPACE);
3105 		else
3106 		    return(XML_READER_TYPE_WHITESPACE);
3107 	    } else {
3108 		return(XML_READER_TYPE_TEXT);
3109 	    }
3110         case XML_CDATA_SECTION_NODE:
3111 	    return(XML_READER_TYPE_CDATA);
3112         case XML_ENTITY_REF_NODE:
3113 	    return(XML_READER_TYPE_ENTITY_REFERENCE);
3114         case XML_ENTITY_NODE:
3115 	    return(XML_READER_TYPE_ENTITY);
3116         case XML_PI_NODE:
3117 	    return(XML_READER_TYPE_PROCESSING_INSTRUCTION);
3118         case XML_COMMENT_NODE:
3119 	    return(XML_READER_TYPE_COMMENT);
3120         case XML_DOCUMENT_NODE:
3121         case XML_HTML_DOCUMENT_NODE:
3122 #ifdef LIBXML_DOCB_ENABLED
3123         case XML_DOCB_DOCUMENT_NODE:
3124 #endif
3125 	    return(XML_READER_TYPE_DOCUMENT);
3126         case XML_DOCUMENT_FRAG_NODE:
3127 	    return(XML_READER_TYPE_DOCUMENT_FRAGMENT);
3128         case XML_NOTATION_NODE:
3129 	    return(XML_READER_TYPE_NOTATION);
3130         case XML_DOCUMENT_TYPE_NODE:
3131         case XML_DTD_NODE:
3132 	    return(XML_READER_TYPE_DOCUMENT_TYPE);
3133 
3134         case XML_ELEMENT_DECL:
3135         case XML_ATTRIBUTE_DECL:
3136         case XML_ENTITY_DECL:
3137         case XML_XINCLUDE_START:
3138         case XML_XINCLUDE_END:
3139 	    return(XML_READER_TYPE_NONE);
3140     }
3141     return(-1);
3142 }
3143 
3144 /**
3145  * xmlTextReaderIsEmptyElement:
3146  * @reader:  the xmlTextReaderPtr used
3147  *
3148  * Check if the current node is empty
3149  *
3150  * Returns 1 if empty, 0 if not and -1 in case of error
3151  */
3152 int
xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader)3153 xmlTextReaderIsEmptyElement(xmlTextReaderPtr reader) {
3154     if ((reader == NULL) || (reader->node == NULL))
3155 	return(-1);
3156     if (reader->node->type != XML_ELEMENT_NODE)
3157 	return(0);
3158     if (reader->curnode != NULL)
3159 	return(0);
3160     if (reader->node->children != NULL)
3161 	return(0);
3162     if (reader->state == XML_TEXTREADER_END)
3163 	return(0);
3164     if (reader->doc != NULL)
3165         return(1);
3166 #ifdef LIBXML_XINCLUDE_ENABLED
3167     if (reader->in_xinclude > 0)
3168         return(1);
3169 #endif
3170     return((reader->node->extra & NODE_IS_EMPTY) != 0);
3171 }
3172 
3173 /**
3174  * xmlTextReaderLocalName:
3175  * @reader:  the xmlTextReaderPtr used
3176  *
3177  * The local name of the node.
3178  *
3179  * Returns the local name or NULL if not available,
3180  *   if non NULL it need to be freed by the caller.
3181  */
3182 xmlChar *
xmlTextReaderLocalName(xmlTextReaderPtr reader)3183 xmlTextReaderLocalName(xmlTextReaderPtr reader) {
3184     xmlNodePtr node;
3185     if ((reader == NULL) || (reader->node == NULL))
3186 	return(NULL);
3187     if (reader->curnode != NULL)
3188 	node = reader->curnode;
3189     else
3190 	node = reader->node;
3191     if (node->type == XML_NAMESPACE_DECL) {
3192 	xmlNsPtr ns = (xmlNsPtr) node;
3193 	if (ns->prefix == NULL)
3194 	    return(xmlStrdup(BAD_CAST "xmlns"));
3195 	else
3196 	    return(xmlStrdup(ns->prefix));
3197     }
3198     if ((node->type != XML_ELEMENT_NODE) &&
3199 	(node->type != XML_ATTRIBUTE_NODE))
3200 	return(xmlTextReaderName(reader));
3201     return(xmlStrdup(node->name));
3202 }
3203 
3204 /**
3205  * xmlTextReaderConstLocalName:
3206  * @reader:  the xmlTextReaderPtr used
3207  *
3208  * The local name of the node.
3209  *
3210  * Returns the local name or NULL if not available, the
3211  *         string will be deallocated with the reader.
3212  */
3213 const xmlChar *
xmlTextReaderConstLocalName(xmlTextReaderPtr reader)3214 xmlTextReaderConstLocalName(xmlTextReaderPtr reader) {
3215     xmlNodePtr node;
3216     if ((reader == NULL) || (reader->node == NULL))
3217 	return(NULL);
3218     if (reader->curnode != NULL)
3219 	node = reader->curnode;
3220     else
3221 	node = reader->node;
3222     if (node->type == XML_NAMESPACE_DECL) {
3223 	xmlNsPtr ns = (xmlNsPtr) node;
3224 	if (ns->prefix == NULL)
3225 	    return(CONSTSTR(BAD_CAST "xmlns"));
3226 	else
3227 	    return(ns->prefix);
3228     }
3229     if ((node->type != XML_ELEMENT_NODE) &&
3230 	(node->type != XML_ATTRIBUTE_NODE))
3231 	return(xmlTextReaderConstName(reader));
3232     return(node->name);
3233 }
3234 
3235 /**
3236  * xmlTextReaderName:
3237  * @reader:  the xmlTextReaderPtr used
3238  *
3239  * The qualified name of the node, equal to Prefix :LocalName.
3240  *
3241  * Returns the local name or NULL if not available,
3242  *   if non NULL it need to be freed by the caller.
3243  */
3244 xmlChar *
xmlTextReaderName(xmlTextReaderPtr reader)3245 xmlTextReaderName(xmlTextReaderPtr reader) {
3246     xmlNodePtr node;
3247     xmlChar *ret;
3248 
3249     if ((reader == NULL) || (reader->node == NULL))
3250 	return(NULL);
3251     if (reader->curnode != NULL)
3252 	node = reader->curnode;
3253     else
3254 	node = reader->node;
3255     switch (node->type) {
3256         case XML_ELEMENT_NODE:
3257         case XML_ATTRIBUTE_NODE:
3258 	    if ((node->ns == NULL) ||
3259 		(node->ns->prefix == NULL))
3260 		return(xmlStrdup(node->name));
3261 
3262 	    ret = xmlStrdup(node->ns->prefix);
3263 	    ret = xmlStrcat(ret, BAD_CAST ":");
3264 	    ret = xmlStrcat(ret, node->name);
3265 	    return(ret);
3266         case XML_TEXT_NODE:
3267 	    return(xmlStrdup(BAD_CAST "#text"));
3268         case XML_CDATA_SECTION_NODE:
3269 	    return(xmlStrdup(BAD_CAST "#cdata-section"));
3270         case XML_ENTITY_NODE:
3271         case XML_ENTITY_REF_NODE:
3272 	    return(xmlStrdup(node->name));
3273         case XML_PI_NODE:
3274 	    return(xmlStrdup(node->name));
3275         case XML_COMMENT_NODE:
3276 	    return(xmlStrdup(BAD_CAST "#comment"));
3277         case XML_DOCUMENT_NODE:
3278         case XML_HTML_DOCUMENT_NODE:
3279 #ifdef LIBXML_DOCB_ENABLED
3280         case XML_DOCB_DOCUMENT_NODE:
3281 #endif
3282 	    return(xmlStrdup(BAD_CAST "#document"));
3283         case XML_DOCUMENT_FRAG_NODE:
3284 	    return(xmlStrdup(BAD_CAST "#document-fragment"));
3285         case XML_NOTATION_NODE:
3286 	    return(xmlStrdup(node->name));
3287         case XML_DOCUMENT_TYPE_NODE:
3288         case XML_DTD_NODE:
3289 	    return(xmlStrdup(node->name));
3290         case XML_NAMESPACE_DECL: {
3291 	    xmlNsPtr ns = (xmlNsPtr) node;
3292 
3293 	    ret = xmlStrdup(BAD_CAST "xmlns");
3294 	    if (ns->prefix == NULL)
3295 		return(ret);
3296 	    ret = xmlStrcat(ret, BAD_CAST ":");
3297 	    ret = xmlStrcat(ret, ns->prefix);
3298 	    return(ret);
3299 	}
3300 
3301         case XML_ELEMENT_DECL:
3302         case XML_ATTRIBUTE_DECL:
3303         case XML_ENTITY_DECL:
3304         case XML_XINCLUDE_START:
3305         case XML_XINCLUDE_END:
3306 	    return(NULL);
3307     }
3308     return(NULL);
3309 }
3310 
3311 /**
3312  * xmlTextReaderConstName:
3313  * @reader:  the xmlTextReaderPtr used
3314  *
3315  * The qualified name of the node, equal to Prefix :LocalName.
3316  *
3317  * Returns the local name or NULL if not available, the string is
3318  *         deallocated with the reader.
3319  */
3320 const xmlChar *
xmlTextReaderConstName(xmlTextReaderPtr reader)3321 xmlTextReaderConstName(xmlTextReaderPtr reader) {
3322     xmlNodePtr node;
3323 
3324     if ((reader == NULL) || (reader->node == NULL))
3325 	return(NULL);
3326     if (reader->curnode != NULL)
3327 	node = reader->curnode;
3328     else
3329 	node = reader->node;
3330     switch (node->type) {
3331         case XML_ELEMENT_NODE:
3332         case XML_ATTRIBUTE_NODE:
3333 	    if ((node->ns == NULL) ||
3334 		(node->ns->prefix == NULL))
3335 		return(node->name);
3336 	    return(CONSTQSTR(node->ns->prefix, node->name));
3337         case XML_TEXT_NODE:
3338 	    return(CONSTSTR(BAD_CAST "#text"));
3339         case XML_CDATA_SECTION_NODE:
3340 	    return(CONSTSTR(BAD_CAST "#cdata-section"));
3341         case XML_ENTITY_NODE:
3342         case XML_ENTITY_REF_NODE:
3343 	    return(CONSTSTR(node->name));
3344         case XML_PI_NODE:
3345 	    return(CONSTSTR(node->name));
3346         case XML_COMMENT_NODE:
3347 	    return(CONSTSTR(BAD_CAST "#comment"));
3348         case XML_DOCUMENT_NODE:
3349         case XML_HTML_DOCUMENT_NODE:
3350 #ifdef LIBXML_DOCB_ENABLED
3351         case XML_DOCB_DOCUMENT_NODE:
3352 #endif
3353 	    return(CONSTSTR(BAD_CAST "#document"));
3354         case XML_DOCUMENT_FRAG_NODE:
3355 	    return(CONSTSTR(BAD_CAST "#document-fragment"));
3356         case XML_NOTATION_NODE:
3357 	    return(CONSTSTR(node->name));
3358         case XML_DOCUMENT_TYPE_NODE:
3359         case XML_DTD_NODE:
3360 	    return(CONSTSTR(node->name));
3361         case XML_NAMESPACE_DECL: {
3362 	    xmlNsPtr ns = (xmlNsPtr) node;
3363 
3364 	    if (ns->prefix == NULL)
3365 		return(CONSTSTR(BAD_CAST "xmlns"));
3366 	    return(CONSTQSTR(BAD_CAST "xmlns", ns->prefix));
3367 	}
3368 
3369         case XML_ELEMENT_DECL:
3370         case XML_ATTRIBUTE_DECL:
3371         case XML_ENTITY_DECL:
3372         case XML_XINCLUDE_START:
3373         case XML_XINCLUDE_END:
3374 	    return(NULL);
3375     }
3376     return(NULL);
3377 }
3378 
3379 /**
3380  * xmlTextReaderPrefix:
3381  * @reader:  the xmlTextReaderPtr used
3382  *
3383  * A shorthand reference to the namespace associated with the node.
3384  *
3385  * Returns the prefix or NULL if not available,
3386  *    if non NULL it need to be freed by the caller.
3387  */
3388 xmlChar *
xmlTextReaderPrefix(xmlTextReaderPtr reader)3389 xmlTextReaderPrefix(xmlTextReaderPtr reader) {
3390     xmlNodePtr node;
3391     if ((reader == NULL) || (reader->node == NULL))
3392 	return(NULL);
3393     if (reader->curnode != NULL)
3394 	node = reader->curnode;
3395     else
3396 	node = reader->node;
3397     if (node->type == XML_NAMESPACE_DECL) {
3398 	xmlNsPtr ns = (xmlNsPtr) node;
3399 	if (ns->prefix == NULL)
3400 	    return(NULL);
3401 	return(xmlStrdup(BAD_CAST "xmlns"));
3402     }
3403     if ((node->type != XML_ELEMENT_NODE) &&
3404 	(node->type != XML_ATTRIBUTE_NODE))
3405 	return(NULL);
3406     if ((node->ns != NULL) && (node->ns->prefix != NULL))
3407 	return(xmlStrdup(node->ns->prefix));
3408     return(NULL);
3409 }
3410 
3411 /**
3412  * xmlTextReaderConstPrefix:
3413  * @reader:  the xmlTextReaderPtr used
3414  *
3415  * A shorthand reference to the namespace associated with the node.
3416  *
3417  * Returns the prefix or NULL if not available, the string is deallocated
3418  *         with the reader.
3419  */
3420 const xmlChar *
xmlTextReaderConstPrefix(xmlTextReaderPtr reader)3421 xmlTextReaderConstPrefix(xmlTextReaderPtr reader) {
3422     xmlNodePtr node;
3423     if ((reader == NULL) || (reader->node == NULL))
3424 	return(NULL);
3425     if (reader->curnode != NULL)
3426 	node = reader->curnode;
3427     else
3428 	node = reader->node;
3429     if (node->type == XML_NAMESPACE_DECL) {
3430 	xmlNsPtr ns = (xmlNsPtr) node;
3431 	if (ns->prefix == NULL)
3432 	    return(NULL);
3433 	return(CONSTSTR(BAD_CAST "xmlns"));
3434     }
3435     if ((node->type != XML_ELEMENT_NODE) &&
3436 	(node->type != XML_ATTRIBUTE_NODE))
3437 	return(NULL);
3438     if ((node->ns != NULL) && (node->ns->prefix != NULL))
3439 	return(CONSTSTR(node->ns->prefix));
3440     return(NULL);
3441 }
3442 
3443 /**
3444  * xmlTextReaderNamespaceUri:
3445  * @reader:  the xmlTextReaderPtr used
3446  *
3447  * The URI defining the namespace associated with the node.
3448  *
3449  * Returns the namespace URI or NULL if not available,
3450  *    if non NULL it need to be freed by the caller.
3451  */
3452 xmlChar *
xmlTextReaderNamespaceUri(xmlTextReaderPtr reader)3453 xmlTextReaderNamespaceUri(xmlTextReaderPtr reader) {
3454     xmlNodePtr node;
3455     if ((reader == NULL) || (reader->node == NULL))
3456 	return(NULL);
3457     if (reader->curnode != NULL)
3458 	node = reader->curnode;
3459     else
3460 	node = reader->node;
3461     if (node->type == XML_NAMESPACE_DECL)
3462 	return(xmlStrdup(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3463     if ((node->type != XML_ELEMENT_NODE) &&
3464 	(node->type != XML_ATTRIBUTE_NODE))
3465 	return(NULL);
3466     if (node->ns != NULL)
3467 	return(xmlStrdup(node->ns->href));
3468     return(NULL);
3469 }
3470 
3471 /**
3472  * xmlTextReaderConstNamespaceUri:
3473  * @reader:  the xmlTextReaderPtr used
3474  *
3475  * The URI defining the namespace associated with the node.
3476  *
3477  * Returns the namespace URI or NULL if not available, the string
3478  *         will be deallocated with the reader
3479  */
3480 const xmlChar *
xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader)3481 xmlTextReaderConstNamespaceUri(xmlTextReaderPtr reader) {
3482     xmlNodePtr node;
3483     if ((reader == NULL) || (reader->node == NULL))
3484 	return(NULL);
3485     if (reader->curnode != NULL)
3486 	node = reader->curnode;
3487     else
3488 	node = reader->node;
3489     if (node->type == XML_NAMESPACE_DECL)
3490 	return(CONSTSTR(BAD_CAST "http://www.w3.org/2000/xmlns/"));
3491     if ((node->type != XML_ELEMENT_NODE) &&
3492 	(node->type != XML_ATTRIBUTE_NODE))
3493 	return(NULL);
3494     if (node->ns != NULL)
3495 	return(CONSTSTR(node->ns->href));
3496     return(NULL);
3497 }
3498 
3499 /**
3500  * xmlTextReaderBaseUri:
3501  * @reader:  the xmlTextReaderPtr used
3502  *
3503  * The base URI of the node.
3504  *
3505  * Returns the base URI or NULL if not available,
3506  *    if non NULL it need to be freed by the caller.
3507  */
3508 xmlChar *
xmlTextReaderBaseUri(xmlTextReaderPtr reader)3509 xmlTextReaderBaseUri(xmlTextReaderPtr reader) {
3510     if ((reader == NULL) || (reader->node == NULL))
3511 	return(NULL);
3512     return(xmlNodeGetBase(NULL, reader->node));
3513 }
3514 
3515 /**
3516  * xmlTextReaderConstBaseUri:
3517  * @reader:  the xmlTextReaderPtr used
3518  *
3519  * The base URI of the node.
3520  *
3521  * Returns the base URI or NULL if not available, the string
3522  *         will be deallocated with the reader
3523  */
3524 const xmlChar *
xmlTextReaderConstBaseUri(xmlTextReaderPtr reader)3525 xmlTextReaderConstBaseUri(xmlTextReaderPtr reader) {
3526     xmlChar *tmp;
3527     const xmlChar *ret;
3528 
3529     if ((reader == NULL) || (reader->node == NULL))
3530 	return(NULL);
3531     tmp = xmlNodeGetBase(NULL, reader->node);
3532     if (tmp == NULL)
3533         return(NULL);
3534     ret = CONSTSTR(tmp);
3535     xmlFree(tmp);
3536     return(ret);
3537 }
3538 
3539 /**
3540  * xmlTextReaderDepth:
3541  * @reader:  the xmlTextReaderPtr used
3542  *
3543  * The depth of the node in the tree.
3544  *
3545  * Returns the depth or -1 in case of error
3546  */
3547 int
xmlTextReaderDepth(xmlTextReaderPtr reader)3548 xmlTextReaderDepth(xmlTextReaderPtr reader) {
3549     if (reader == NULL)
3550 	return(-1);
3551     if (reader->node == NULL)
3552 	return(0);
3553 
3554     if (reader->curnode != NULL) {
3555 	if ((reader->curnode->type == XML_ATTRIBUTE_NODE) ||
3556 	    (reader->curnode->type == XML_NAMESPACE_DECL))
3557 	    return(reader->depth + 1);
3558 	return(reader->depth + 2);
3559     }
3560     return(reader->depth);
3561 }
3562 
3563 /**
3564  * xmlTextReaderHasAttributes:
3565  * @reader:  the xmlTextReaderPtr used
3566  *
3567  * Whether the node has attributes.
3568  *
3569  * Returns 1 if true, 0 if false, and -1 in case or error
3570  */
3571 int
xmlTextReaderHasAttributes(xmlTextReaderPtr reader)3572 xmlTextReaderHasAttributes(xmlTextReaderPtr reader) {
3573     xmlNodePtr node;
3574     if (reader == NULL)
3575 	return(-1);
3576     if (reader->node == NULL)
3577 	return(0);
3578     if (reader->curnode != NULL)
3579 	node = reader->curnode;
3580     else
3581 	node = reader->node;
3582 
3583     if ((node->type == XML_ELEMENT_NODE) &&
3584 	((node->properties != NULL) || (node->nsDef != NULL)))
3585 	return(1);
3586     /* TODO: handle the xmlDecl */
3587     return(0);
3588 }
3589 
3590 /**
3591  * xmlTextReaderHasValue:
3592  * @reader:  the xmlTextReaderPtr used
3593  *
3594  * Whether the node can have a text value.
3595  *
3596  * Returns 1 if true, 0 if false, and -1 in case or error
3597  */
3598 int
xmlTextReaderHasValue(xmlTextReaderPtr reader)3599 xmlTextReaderHasValue(xmlTextReaderPtr reader) {
3600     xmlNodePtr node;
3601     if (reader == NULL)
3602 	return(-1);
3603     if (reader->node == NULL)
3604 	return(0);
3605     if (reader->curnode != NULL)
3606 	node = reader->curnode;
3607     else
3608 	node = reader->node;
3609 
3610     switch (node->type) {
3611         case XML_ATTRIBUTE_NODE:
3612         case XML_TEXT_NODE:
3613         case XML_CDATA_SECTION_NODE:
3614         case XML_PI_NODE:
3615         case XML_COMMENT_NODE:
3616         case XML_NAMESPACE_DECL:
3617 	    return(1);
3618 	default:
3619 	    break;
3620     }
3621     return(0);
3622 }
3623 
3624 /**
3625  * xmlTextReaderValue:
3626  * @reader:  the xmlTextReaderPtr used
3627  *
3628  * Provides the text value of the node if present
3629  *
3630  * Returns the string or NULL if not available. The result must be deallocated
3631  *     with xmlFree()
3632  */
3633 xmlChar *
xmlTextReaderValue(xmlTextReaderPtr reader)3634 xmlTextReaderValue(xmlTextReaderPtr reader) {
3635     xmlNodePtr node;
3636     if (reader == NULL)
3637 	return(NULL);
3638     if (reader->node == NULL)
3639 	return(NULL);
3640     if (reader->curnode != NULL)
3641 	node = reader->curnode;
3642     else
3643 	node = reader->node;
3644 
3645     switch (node->type) {
3646         case XML_NAMESPACE_DECL:
3647 	    return(xmlStrdup(((xmlNsPtr) node)->href));
3648         case XML_ATTRIBUTE_NODE:{
3649 	    xmlAttrPtr attr = (xmlAttrPtr) node;
3650 
3651 	    if (attr->parent != NULL)
3652 		return (xmlNodeListGetString
3653 			(attr->parent->doc, attr->children, 1));
3654 	    else
3655 		return (xmlNodeListGetString(NULL, attr->children, 1));
3656 	    break;
3657 	}
3658         case XML_TEXT_NODE:
3659         case XML_CDATA_SECTION_NODE:
3660         case XML_PI_NODE:
3661         case XML_COMMENT_NODE:
3662             if (node->content != NULL)
3663                 return (xmlStrdup(node->content));
3664 	default:
3665 	    break;
3666     }
3667     return(NULL);
3668 }
3669 
3670 /**
3671  * xmlTextReaderConstValue:
3672  * @reader:  the xmlTextReaderPtr used
3673  *
3674  * Provides the text value of the node if present
3675  *
3676  * Returns the string or NULL if not available. The result will be
3677  *     deallocated on the next Read() operation.
3678  */
3679 const xmlChar *
xmlTextReaderConstValue(xmlTextReaderPtr reader)3680 xmlTextReaderConstValue(xmlTextReaderPtr reader) {
3681     xmlNodePtr node;
3682     if (reader == NULL)
3683 	return(NULL);
3684     if (reader->node == NULL)
3685 	return(NULL);
3686     if (reader->curnode != NULL)
3687 	node = reader->curnode;
3688     else
3689 	node = reader->node;
3690 
3691     switch (node->type) {
3692         case XML_NAMESPACE_DECL:
3693 	    return(((xmlNsPtr) node)->href);
3694         case XML_ATTRIBUTE_NODE:{
3695 	    xmlAttrPtr attr = (xmlAttrPtr) node;
3696 	    const xmlChar *ret;
3697 
3698 	    if ((attr->children != NULL) &&
3699 	        (attr->children->type == XML_TEXT_NODE) &&
3700 		(attr->children->next == NULL))
3701 		return(attr->children->content);
3702 	    else {
3703 		if (reader->buffer == NULL) {
3704 		    reader->buffer = xmlBufCreateSize(100);
3705                     if (reader->buffer == NULL) {
3706                         xmlGenericError(xmlGenericErrorContext,
3707                                         "xmlTextReaderSetup : malloc failed\n");
3708                         return (NULL);
3709                     }
3710 		    xmlBufSetAllocationScheme(reader->buffer,
3711 		                              XML_BUFFER_ALLOC_BOUNDED);
3712                 } else
3713                     xmlBufEmpty(reader->buffer);
3714 	        xmlBufGetNodeContent(reader->buffer, node);
3715 		ret = xmlBufContent(reader->buffer);
3716 		if (ret == NULL) {
3717 		    /* error on the buffer best to reallocate */
3718 		    xmlBufFree(reader->buffer);
3719 		    reader->buffer = xmlBufCreateSize(100);
3720 		    xmlBufSetAllocationScheme(reader->buffer,
3721 		                              XML_BUFFER_ALLOC_BOUNDED);
3722 		    ret = BAD_CAST "";
3723 		}
3724 		return(ret);
3725 	    }
3726 	    break;
3727 	}
3728         case XML_TEXT_NODE:
3729         case XML_CDATA_SECTION_NODE:
3730         case XML_PI_NODE:
3731         case XML_COMMENT_NODE:
3732 	    return(node->content);
3733 	default:
3734 	    break;
3735     }
3736     return(NULL);
3737 }
3738 
3739 /**
3740  * xmlTextReaderIsDefault:
3741  * @reader:  the xmlTextReaderPtr used
3742  *
3743  * Whether an Attribute  node was generated from the default value
3744  * defined in the DTD or schema.
3745  *
3746  * Returns 0 if not defaulted, 1 if defaulted, and -1 in case of error
3747  */
3748 int
xmlTextReaderIsDefault(xmlTextReaderPtr reader)3749 xmlTextReaderIsDefault(xmlTextReaderPtr reader) {
3750     if (reader == NULL)
3751 	return(-1);
3752     return(0);
3753 }
3754 
3755 /**
3756  * xmlTextReaderQuoteChar:
3757  * @reader:  the xmlTextReaderPtr used
3758  *
3759  * The quotation mark character used to enclose the value of an attribute.
3760  *
3761  * Returns " or ' and -1 in case of error
3762  */
3763 int
xmlTextReaderQuoteChar(xmlTextReaderPtr reader)3764 xmlTextReaderQuoteChar(xmlTextReaderPtr reader) {
3765     if (reader == NULL)
3766 	return(-1);
3767     /* TODO maybe lookup the attribute value for " first */
3768     return((int) '"');
3769 }
3770 
3771 /**
3772  * xmlTextReaderXmlLang:
3773  * @reader:  the xmlTextReaderPtr used
3774  *
3775  * The xml:lang scope within which the node resides.
3776  *
3777  * Returns the xml:lang value or NULL if none exists.,
3778  *    if non NULL it need to be freed by the caller.
3779  */
3780 xmlChar *
xmlTextReaderXmlLang(xmlTextReaderPtr reader)3781 xmlTextReaderXmlLang(xmlTextReaderPtr reader) {
3782     if (reader == NULL)
3783 	return(NULL);
3784     if (reader->node == NULL)
3785 	return(NULL);
3786     return(xmlNodeGetLang(reader->node));
3787 }
3788 
3789 /**
3790  * xmlTextReaderConstXmlLang:
3791  * @reader:  the xmlTextReaderPtr used
3792  *
3793  * The xml:lang scope within which the node resides.
3794  *
3795  * Returns the xml:lang value or NULL if none exists.
3796  */
3797 const xmlChar *
xmlTextReaderConstXmlLang(xmlTextReaderPtr reader)3798 xmlTextReaderConstXmlLang(xmlTextReaderPtr reader) {
3799     xmlChar *tmp;
3800     const xmlChar *ret;
3801 
3802     if (reader == NULL)
3803 	return(NULL);
3804     if (reader->node == NULL)
3805 	return(NULL);
3806     tmp = xmlNodeGetLang(reader->node);
3807     if (tmp == NULL)
3808         return(NULL);
3809     ret = CONSTSTR(tmp);
3810     xmlFree(tmp);
3811     return(ret);
3812 }
3813 
3814 /**
3815  * xmlTextReaderConstString:
3816  * @reader:  the xmlTextReaderPtr used
3817  * @str:  the string to intern.
3818  *
3819  * Get an interned string from the reader, allows for example to
3820  * speedup string name comparisons
3821  *
3822  * Returns an interned copy of the string or NULL in case of error. The
3823  *         string will be deallocated with the reader.
3824  */
3825 const xmlChar *
xmlTextReaderConstString(xmlTextReaderPtr reader,const xmlChar * str)3826 xmlTextReaderConstString(xmlTextReaderPtr reader, const xmlChar *str) {
3827     if (reader == NULL)
3828 	return(NULL);
3829     return(CONSTSTR(str));
3830 }
3831 
3832 /**
3833  * xmlTextReaderNormalization:
3834  * @reader:  the xmlTextReaderPtr used
3835  *
3836  * The value indicating whether to normalize white space and attribute values.
3837  * Since attribute value and end of line normalizations are a MUST in the XML
3838  * specification only the value true is accepted. The broken behaviour of
3839  * accepting out of range character entities like &#0; is of course not
3840  * supported either.
3841  *
3842  * Returns 1 or -1 in case of error.
3843  */
3844 int
xmlTextReaderNormalization(xmlTextReaderPtr reader)3845 xmlTextReaderNormalization(xmlTextReaderPtr reader) {
3846     if (reader == NULL)
3847 	return(-1);
3848     return(1);
3849 }
3850 
3851 /************************************************************************
3852  *									*
3853  *			Extensions to the base APIs			*
3854  *									*
3855  ************************************************************************/
3856 
3857 /**
3858  * xmlTextReaderSetParserProp:
3859  * @reader:  the xmlTextReaderPtr used
3860  * @prop:  the xmlParserProperties to set
3861  * @value:  usually 0 or 1 to (de)activate it
3862  *
3863  * Change the parser processing behaviour by changing some of its internal
3864  * properties. Note that some properties can only be changed before any
3865  * read has been done.
3866  *
3867  * Returns 0 if the call was successful, or -1 in case of error
3868  */
3869 int
xmlTextReaderSetParserProp(xmlTextReaderPtr reader,int prop,int value)3870 xmlTextReaderSetParserProp(xmlTextReaderPtr reader, int prop, int value) {
3871     xmlParserProperties p = (xmlParserProperties) prop;
3872     xmlParserCtxtPtr ctxt;
3873 
3874     if ((reader == NULL) || (reader->ctxt == NULL))
3875 	return(-1);
3876     ctxt = reader->ctxt;
3877 
3878     switch (p) {
3879         case XML_PARSER_LOADDTD:
3880 	    if (value != 0) {
3881 		if (ctxt->loadsubset == 0) {
3882 		    if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
3883 			return(-1);
3884 		    ctxt->loadsubset = XML_DETECT_IDS;
3885 		}
3886 	    } else {
3887 		ctxt->loadsubset = 0;
3888 	    }
3889 	    return(0);
3890         case XML_PARSER_DEFAULTATTRS:
3891 	    if (value != 0) {
3892 		ctxt->loadsubset |= XML_COMPLETE_ATTRS;
3893 	    } else {
3894 		if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3895 		    ctxt->loadsubset -= XML_COMPLETE_ATTRS;
3896 	    }
3897 	    return(0);
3898         case XML_PARSER_VALIDATE:
3899 	    if (value != 0) {
3900                 ctxt->options |= XML_PARSE_DTDVALID;
3901 		ctxt->validate = 1;
3902 		reader->validate = XML_TEXTREADER_VALIDATE_DTD;
3903 	    } else {
3904                 ctxt->options &= ~XML_PARSE_DTDVALID;
3905 		ctxt->validate = 0;
3906 	    }
3907 	    return(0);
3908         case XML_PARSER_SUBST_ENTITIES:
3909 	    if (value != 0) {
3910                 ctxt->options |= XML_PARSE_NOENT;
3911 		ctxt->replaceEntities = 1;
3912 	    } else {
3913                 ctxt->options &= ~XML_PARSE_NOENT;
3914 		ctxt->replaceEntities = 0;
3915 	    }
3916 	    return(0);
3917     }
3918     return(-1);
3919 }
3920 
3921 /**
3922  * xmlTextReaderGetParserProp:
3923  * @reader:  the xmlTextReaderPtr used
3924  * @prop:  the xmlParserProperties to get
3925  *
3926  * Read the parser internal property.
3927  *
3928  * Returns the value, usually 0 or 1, or -1 in case of error.
3929  */
3930 int
xmlTextReaderGetParserProp(xmlTextReaderPtr reader,int prop)3931 xmlTextReaderGetParserProp(xmlTextReaderPtr reader, int prop) {
3932     xmlParserProperties p = (xmlParserProperties) prop;
3933     xmlParserCtxtPtr ctxt;
3934 
3935     if ((reader == NULL) || (reader->ctxt == NULL))
3936 	return(-1);
3937     ctxt = reader->ctxt;
3938 
3939     switch (p) {
3940         case XML_PARSER_LOADDTD:
3941 	    if ((ctxt->loadsubset != 0) || (ctxt->validate != 0))
3942 		return(1);
3943 	    return(0);
3944         case XML_PARSER_DEFAULTATTRS:
3945 	    if (ctxt->loadsubset & XML_COMPLETE_ATTRS)
3946 		return(1);
3947 	    return(0);
3948         case XML_PARSER_VALIDATE:
3949 	    return(reader->validate);
3950 	case XML_PARSER_SUBST_ENTITIES:
3951 	    return(ctxt->replaceEntities);
3952     }
3953     return(-1);
3954 }
3955 
3956 
3957 /**
3958  * xmlTextReaderGetParserLineNumber:
3959  * @reader: the user data (XML reader context)
3960  *
3961  * Provide the line number of the current parsing point.
3962  *
3963  * Returns an int or 0 if not available
3964  */
3965 int
xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)3966 xmlTextReaderGetParserLineNumber(xmlTextReaderPtr reader)
3967 {
3968     if ((reader == NULL) || (reader->ctxt == NULL) ||
3969         (reader->ctxt->input == NULL)) {
3970         return (0);
3971     }
3972     return (reader->ctxt->input->line);
3973 }
3974 
3975 /**
3976  * xmlTextReaderGetParserColumnNumber:
3977  * @reader: the user data (XML reader context)
3978  *
3979  * Provide the column number of the current parsing point.
3980  *
3981  * Returns an int or 0 if not available
3982  */
3983 int
xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)3984 xmlTextReaderGetParserColumnNumber(xmlTextReaderPtr reader)
3985 {
3986     if ((reader == NULL) || (reader->ctxt == NULL) ||
3987         (reader->ctxt->input == NULL)) {
3988         return (0);
3989     }
3990     return (reader->ctxt->input->col);
3991 }
3992 
3993 /**
3994  * xmlTextReaderCurrentNode:
3995  * @reader:  the xmlTextReaderPtr used
3996  *
3997  * Hacking interface allowing to get the xmlNodePtr corresponding to the
3998  * current node being accessed by the xmlTextReader. This is dangerous
3999  * because the underlying node may be destroyed on the next Reads.
4000  *
4001  * Returns the xmlNodePtr or NULL in case of error.
4002  */
4003 xmlNodePtr
xmlTextReaderCurrentNode(xmlTextReaderPtr reader)4004 xmlTextReaderCurrentNode(xmlTextReaderPtr reader) {
4005     if (reader == NULL)
4006 	return(NULL);
4007 
4008     if (reader->curnode != NULL)
4009 	return(reader->curnode);
4010     return(reader->node);
4011 }
4012 
4013 /**
4014  * xmlTextReaderPreserve:
4015  * @reader:  the xmlTextReaderPtr used
4016  *
4017  * This tells the XML Reader to preserve the current node.
4018  * The caller must also use xmlTextReaderCurrentDoc() to
4019  * keep an handle on the resulting document once parsing has finished
4020  *
4021  * Returns the xmlNodePtr or NULL in case of error.
4022  */
4023 xmlNodePtr
xmlTextReaderPreserve(xmlTextReaderPtr reader)4024 xmlTextReaderPreserve(xmlTextReaderPtr reader) {
4025     xmlNodePtr cur, parent;
4026 
4027     if (reader == NULL)
4028 	return(NULL);
4029 
4030     if (reader->curnode != NULL)
4031         cur = reader->curnode;
4032     else
4033         cur = reader->node;
4034     if (cur == NULL)
4035         return(NULL);
4036 
4037     if ((cur->type != XML_DOCUMENT_NODE) && (cur->type != XML_DTD_NODE)) {
4038 	cur->extra |= NODE_IS_PRESERVED;
4039 	cur->extra |= NODE_IS_SPRESERVED;
4040     }
4041     reader->preserves++;
4042 
4043     parent = cur->parent;;
4044     while (parent != NULL) {
4045         if (parent->type == XML_ELEMENT_NODE)
4046 	    parent->extra |= NODE_IS_PRESERVED;
4047 	parent = parent->parent;
4048     }
4049     return(cur);
4050 }
4051 
4052 #ifdef LIBXML_PATTERN_ENABLED
4053 /**
4054  * xmlTextReaderPreservePattern:
4055  * @reader:  the xmlTextReaderPtr used
4056  * @pattern:  an XPath subset pattern
4057  * @namespaces: the prefix definitions, array of [URI, prefix] or NULL
4058  *
4059  * This tells the XML Reader to preserve all nodes matched by the
4060  * pattern. The caller must also use xmlTextReaderCurrentDoc() to
4061  * keep an handle on the resulting document once parsing has finished
4062  *
4063  * Returns a non-negative number in case of success and -1 in case of error
4064  */
4065 int
xmlTextReaderPreservePattern(xmlTextReaderPtr reader,const xmlChar * pattern,const xmlChar ** namespaces)4066 xmlTextReaderPreservePattern(xmlTextReaderPtr reader, const xmlChar *pattern,
4067                              const xmlChar **namespaces)
4068 {
4069     xmlPatternPtr comp;
4070 
4071     if ((reader == NULL) || (pattern == NULL))
4072 	return(-1);
4073 
4074     comp = xmlPatterncompile(pattern, reader->dict, 0, namespaces);
4075     if (comp == NULL)
4076         return(-1);
4077 
4078     if (reader->patternMax <= 0) {
4079 	reader->patternMax = 4;
4080 	reader->patternTab = (xmlPatternPtr *) xmlMalloc(reader->patternMax *
4081 					      sizeof(reader->patternTab[0]));
4082         if (reader->patternTab == NULL) {
4083             xmlGenericError(xmlGenericErrorContext, "xmlMalloc failed !\n");
4084             return (-1);
4085         }
4086     }
4087     if (reader->patternNr >= reader->patternMax) {
4088         xmlPatternPtr *tmp;
4089         reader->patternMax *= 2;
4090 	tmp = (xmlPatternPtr *) xmlRealloc(reader->patternTab,
4091                                       reader->patternMax *
4092                                       sizeof(reader->patternTab[0]));
4093         if (tmp == NULL) {
4094             xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
4095 	    reader->patternMax /= 2;
4096             return (-1);
4097         }
4098 	reader->patternTab = tmp;
4099     }
4100     reader->patternTab[reader->patternNr] = comp;
4101     return(reader->patternNr++);
4102 }
4103 #endif
4104 
4105 /**
4106  * xmlTextReaderCurrentDoc:
4107  * @reader:  the xmlTextReaderPtr used
4108  *
4109  * Hacking interface allowing to get the xmlDocPtr corresponding to the
4110  * current document being accessed by the xmlTextReader.
4111  * NOTE: as a result of this call, the reader will not destroy the
4112  *       associated XML document and calling xmlFreeDoc() on the result
4113  *       is needed once the reader parsing has finished.
4114  *
4115  * Returns the xmlDocPtr or NULL in case of error.
4116  */
4117 xmlDocPtr
xmlTextReaderCurrentDoc(xmlTextReaderPtr reader)4118 xmlTextReaderCurrentDoc(xmlTextReaderPtr reader) {
4119     if (reader == NULL)
4120 	return(NULL);
4121     if (reader->doc != NULL)
4122         return(reader->doc);
4123     if ((reader->ctxt == NULL) || (reader->ctxt->myDoc == NULL))
4124 	return(NULL);
4125 
4126     reader->preserve = 1;
4127     return(reader->ctxt->myDoc);
4128 }
4129 
4130 #ifdef LIBXML_SCHEMAS_ENABLED
4131 static char *xmlTextReaderBuildMessage(const char *msg, va_list ap) LIBXML_ATTR_FORMAT(1,0);
4132 
4133 static void XMLCDECL
4134 xmlTextReaderValidityError(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
4135 
4136 static void XMLCDECL
4137 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
4138 
4139 static void XMLCDECL
4140 xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
4141 
4142 static void XMLCDECL
4143 xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...) LIBXML_ATTR_FORMAT(2,3);
4144 
4145 static void XMLCDECL
xmlTextReaderValidityErrorRelay(void * ctx,const char * msg,...)4146 xmlTextReaderValidityErrorRelay(void *ctx, const char *msg, ...)
4147 {
4148     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4149 
4150     char *str;
4151 
4152     va_list ap;
4153 
4154     va_start(ap, msg);
4155     str = xmlTextReaderBuildMessage(msg, ap);
4156     if (!reader->errorFunc) {
4157         xmlTextReaderValidityError(ctx, "%s", str);
4158     } else {
4159         reader->errorFunc(reader->errorFuncArg, str,
4160                           XML_PARSER_SEVERITY_VALIDITY_ERROR,
4161                           NULL /* locator */ );
4162     }
4163     if (str != NULL)
4164         xmlFree(str);
4165     va_end(ap);
4166 }
4167 
4168 static void XMLCDECL
xmlTextReaderValidityWarningRelay(void * ctx,const char * msg,...)4169 xmlTextReaderValidityWarningRelay(void *ctx, const char *msg, ...)
4170 {
4171     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx;
4172 
4173     char *str;
4174 
4175     va_list ap;
4176 
4177     va_start(ap, msg);
4178     str = xmlTextReaderBuildMessage(msg, ap);
4179     if (!reader->errorFunc) {
4180         xmlTextReaderValidityWarning(ctx, "%s", str);
4181     } else {
4182         reader->errorFunc(reader->errorFuncArg, str,
4183                           XML_PARSER_SEVERITY_VALIDITY_WARNING,
4184                           NULL /* locator */ );
4185     }
4186     if (str != NULL)
4187         xmlFree(str);
4188     va_end(ap);
4189 }
4190 
4191 static void
4192   xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error);
4193 
4194 static void
xmlTextReaderValidityStructuredRelay(void * userData,xmlErrorPtr error)4195 xmlTextReaderValidityStructuredRelay(void *userData, xmlErrorPtr error)
4196 {
4197     xmlTextReaderPtr reader = (xmlTextReaderPtr) userData;
4198 
4199     if (reader->sErrorFunc) {
4200         reader->sErrorFunc(reader->errorFuncArg, error);
4201     } else {
4202         xmlTextReaderStructuredError(reader, error);
4203     }
4204 }
4205 /**
4206  * xmlTextReaderRelaxNGSetSchema:
4207  * @reader:  the xmlTextReaderPtr used
4208  * @schema:  a precompiled RelaxNG schema
4209  *
4210  * Use RelaxNG to validate the document as it is processed.
4211  * Activation is only possible before the first Read().
4212  * if @schema is NULL, then RelaxNG validation is deactivated.
4213  @ The @schema should not be freed until the reader is deallocated
4214  * or its use has been deactivated.
4215  *
4216  * Returns 0 in case the RelaxNG validation could be (de)activated and
4217  *         -1 in case of error.
4218  */
4219 int
xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader,xmlRelaxNGPtr schema)4220 xmlTextReaderRelaxNGSetSchema(xmlTextReaderPtr reader, xmlRelaxNGPtr schema) {
4221     if (reader == NULL)
4222         return(-1);
4223     if (schema == NULL) {
4224         if (reader->rngSchemas != NULL) {
4225 	    xmlRelaxNGFree(reader->rngSchemas);
4226 	    reader->rngSchemas = NULL;
4227 	}
4228         if (reader->rngValidCtxt != NULL) {
4229 	    if (! reader->rngPreserveCtxt)
4230 		xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4231 	    reader->rngValidCtxt = NULL;
4232         }
4233 	reader->rngPreserveCtxt = 0;
4234 	return(0);
4235     }
4236     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4237 	return(-1);
4238     if (reader->rngSchemas != NULL) {
4239 	xmlRelaxNGFree(reader->rngSchemas);
4240 	reader->rngSchemas = NULL;
4241     }
4242     if (reader->rngValidCtxt != NULL) {
4243 	if (! reader->rngPreserveCtxt)
4244 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4245 	reader->rngValidCtxt = NULL;
4246     }
4247     reader->rngPreserveCtxt = 0;
4248     reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(schema);
4249     if (reader->rngValidCtxt == NULL)
4250         return(-1);
4251     if (reader->errorFunc != NULL) {
4252 	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4253 			xmlTextReaderValidityErrorRelay,
4254 			xmlTextReaderValidityWarningRelay,
4255 			reader);
4256     }
4257 	if (reader->sErrorFunc != NULL) {
4258 		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4259 			xmlTextReaderValidityStructuredRelay,
4260 			reader);
4261     }
4262     reader->rngValidErrors = 0;
4263     reader->rngFullNode = NULL;
4264     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4265     return(0);
4266 }
4267 
4268 /**
4269  * xmlTextReaderLocator:
4270  * @ctx: the xmlTextReaderPtr used
4271  * @file: returned file information
4272  * @line: returned line information
4273  *
4274  * Internal locator function for the readers
4275  *
4276  * Returns 0 in case the Schema validation could be (de)activated and
4277  *         -1 in case of error.
4278  */
4279 static int
xmlTextReaderLocator(void * ctx,const char ** file,unsigned long * line)4280 xmlTextReaderLocator(void *ctx, const char **file, unsigned long *line) {
4281     xmlTextReaderPtr reader;
4282 
4283     if ((ctx == NULL) || ((file == NULL) && (line == NULL)))
4284         return(-1);
4285 
4286     if (file != NULL)
4287         *file = NULL;
4288     if (line != NULL)
4289         *line = 0;
4290 
4291     reader = (xmlTextReaderPtr) ctx;
4292     if ((reader->ctxt != NULL) && (reader->ctxt->input != NULL)) {
4293 	if (file != NULL)
4294 	    *file = reader->ctxt->input->filename;
4295 	if (line != NULL)
4296 	    *line = reader->ctxt->input->line;
4297 	return(0);
4298     }
4299     if (reader->node != NULL) {
4300         long res;
4301 	int ret = 0;
4302 
4303 	if (line != NULL) {
4304 	    res = xmlGetLineNo(reader->node);
4305 	    if (res > 0)
4306 	        *line = (unsigned long) res;
4307 	    else
4308                 ret = -1;
4309 	}
4310         if (file != NULL) {
4311 	    xmlDocPtr doc = reader->node->doc;
4312 	    if ((doc != NULL) && (doc->URL != NULL))
4313 	        *file = (const char *) doc->URL;
4314 	    else
4315                 ret = -1;
4316 	}
4317 	return(ret);
4318     }
4319     return(-1);
4320 }
4321 
4322 /**
4323  * xmlTextReaderSetSchema:
4324  * @reader:  the xmlTextReaderPtr used
4325  * @schema:  a precompiled Schema schema
4326  *
4327  * Use XSD Schema to validate the document as it is processed.
4328  * Activation is only possible before the first Read().
4329  * if @schema is NULL, then Schema validation is deactivated.
4330  * The @schema should not be freed until the reader is deallocated
4331  * or its use has been deactivated.
4332  *
4333  * Returns 0 in case the Schema validation could be (de)activated and
4334  *         -1 in case of error.
4335  */
4336 int
xmlTextReaderSetSchema(xmlTextReaderPtr reader,xmlSchemaPtr schema)4337 xmlTextReaderSetSchema(xmlTextReaderPtr reader, xmlSchemaPtr schema) {
4338     if (reader == NULL)
4339         return(-1);
4340     if (schema == NULL) {
4341 	if (reader->xsdPlug != NULL) {
4342 	    xmlSchemaSAXUnplug(reader->xsdPlug);
4343 	    reader->xsdPlug = NULL;
4344 	}
4345         if (reader->xsdValidCtxt != NULL) {
4346 	    if (! reader->xsdPreserveCtxt)
4347 		xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4348 	    reader->xsdValidCtxt = NULL;
4349         }
4350 	reader->xsdPreserveCtxt = 0;
4351         if (reader->xsdSchemas != NULL) {
4352 	    xmlSchemaFree(reader->xsdSchemas);
4353 	    reader->xsdSchemas = NULL;
4354 	}
4355 	return(0);
4356     }
4357     if (reader->mode != XML_TEXTREADER_MODE_INITIAL)
4358 	return(-1);
4359     if (reader->xsdPlug != NULL) {
4360 	xmlSchemaSAXUnplug(reader->xsdPlug);
4361 	reader->xsdPlug = NULL;
4362     }
4363     if (reader->xsdValidCtxt != NULL) {
4364 	if (! reader->xsdPreserveCtxt)
4365 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4366 	reader->xsdValidCtxt = NULL;
4367     }
4368     reader->xsdPreserveCtxt = 0;
4369     if (reader->xsdSchemas != NULL) {
4370 	xmlSchemaFree(reader->xsdSchemas);
4371 	reader->xsdSchemas = NULL;
4372     }
4373     reader->xsdValidCtxt = xmlSchemaNewValidCtxt(schema);
4374     if (reader->xsdValidCtxt == NULL) {
4375 	xmlSchemaFree(reader->xsdSchemas);
4376 	reader->xsdSchemas = NULL;
4377         return(-1);
4378     }
4379     reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4380                                        &(reader->ctxt->sax),
4381 				       &(reader->ctxt->userData));
4382     if (reader->xsdPlug == NULL) {
4383 	xmlSchemaFree(reader->xsdSchemas);
4384 	reader->xsdSchemas = NULL;
4385 	xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4386 	reader->xsdValidCtxt = NULL;
4387 	return(-1);
4388     }
4389     xmlSchemaValidateSetLocator(reader->xsdValidCtxt,
4390                                 xmlTextReaderLocator,
4391 				(void *) reader);
4392 
4393     if (reader->errorFunc != NULL) {
4394 	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4395 			xmlTextReaderValidityErrorRelay,
4396 			xmlTextReaderValidityWarningRelay,
4397 			reader);
4398     }
4399 	if (reader->sErrorFunc != NULL) {
4400 		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4401 			xmlTextReaderValidityStructuredRelay,
4402 			reader);
4403     }
4404     reader->xsdValidErrors = 0;
4405     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4406     return(0);
4407 }
4408 
4409 /**
4410  * xmlTextReaderRelaxNGValidateInternal:
4411  * @reader:  the xmlTextReaderPtr used
4412  * @rng:  the path to a RelaxNG schema or NULL
4413  * @ctxt: the RelaxNG schema validation context or NULL
4414  * @options: options (not yet used)
4415  *
4416  * Use RelaxNG to validate the document as it is processed.
4417  * Activation is only possible before the first Read().
4418  * If both @rng and @ctxt are NULL, then RelaxNG validation is deactivated.
4419  *
4420  * Returns 0 in case the RelaxNG validation could be (de)activated and
4421  *	   -1 in case of error.
4422  */
4423 static int
xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader,const char * rng,xmlRelaxNGValidCtxtPtr ctxt,int options ATTRIBUTE_UNUSED)4424 xmlTextReaderRelaxNGValidateInternal(xmlTextReaderPtr reader,
4425 				     const char *rng,
4426 				     xmlRelaxNGValidCtxtPtr ctxt,
4427 				     int options ATTRIBUTE_UNUSED)
4428 {
4429     if (reader == NULL)
4430 	return(-1);
4431 
4432     if ((rng != NULL) && (ctxt != NULL))
4433 	return (-1);
4434 
4435     if (((rng != NULL) || (ctxt != NULL)) &&
4436 	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
4437 	 (reader->ctxt == NULL)))
4438 	return(-1);
4439 
4440     /* Cleanup previous validation stuff. */
4441     if (reader->rngValidCtxt != NULL) {
4442 	if ( !reader->rngPreserveCtxt)
4443 	    xmlRelaxNGFreeValidCtxt(reader->rngValidCtxt);
4444 	reader->rngValidCtxt = NULL;
4445     }
4446     reader->rngPreserveCtxt = 0;
4447     if (reader->rngSchemas != NULL) {
4448 	xmlRelaxNGFree(reader->rngSchemas);
4449 	reader->rngSchemas = NULL;
4450     }
4451 
4452     if ((rng == NULL) && (ctxt == NULL)) {
4453 	/* We just want to deactivate the validation, so get out. */
4454 	return(0);
4455     }
4456 
4457 
4458     if (rng != NULL) {
4459 	xmlRelaxNGParserCtxtPtr pctxt;
4460 	/* Parse the schema and create validation environment. */
4461 
4462 	pctxt = xmlRelaxNGNewParserCtxt(rng);
4463 	if (reader->errorFunc != NULL) {
4464 	    xmlRelaxNGSetParserErrors(pctxt,
4465 		xmlTextReaderValidityErrorRelay,
4466 		xmlTextReaderValidityWarningRelay,
4467 		reader);
4468 	}
4469 	if (reader->sErrorFunc != NULL) {
4470 	    xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4471 		xmlTextReaderValidityStructuredRelay,
4472 		reader);
4473 	}
4474 	reader->rngSchemas = xmlRelaxNGParse(pctxt);
4475 	xmlRelaxNGFreeParserCtxt(pctxt);
4476 	if (reader->rngSchemas == NULL)
4477 	    return(-1);
4478 	reader->rngValidCtxt = xmlRelaxNGNewValidCtxt(reader->rngSchemas);
4479 	if (reader->rngValidCtxt == NULL) {
4480 	    xmlRelaxNGFree(reader->rngSchemas);
4481 	    reader->rngSchemas = NULL;
4482 	    return(-1);
4483 	}
4484     } else {
4485 	/* Use the given validation context. */
4486 	reader->rngValidCtxt = ctxt;
4487 	reader->rngPreserveCtxt = 1;
4488     }
4489     /*
4490     * Redirect the validation context's error channels to use
4491     * the reader channels.
4492     * TODO: In case the user provides the validation context we
4493     *	could make this redirection optional.
4494     */
4495     if (reader->errorFunc != NULL) {
4496 	xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
4497 			 xmlTextReaderValidityErrorRelay,
4498 			 xmlTextReaderValidityWarningRelay,
4499 			 reader);
4500     }
4501 	if (reader->sErrorFunc != NULL) {
4502 		xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
4503 			xmlTextReaderValidityStructuredRelay,
4504 			reader);
4505     }
4506     reader->rngValidErrors = 0;
4507     reader->rngFullNode = NULL;
4508     reader->validate = XML_TEXTREADER_VALIDATE_RNG;
4509     return(0);
4510 }
4511 
4512 /**
4513  * xmlTextReaderSchemaValidateInternal:
4514  * @reader:  the xmlTextReaderPtr used
4515  * @xsd:  the path to a W3C XSD schema or NULL
4516  * @ctxt: the XML Schema validation context or NULL
4517  * @options: options (not used yet)
4518  *
4519  * Validate the document as it is processed using XML Schema.
4520  * Activation is only possible before the first Read().
4521  * If both @xsd and @ctxt are NULL then XML Schema validation is deactivated.
4522  *
4523  * Returns 0 in case the schemas validation could be (de)activated and
4524  *         -1 in case of error.
4525  */
4526 static int
xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,const char * xsd,xmlSchemaValidCtxtPtr ctxt,int options ATTRIBUTE_UNUSED)4527 xmlTextReaderSchemaValidateInternal(xmlTextReaderPtr reader,
4528 				    const char *xsd,
4529 				    xmlSchemaValidCtxtPtr ctxt,
4530 				    int options ATTRIBUTE_UNUSED)
4531 {
4532     if (reader == NULL)
4533         return(-1);
4534 
4535     if ((xsd != NULL) && (ctxt != NULL))
4536 	return(-1);
4537 
4538     if (((xsd != NULL) || (ctxt != NULL)) &&
4539 	((reader->mode != XML_TEXTREADER_MODE_INITIAL) ||
4540         (reader->ctxt == NULL)))
4541 	return(-1);
4542 
4543     /* Cleanup previous validation stuff. */
4544     if (reader->xsdPlug != NULL) {
4545 	xmlSchemaSAXUnplug(reader->xsdPlug);
4546 	reader->xsdPlug = NULL;
4547     }
4548     if (reader->xsdValidCtxt != NULL) {
4549 	if (! reader->xsdPreserveCtxt)
4550 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4551 	reader->xsdValidCtxt = NULL;
4552     }
4553     reader->xsdPreserveCtxt = 0;
4554     if (reader->xsdSchemas != NULL) {
4555 	xmlSchemaFree(reader->xsdSchemas);
4556 	reader->xsdSchemas = NULL;
4557     }
4558 
4559     if ((xsd == NULL) && (ctxt == NULL)) {
4560 	/* We just want to deactivate the validation, so get out. */
4561 	return(0);
4562     }
4563 
4564     if (xsd != NULL) {
4565 	xmlSchemaParserCtxtPtr pctxt;
4566 	/* Parse the schema and create validation environment. */
4567 	pctxt = xmlSchemaNewParserCtxt(xsd);
4568 	if (reader->errorFunc != NULL) {
4569 	    xmlSchemaSetParserErrors(pctxt,
4570 		xmlTextReaderValidityErrorRelay,
4571 		xmlTextReaderValidityWarningRelay,
4572 		reader);
4573 	}
4574 	reader->xsdSchemas = xmlSchemaParse(pctxt);
4575 	xmlSchemaFreeParserCtxt(pctxt);
4576 	if (reader->xsdSchemas == NULL)
4577 	    return(-1);
4578 	reader->xsdValidCtxt = xmlSchemaNewValidCtxt(reader->xsdSchemas);
4579 	if (reader->xsdValidCtxt == NULL) {
4580 	    xmlSchemaFree(reader->xsdSchemas);
4581 	    reader->xsdSchemas = NULL;
4582 	    return(-1);
4583 	}
4584 	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4585 	    &(reader->ctxt->sax),
4586 	    &(reader->ctxt->userData));
4587 	if (reader->xsdPlug == NULL) {
4588 	    xmlSchemaFree(reader->xsdSchemas);
4589 	    reader->xsdSchemas = NULL;
4590 	    xmlSchemaFreeValidCtxt(reader->xsdValidCtxt);
4591 	    reader->xsdValidCtxt = NULL;
4592 	    return(-1);
4593 	}
4594     } else {
4595 	/* Use the given validation context. */
4596 	reader->xsdValidCtxt = ctxt;
4597 	reader->xsdPreserveCtxt = 1;
4598 	reader->xsdPlug = xmlSchemaSAXPlug(reader->xsdValidCtxt,
4599 	    &(reader->ctxt->sax),
4600 	    &(reader->ctxt->userData));
4601 	if (reader->xsdPlug == NULL) {
4602 	    reader->xsdValidCtxt = NULL;
4603 	    reader->xsdPreserveCtxt = 0;
4604 	    return(-1);
4605 	}
4606     }
4607     xmlSchemaValidateSetLocator(reader->xsdValidCtxt,
4608                                 xmlTextReaderLocator,
4609 				(void *) reader);
4610     /*
4611     * Redirect the validation context's error channels to use
4612     * the reader channels.
4613     * TODO: In case the user provides the validation context we
4614     *   could make this redirection optional.
4615     */
4616     if (reader->errorFunc != NULL) {
4617 	xmlSchemaSetValidErrors(reader->xsdValidCtxt,
4618 			 xmlTextReaderValidityErrorRelay,
4619 			 xmlTextReaderValidityWarningRelay,
4620 			 reader);
4621     }
4622 	if (reader->sErrorFunc != NULL) {
4623 		xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
4624 			xmlTextReaderValidityStructuredRelay,
4625 			reader);
4626     }
4627     reader->xsdValidErrors = 0;
4628     reader->validate = XML_TEXTREADER_VALIDATE_XSD;
4629     return(0);
4630 }
4631 
4632 /**
4633  * xmlTextReaderSchemaValidateCtxt:
4634  * @reader:  the xmlTextReaderPtr used
4635  * @ctxt: the XML Schema validation context or NULL
4636  * @options: options (not used yet)
4637  *
4638  * Use W3C XSD schema context to validate the document as it is processed.
4639  * Activation is only possible before the first Read().
4640  * If @ctxt is NULL, then XML Schema validation is deactivated.
4641  *
4642  * Returns 0 in case the schemas validation could be (de)activated and
4643  *         -1 in case of error.
4644  */
4645 int
xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,xmlSchemaValidCtxtPtr ctxt,int options)4646 xmlTextReaderSchemaValidateCtxt(xmlTextReaderPtr reader,
4647 				    xmlSchemaValidCtxtPtr ctxt,
4648 				    int options)
4649 {
4650     return(xmlTextReaderSchemaValidateInternal(reader, NULL, ctxt, options));
4651 }
4652 
4653 /**
4654  * xmlTextReaderSchemaValidate:
4655  * @reader:  the xmlTextReaderPtr used
4656  * @xsd:  the path to a W3C XSD schema or NULL
4657  *
4658  * Use W3C XSD schema to validate the document as it is processed.
4659  * Activation is only possible before the first Read().
4660  * If @xsd is NULL, then XML Schema validation is deactivated.
4661  *
4662  * Returns 0 in case the schemas validation could be (de)activated and
4663  *         -1 in case of error.
4664  */
4665 int
xmlTextReaderSchemaValidate(xmlTextReaderPtr reader,const char * xsd)4666 xmlTextReaderSchemaValidate(xmlTextReaderPtr reader, const char *xsd)
4667 {
4668     return(xmlTextReaderSchemaValidateInternal(reader, xsd, NULL, 0));
4669 }
4670 
4671 /**
4672  * xmlTextReaderRelaxNGValidateCtxt:
4673  * @reader:  the xmlTextReaderPtr used
4674  * @ctxt: the RelaxNG schema validation context or NULL
4675  * @options: options (not used yet)
4676  *
4677  * Use RelaxNG schema context to validate the document as it is processed.
4678  * Activation is only possible before the first Read().
4679  * If @ctxt is NULL, then RelaxNG schema validation is deactivated.
4680  *
4681  * Returns 0 in case the schemas validation could be (de)activated and
4682  *         -1 in case of error.
4683  */
4684 int
xmlTextReaderRelaxNGValidateCtxt(xmlTextReaderPtr reader,xmlRelaxNGValidCtxtPtr ctxt,int options)4685 xmlTextReaderRelaxNGValidateCtxt(xmlTextReaderPtr reader,
4686 				 xmlRelaxNGValidCtxtPtr ctxt,
4687 				 int options)
4688 {
4689     return(xmlTextReaderRelaxNGValidateInternal(reader, NULL, ctxt, options));
4690 }
4691 
4692 /**
4693  * xmlTextReaderRelaxNGValidate:
4694  * @reader:  the xmlTextReaderPtr used
4695  * @rng:  the path to a RelaxNG schema or NULL
4696  *
4697  * Use RelaxNG schema to validate the document as it is processed.
4698  * Activation is only possible before the first Read().
4699  * If @rng is NULL, then RelaxNG schema validation is deactivated.
4700  *
4701  * Returns 0 in case the schemas validation could be (de)activated and
4702  *         -1 in case of error.
4703  */
4704 int
xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader,const char * rng)4705 xmlTextReaderRelaxNGValidate(xmlTextReaderPtr reader, const char *rng)
4706 {
4707     return(xmlTextReaderRelaxNGValidateInternal(reader, rng, NULL, 0));
4708 }
4709 
4710 #endif
4711 
4712 /**
4713  * xmlTextReaderIsNamespaceDecl:
4714  * @reader: the xmlTextReaderPtr used
4715  *
4716  * Determine whether the current node is a namespace declaration
4717  * rather than a regular attribute.
4718  *
4719  * Returns 1 if the current node is a namespace declaration, 0 if it
4720  * is a regular attribute or other type of node, or -1 in case of
4721  * error.
4722  */
4723 int
xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader)4724 xmlTextReaderIsNamespaceDecl(xmlTextReaderPtr reader) {
4725     xmlNodePtr node;
4726     if (reader == NULL)
4727 	return(-1);
4728     if (reader->node == NULL)
4729 	return(-1);
4730     if (reader->curnode != NULL)
4731 	node = reader->curnode;
4732     else
4733 	node = reader->node;
4734 
4735     if (XML_NAMESPACE_DECL == node->type)
4736 	return(1);
4737     else
4738 	return(0);
4739 }
4740 
4741 /**
4742  * xmlTextReaderConstXmlVersion:
4743  * @reader:  the xmlTextReaderPtr used
4744  *
4745  * Determine the XML version of the document being read.
4746  *
4747  * Returns a string containing the XML version of the document or NULL
4748  * in case of error.  The string is deallocated with the reader.
4749  */
4750 const xmlChar *
xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader)4751 xmlTextReaderConstXmlVersion(xmlTextReaderPtr reader) {
4752     xmlDocPtr doc = NULL;
4753     if (reader == NULL)
4754 	return(NULL);
4755     if (reader->doc != NULL)
4756         doc = reader->doc;
4757     else if (reader->ctxt != NULL)
4758 	doc = reader->ctxt->myDoc;
4759     if (doc == NULL)
4760 	return(NULL);
4761 
4762     if (doc->version == NULL)
4763 	return(NULL);
4764     else
4765       return(CONSTSTR(doc->version));
4766 }
4767 
4768 /**
4769  * xmlTextReaderStandalone:
4770  * @reader:  the xmlTextReaderPtr used
4771  *
4772  * Determine the standalone status of the document being read.
4773  *
4774  * Returns 1 if the document was declared to be standalone, 0 if it
4775  * was declared to be not standalone, or -1 if the document did not
4776  * specify its standalone status or in case of error.
4777  */
4778 int
xmlTextReaderStandalone(xmlTextReaderPtr reader)4779 xmlTextReaderStandalone(xmlTextReaderPtr reader) {
4780     xmlDocPtr doc = NULL;
4781     if (reader == NULL)
4782 	return(-1);
4783     if (reader->doc != NULL)
4784         doc = reader->doc;
4785     else if (reader->ctxt != NULL)
4786 	doc = reader->ctxt->myDoc;
4787     if (doc == NULL)
4788 	return(-1);
4789 
4790     return(doc->standalone);
4791 }
4792 
4793 /************************************************************************
4794  *									*
4795  *			Error Handling Extensions                       *
4796  *									*
4797  ************************************************************************/
4798 
4799 /* helper to build a xmlMalloc'ed string from a format and va_list */
4800 static char *
xmlTextReaderBuildMessage(const char * msg,va_list ap)4801 xmlTextReaderBuildMessage(const char *msg, va_list ap) {
4802     int size = 0;
4803     int chars;
4804     char *larger;
4805     char *str = NULL;
4806     va_list aq;
4807 
4808     while (1) {
4809         VA_COPY(aq, ap);
4810         chars = vsnprintf(str, size, msg, aq);
4811         va_end(aq);
4812         if (chars < 0) {
4813 	    xmlGenericError(xmlGenericErrorContext, "vsnprintf failed !\n");
4814 	    if (str)
4815 		xmlFree(str);
4816 	    return NULL;
4817 	}
4818 	if ((chars < size) || (size == MAX_ERR_MSG_SIZE))
4819             break;
4820         if (chars < MAX_ERR_MSG_SIZE)
4821 	size = chars + 1;
4822 	else
4823 		size = MAX_ERR_MSG_SIZE;
4824         if ((larger = (char *) xmlRealloc(str, size)) == NULL) {
4825 	    xmlGenericError(xmlGenericErrorContext, "xmlRealloc failed !\n");
4826 	    if (str)
4827                 xmlFree(str);
4828             return NULL;
4829         }
4830         str = larger;
4831     }
4832 
4833     return str;
4834 }
4835 
4836 /**
4837  * xmlTextReaderLocatorLineNumber:
4838  * @locator: the xmlTextReaderLocatorPtr used
4839  *
4840  * Obtain the line number for the given locator.
4841  *
4842  * Returns the line number or -1 in case of error.
4843  */
4844 int
xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator)4845 xmlTextReaderLocatorLineNumber(xmlTextReaderLocatorPtr locator) {
4846     /* we know that locator is a xmlParserCtxtPtr */
4847     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4848     int ret = -1;
4849 
4850     if (locator == NULL)
4851         return(-1);
4852     if (ctx->node != NULL) {
4853 	ret = xmlGetLineNo(ctx->node);
4854     }
4855     else {
4856 	/* inspired from error.c */
4857 	xmlParserInputPtr input;
4858 	input = ctx->input;
4859 	if ((input->filename == NULL) && (ctx->inputNr > 1))
4860 	    input = ctx->inputTab[ctx->inputNr - 2];
4861 	if (input != NULL) {
4862 	    ret = input->line;
4863 	}
4864 	else {
4865 	    ret = -1;
4866 	}
4867     }
4868 
4869     return ret;
4870 }
4871 
4872 /**
4873  * xmlTextReaderLocatorBaseURI:
4874  * @locator: the xmlTextReaderLocatorPtr used
4875  *
4876  * Obtain the base URI for the given locator.
4877  *
4878  * Returns the base URI or NULL in case of error,
4879  *    if non NULL it need to be freed by the caller.
4880  */
4881 xmlChar *
xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator)4882 xmlTextReaderLocatorBaseURI(xmlTextReaderLocatorPtr locator) {
4883     /* we know that locator is a xmlParserCtxtPtr */
4884     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr)locator;
4885     xmlChar *ret = NULL;
4886 
4887     if (locator == NULL)
4888         return(NULL);
4889     if (ctx->node != NULL) {
4890 	ret = xmlNodeGetBase(NULL,ctx->node);
4891     }
4892     else {
4893 	/* inspired from error.c */
4894 	xmlParserInputPtr input;
4895 	input = ctx->input;
4896 	if ((input->filename == NULL) && (ctx->inputNr > 1))
4897 	    input = ctx->inputTab[ctx->inputNr - 2];
4898 	if (input != NULL) {
4899 	    ret = xmlStrdup(BAD_CAST input->filename);
4900 	}
4901 	else {
4902 	    ret = NULL;
4903 	}
4904     }
4905 
4906     return ret;
4907 }
4908 
4909 static void
xmlTextReaderGenericError(void * ctxt,xmlParserSeverities severity,char * str)4910 xmlTextReaderGenericError(void *ctxt, xmlParserSeverities severity,
4911                           char *str)
4912 {
4913     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4914 
4915     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4916 
4917     if (str != NULL) {
4918         if (reader->errorFunc)
4919             reader->errorFunc(reader->errorFuncArg, str, severity,
4920                               (xmlTextReaderLocatorPtr) ctx);
4921         xmlFree(str);
4922     }
4923 }
4924 
4925 static void
xmlTextReaderStructuredError(void * ctxt,xmlErrorPtr error)4926 xmlTextReaderStructuredError(void *ctxt, xmlErrorPtr error)
4927 {
4928     xmlParserCtxtPtr ctx = (xmlParserCtxtPtr) ctxt;
4929 
4930     xmlTextReaderPtr reader = (xmlTextReaderPtr) ctx->_private;
4931 
4932     if (error && reader->sErrorFunc) {
4933         reader->sErrorFunc(reader->errorFuncArg, (xmlErrorPtr) error);
4934     }
4935 }
4936 
4937 static void XMLCDECL LIBXML_ATTR_FORMAT(2,3)
xmlTextReaderError(void * ctxt,const char * msg,...)4938 xmlTextReaderError(void *ctxt, const char *msg, ...)
4939 {
4940     va_list ap;
4941 
4942     va_start(ap, msg);
4943     xmlTextReaderGenericError(ctxt,
4944                               XML_PARSER_SEVERITY_ERROR,
4945                               xmlTextReaderBuildMessage(msg, ap));
4946     va_end(ap);
4947 
4948 }
4949 
4950 static void XMLCDECL LIBXML_ATTR_FORMAT(2,3)
xmlTextReaderWarning(void * ctxt,const char * msg,...)4951 xmlTextReaderWarning(void *ctxt, const char *msg, ...)
4952 {
4953     va_list ap;
4954 
4955     va_start(ap, msg);
4956     xmlTextReaderGenericError(ctxt,
4957                               XML_PARSER_SEVERITY_WARNING,
4958                               xmlTextReaderBuildMessage(msg, ap));
4959     va_end(ap);
4960 }
4961 
4962 static void XMLCDECL
xmlTextReaderValidityError(void * ctxt,const char * msg,...)4963 xmlTextReaderValidityError(void *ctxt, const char *msg, ...)
4964 {
4965     va_list ap;
4966 
4967     int len = xmlStrlen((const xmlChar *) msg);
4968 
4969     if ((len > 1) && (msg[len - 2] != ':')) {
4970         /*
4971          * some callbacks only report locator information:
4972          * skip them (mimicking behaviour in error.c)
4973          */
4974         va_start(ap, msg);
4975         xmlTextReaderGenericError(ctxt,
4976                                   XML_PARSER_SEVERITY_VALIDITY_ERROR,
4977                                   xmlTextReaderBuildMessage(msg, ap));
4978         va_end(ap);
4979     }
4980 }
4981 
4982 static void XMLCDECL
xmlTextReaderValidityWarning(void * ctxt,const char * msg,...)4983 xmlTextReaderValidityWarning(void *ctxt, const char *msg, ...)
4984 {
4985     va_list ap;
4986 
4987     int len = xmlStrlen((const xmlChar *) msg);
4988 
4989     if ((len != 0) && (msg[len - 1] != ':')) {
4990         /*
4991          * some callbacks only report locator information:
4992          * skip them (mimicking behaviour in error.c)
4993          */
4994         va_start(ap, msg);
4995         xmlTextReaderGenericError(ctxt,
4996                                   XML_PARSER_SEVERITY_VALIDITY_WARNING,
4997                                   xmlTextReaderBuildMessage(msg, ap));
4998         va_end(ap);
4999     }
5000 }
5001 
5002 /**
5003  * xmlTextReaderSetErrorHandler:
5004  * @reader:  the xmlTextReaderPtr used
5005  * @f:	the callback function to call on error and warnings
5006  * @arg:    a user argument to pass to the callback function
5007  *
5008  * Register a callback function that will be called on error and warnings.
5009  *
5010  * If @f is NULL, the default error and warning handlers are restored.
5011  */
5012 void
xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,xmlTextReaderErrorFunc f,void * arg)5013 xmlTextReaderSetErrorHandler(xmlTextReaderPtr reader,
5014                              xmlTextReaderErrorFunc f, void *arg)
5015 {
5016     if (f != NULL) {
5017         reader->ctxt->sax->error = xmlTextReaderError;
5018         reader->ctxt->sax->serror = NULL;
5019         reader->ctxt->vctxt.error = xmlTextReaderValidityError;
5020         reader->ctxt->sax->warning = xmlTextReaderWarning;
5021         reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
5022         reader->errorFunc = f;
5023         reader->sErrorFunc = NULL;
5024         reader->errorFuncArg = arg;
5025 #ifdef LIBXML_SCHEMAS_ENABLED
5026         if (reader->rngValidCtxt) {
5027             xmlRelaxNGSetValidErrors(reader->rngValidCtxt,
5028                                      xmlTextReaderValidityErrorRelay,
5029                                      xmlTextReaderValidityWarningRelay,
5030                                      reader);
5031             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
5032                                                reader);
5033         }
5034         if (reader->xsdValidCtxt) {
5035             xmlSchemaSetValidErrors(reader->xsdValidCtxt,
5036                                     xmlTextReaderValidityErrorRelay,
5037                                     xmlTextReaderValidityWarningRelay,
5038                                     reader);
5039             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
5040                                               reader);
5041         }
5042 #endif
5043     } else {
5044         /* restore defaults */
5045         reader->ctxt->sax->error = xmlParserError;
5046         reader->ctxt->vctxt.error = xmlParserValidityError;
5047         reader->ctxt->sax->warning = xmlParserWarning;
5048         reader->ctxt->vctxt.warning = xmlParserValidityWarning;
5049         reader->errorFunc = NULL;
5050         reader->sErrorFunc = NULL;
5051         reader->errorFuncArg = NULL;
5052 #ifdef LIBXML_SCHEMAS_ENABLED
5053         if (reader->rngValidCtxt) {
5054             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
5055                                      reader);
5056             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
5057                                                reader);
5058         }
5059         if (reader->xsdValidCtxt) {
5060             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
5061                                     reader);
5062             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
5063                                               reader);
5064         }
5065 #endif
5066     }
5067 }
5068 
5069 /**
5070 * xmlTextReaderSetStructuredErrorHandler:
5071  * @reader:  the xmlTextReaderPtr used
5072  * @f:	the callback function to call on error and warnings
5073  * @arg:    a user argument to pass to the callback function
5074  *
5075  * Register a callback function that will be called on error and warnings.
5076  *
5077  * If @f is NULL, the default error and warning handlers are restored.
5078  */
5079 void
xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,xmlStructuredErrorFunc f,void * arg)5080 xmlTextReaderSetStructuredErrorHandler(xmlTextReaderPtr reader,
5081                                        xmlStructuredErrorFunc f, void *arg)
5082 {
5083     if (f != NULL) {
5084         reader->ctxt->sax->error = NULL;
5085         reader->ctxt->sax->serror = xmlTextReaderStructuredError;
5086         reader->ctxt->vctxt.error = xmlTextReaderValidityError;
5087         reader->ctxt->sax->warning = xmlTextReaderWarning;
5088         reader->ctxt->vctxt.warning = xmlTextReaderValidityWarning;
5089         reader->sErrorFunc = f;
5090         reader->errorFunc = NULL;
5091         reader->errorFuncArg = arg;
5092 #ifdef LIBXML_SCHEMAS_ENABLED
5093         if (reader->rngValidCtxt) {
5094             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
5095                                      reader);
5096             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt,
5097                                         xmlTextReaderValidityStructuredRelay,
5098                                                reader);
5099         }
5100         if (reader->xsdValidCtxt) {
5101             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
5102                                     reader);
5103             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt,
5104                                        xmlTextReaderValidityStructuredRelay,
5105                                               reader);
5106         }
5107 #endif
5108     } else {
5109         /* restore defaults */
5110         reader->ctxt->sax->error = xmlParserError;
5111         reader->ctxt->sax->serror = NULL;
5112         reader->ctxt->vctxt.error = xmlParserValidityError;
5113         reader->ctxt->sax->warning = xmlParserWarning;
5114         reader->ctxt->vctxt.warning = xmlParserValidityWarning;
5115         reader->errorFunc = NULL;
5116         reader->sErrorFunc = NULL;
5117         reader->errorFuncArg = NULL;
5118 #ifdef LIBXML_SCHEMAS_ENABLED
5119         if (reader->rngValidCtxt) {
5120             xmlRelaxNGSetValidErrors(reader->rngValidCtxt, NULL, NULL,
5121                                      reader);
5122             xmlRelaxNGSetValidStructuredErrors(reader->rngValidCtxt, NULL,
5123                                                reader);
5124         }
5125         if (reader->xsdValidCtxt) {
5126             xmlSchemaSetValidErrors(reader->xsdValidCtxt, NULL, NULL,
5127                                     reader);
5128             xmlSchemaSetValidStructuredErrors(reader->xsdValidCtxt, NULL,
5129                                               reader);
5130         }
5131 #endif
5132     }
5133 }
5134 
5135 /**
5136  * xmlTextReaderIsValid:
5137  * @reader:  the xmlTextReaderPtr used
5138  *
5139  * Retrieve the validity status from the parser context
5140  *
5141  * Returns the flag value 1 if valid, 0 if no, and -1 in case of error
5142  */
5143 int
xmlTextReaderIsValid(xmlTextReaderPtr reader)5144 xmlTextReaderIsValid(xmlTextReaderPtr reader)
5145 {
5146     if (reader == NULL)
5147         return (-1);
5148 #ifdef LIBXML_SCHEMAS_ENABLED
5149     if (reader->validate == XML_TEXTREADER_VALIDATE_RNG)
5150         return (reader->rngValidErrors == 0);
5151     if (reader->validate == XML_TEXTREADER_VALIDATE_XSD)
5152         return (reader->xsdValidErrors == 0);
5153 #endif
5154     if ((reader->ctxt != NULL) && (reader->ctxt->validate == 1))
5155         return (reader->ctxt->valid);
5156     return (0);
5157 }
5158 
5159 /**
5160  * xmlTextReaderGetErrorHandler:
5161  * @reader:  the xmlTextReaderPtr used
5162  * @f:	the callback function or NULL is no callback has been registered
5163  * @arg:    a user argument
5164  *
5165  * Retrieve the error callback function and user argument.
5166  */
5167 void
xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,xmlTextReaderErrorFunc * f,void ** arg)5168 xmlTextReaderGetErrorHandler(xmlTextReaderPtr reader,
5169                              xmlTextReaderErrorFunc * f, void **arg)
5170 {
5171     if (f != NULL)
5172         *f = reader->errorFunc;
5173     if (arg != NULL)
5174         *arg = reader->errorFuncArg;
5175 }
5176 /************************************************************************
5177  *									*
5178  *	New set (2.6.0) of simpler and more flexible APIs		*
5179  *									*
5180  ************************************************************************/
5181 
5182 /**
5183  * xmlTextReaderSetup:
5184  * @reader:  an XML reader
5185  * @input: xmlParserInputBufferPtr used to feed the reader, will
5186  *         be destroyed with it.
5187  * @URL:  the base URL to use for the document
5188  * @encoding:  the document encoding, or NULL
5189  * @options:  a combination of xmlParserOption
5190  *
5191  * Setup an XML reader with new options
5192  *
5193  * Returns 0 in case of success and -1 in case of error.
5194  */
5195 int
xmlTextReaderSetup(xmlTextReaderPtr reader,xmlParserInputBufferPtr input,const char * URL,const char * encoding,int options)5196 xmlTextReaderSetup(xmlTextReaderPtr reader,
5197                    xmlParserInputBufferPtr input, const char *URL,
5198                    const char *encoding, int options)
5199 {
5200     if (reader == NULL) {
5201         if (input != NULL)
5202 	    xmlFreeParserInputBuffer(input);
5203         return (-1);
5204     }
5205 
5206     /*
5207      * we force the generation of compact text nodes on the reader
5208      * since usr applications should never modify the tree
5209      */
5210     options |= XML_PARSE_COMPACT;
5211 
5212     reader->doc = NULL;
5213     reader->entNr = 0;
5214     reader->parserFlags = options;
5215     reader->validate = XML_TEXTREADER_NOT_VALIDATE;
5216     if ((input != NULL) && (reader->input != NULL) &&
5217         (reader->allocs & XML_TEXTREADER_INPUT)) {
5218 	xmlFreeParserInputBuffer(reader->input);
5219 	reader->input = NULL;
5220 	reader->allocs -= XML_TEXTREADER_INPUT;
5221     }
5222     if (input != NULL) {
5223 	reader->input = input;
5224 	reader->allocs |= XML_TEXTREADER_INPUT;
5225     }
5226     if (reader->buffer == NULL)
5227         reader->buffer = xmlBufCreateSize(100);
5228     if (reader->buffer == NULL) {
5229         xmlGenericError(xmlGenericErrorContext,
5230                         "xmlTextReaderSetup : malloc failed\n");
5231         return (-1);
5232     }
5233     /* no operation on a reader should require a huge buffer */
5234     xmlBufSetAllocationScheme(reader->buffer,
5235 			      XML_BUFFER_ALLOC_BOUNDED);
5236     if (reader->sax == NULL)
5237 	reader->sax = (xmlSAXHandler *) xmlMalloc(sizeof(xmlSAXHandler));
5238     if (reader->sax == NULL) {
5239         xmlGenericError(xmlGenericErrorContext,
5240                         "xmlTextReaderSetup : malloc failed\n");
5241         return (-1);
5242     }
5243     xmlSAXVersion(reader->sax, 2);
5244     reader->startElement = reader->sax->startElement;
5245     reader->sax->startElement = xmlTextReaderStartElement;
5246     reader->endElement = reader->sax->endElement;
5247     reader->sax->endElement = xmlTextReaderEndElement;
5248 #ifdef LIBXML_SAX1_ENABLED
5249     if (reader->sax->initialized == XML_SAX2_MAGIC) {
5250 #endif /* LIBXML_SAX1_ENABLED */
5251         reader->startElementNs = reader->sax->startElementNs;
5252         reader->sax->startElementNs = xmlTextReaderStartElementNs;
5253         reader->endElementNs = reader->sax->endElementNs;
5254         reader->sax->endElementNs = xmlTextReaderEndElementNs;
5255 #ifdef LIBXML_SAX1_ENABLED
5256     } else {
5257         reader->startElementNs = NULL;
5258         reader->endElementNs = NULL;
5259     }
5260 #endif /* LIBXML_SAX1_ENABLED */
5261     reader->characters = reader->sax->characters;
5262     reader->sax->characters = xmlTextReaderCharacters;
5263     reader->sax->ignorableWhitespace = xmlTextReaderCharacters;
5264     reader->cdataBlock = reader->sax->cdataBlock;
5265     reader->sax->cdataBlock = xmlTextReaderCDataBlock;
5266 
5267     reader->mode = XML_TEXTREADER_MODE_INITIAL;
5268     reader->node = NULL;
5269     reader->curnode = NULL;
5270     if (input != NULL) {
5271         if (xmlBufUse(reader->input->buffer) < 4) {
5272             xmlParserInputBufferRead(input, 4);
5273         }
5274         if (reader->ctxt == NULL) {
5275             if (xmlBufUse(reader->input->buffer) >= 4) {
5276                 reader->ctxt = xmlCreatePushParserCtxt(reader->sax, NULL,
5277 		       (const char *) xmlBufContent(reader->input->buffer),
5278                                       4, URL);
5279                 reader->base = 0;
5280                 reader->cur = 4;
5281             } else {
5282                 reader->ctxt =
5283                     xmlCreatePushParserCtxt(reader->sax, NULL, NULL, 0, URL);
5284                 reader->base = 0;
5285                 reader->cur = 0;
5286             }
5287         } else {
5288 	    xmlParserInputPtr inputStream;
5289 	    xmlParserInputBufferPtr buf;
5290 	    xmlCharEncoding enc = XML_CHAR_ENCODING_NONE;
5291 
5292 	    xmlCtxtReset(reader->ctxt);
5293 	    buf = xmlAllocParserInputBuffer(enc);
5294 	    if (buf == NULL) return(-1);
5295 	    inputStream = xmlNewInputStream(reader->ctxt);
5296 	    if (inputStream == NULL) {
5297 		xmlFreeParserInputBuffer(buf);
5298 		return(-1);
5299 	    }
5300 
5301 	    if (URL == NULL)
5302 		inputStream->filename = NULL;
5303 	    else
5304 		inputStream->filename = (char *)
5305 		    xmlCanonicPath((const xmlChar *) URL);
5306 	    inputStream->buf = buf;
5307             xmlBufResetInput(buf->buffer, inputStream);
5308 
5309 	    inputPush(reader->ctxt, inputStream);
5310 	    reader->cur = 0;
5311 	}
5312         if (reader->ctxt == NULL) {
5313             xmlGenericError(xmlGenericErrorContext,
5314                             "xmlTextReaderSetup : malloc failed\n");
5315             return (-1);
5316         }
5317     }
5318     if (reader->dict != NULL) {
5319         if (reader->ctxt->dict != NULL) {
5320 	    if (reader->dict != reader->ctxt->dict) {
5321 		xmlDictFree(reader->dict);
5322 		reader->dict = reader->ctxt->dict;
5323 	    }
5324 	} else {
5325 	    reader->ctxt->dict = reader->dict;
5326 	}
5327     } else {
5328 	if (reader->ctxt->dict == NULL)
5329 	    reader->ctxt->dict = xmlDictCreate();
5330         reader->dict = reader->ctxt->dict;
5331     }
5332     reader->ctxt->_private = reader;
5333     reader->ctxt->linenumbers = 1;
5334     reader->ctxt->dictNames = 1;
5335     /*
5336      * use the parser dictionary to allocate all elements and attributes names
5337      */
5338     reader->ctxt->docdict = 1;
5339     reader->ctxt->parseMode = XML_PARSE_READER;
5340 
5341 #ifdef LIBXML_XINCLUDE_ENABLED
5342     if (reader->xincctxt != NULL) {
5343 	xmlXIncludeFreeContext(reader->xincctxt);
5344 	reader->xincctxt = NULL;
5345     }
5346     if (options & XML_PARSE_XINCLUDE) {
5347         reader->xinclude = 1;
5348 	reader->xinclude_name = xmlDictLookup(reader->dict, XINCLUDE_NODE, -1);
5349 	options -= XML_PARSE_XINCLUDE;
5350     } else
5351         reader->xinclude = 0;
5352     reader->in_xinclude = 0;
5353 #endif
5354 #ifdef LIBXML_PATTERN_ENABLED
5355     if (reader->patternTab == NULL) {
5356         reader->patternNr = 0;
5357 	reader->patternMax = 0;
5358     }
5359     while (reader->patternNr > 0) {
5360         reader->patternNr--;
5361 	if (reader->patternTab[reader->patternNr] != NULL) {
5362 	    xmlFreePattern(reader->patternTab[reader->patternNr]);
5363             reader->patternTab[reader->patternNr] = NULL;
5364 	}
5365     }
5366 #endif
5367 
5368     if (options & XML_PARSE_DTDVALID)
5369         reader->validate = XML_TEXTREADER_VALIDATE_DTD;
5370 
5371     xmlCtxtUseOptions(reader->ctxt, options);
5372     if (encoding != NULL) {
5373         xmlCharEncodingHandlerPtr hdlr;
5374 
5375         hdlr = xmlFindCharEncodingHandler(encoding);
5376         if (hdlr != NULL)
5377             xmlSwitchToEncoding(reader->ctxt, hdlr);
5378     }
5379     if ((URL != NULL) && (reader->ctxt->input != NULL) &&
5380         (reader->ctxt->input->filename == NULL))
5381         reader->ctxt->input->filename = (char *)
5382             xmlStrdup((const xmlChar *) URL);
5383 
5384     reader->doc = NULL;
5385 
5386     return (0);
5387 }
5388 
5389 /**
5390  * xmlTextReaderByteConsumed:
5391  * @reader: an XML reader
5392  *
5393  * This function provides the current index of the parser used
5394  * by the reader, relative to the start of the current entity.
5395  * This function actually just wraps a call to xmlBytesConsumed()
5396  * for the parser context associated with the reader.
5397  * See xmlBytesConsumed() for more information.
5398  *
5399  * Returns the index in bytes from the beginning of the entity or -1
5400  *         in case the index could not be computed.
5401  */
5402 long
xmlTextReaderByteConsumed(xmlTextReaderPtr reader)5403 xmlTextReaderByteConsumed(xmlTextReaderPtr reader) {
5404     if ((reader == NULL) || (reader->ctxt == NULL))
5405         return(-1);
5406     return(xmlByteConsumed(reader->ctxt));
5407 }
5408 
5409 
5410 /**
5411  * xmlReaderWalker:
5412  * @doc:  a preparsed document
5413  *
5414  * Create an xmltextReader for a preparsed document.
5415  *
5416  * Returns the new reader or NULL in case of error.
5417  */
5418 xmlTextReaderPtr
xmlReaderWalker(xmlDocPtr doc)5419 xmlReaderWalker(xmlDocPtr doc)
5420 {
5421     xmlTextReaderPtr ret;
5422 
5423     if (doc == NULL)
5424         return(NULL);
5425 
5426     ret = xmlMalloc(sizeof(xmlTextReader));
5427     if (ret == NULL) {
5428         xmlGenericError(xmlGenericErrorContext,
5429 		"xmlNewTextReader : malloc failed\n");
5430 	return(NULL);
5431     }
5432     memset(ret, 0, sizeof(xmlTextReader));
5433     ret->entNr = 0;
5434     ret->input = NULL;
5435     ret->mode = XML_TEXTREADER_MODE_INITIAL;
5436     ret->node = NULL;
5437     ret->curnode = NULL;
5438     ret->base = 0;
5439     ret->cur = 0;
5440     ret->allocs = XML_TEXTREADER_CTXT;
5441     ret->doc = doc;
5442     ret->state = XML_TEXTREADER_START;
5443     ret->dict = xmlDictCreate();
5444     return(ret);
5445 }
5446 
5447 /**
5448  * xmlReaderForDoc:
5449  * @cur:  a pointer to a zero terminated string
5450  * @URL:  the base URL to use for the document
5451  * @encoding:  the document encoding, or NULL
5452  * @options:  a combination of xmlParserOption
5453  *
5454  * Create an xmltextReader for an XML in-memory document.
5455  * The parsing flags @options are a combination of xmlParserOption.
5456  *
5457  * Returns the new reader or NULL in case of error.
5458  */
5459 xmlTextReaderPtr
xmlReaderForDoc(const xmlChar * cur,const char * URL,const char * encoding,int options)5460 xmlReaderForDoc(const xmlChar * cur, const char *URL, const char *encoding,
5461                 int options)
5462 {
5463     int len;
5464 
5465     if (cur == NULL)
5466         return (NULL);
5467     len = xmlStrlen(cur);
5468 
5469     return (xmlReaderForMemory
5470             ((const char *) cur, len, URL, encoding, options));
5471 }
5472 
5473 /**
5474  * xmlReaderForFile:
5475  * @filename:  a file or URL
5476  * @encoding:  the document encoding, or NULL
5477  * @options:  a combination of xmlParserOption
5478  *
5479  * parse an XML file from the filesystem or the network.
5480  * The parsing flags @options are a combination of xmlParserOption.
5481  *
5482  * Returns the new reader or NULL in case of error.
5483  */
5484 xmlTextReaderPtr
xmlReaderForFile(const char * filename,const char * encoding,int options)5485 xmlReaderForFile(const char *filename, const char *encoding, int options)
5486 {
5487     xmlTextReaderPtr reader;
5488 
5489     reader = xmlNewTextReaderFilename(filename);
5490     if (reader == NULL)
5491         return (NULL);
5492     xmlTextReaderSetup(reader, NULL, NULL, encoding, options);
5493     return (reader);
5494 }
5495 
5496 /**
5497  * xmlReaderForMemory:
5498  * @buffer:  a pointer to a char array
5499  * @size:  the size of the array
5500  * @URL:  the base URL to use for the document
5501  * @encoding:  the document encoding, or NULL
5502  * @options:  a combination of xmlParserOption
5503  *
5504  * Create an xmltextReader for an XML in-memory document.
5505  * The parsing flags @options are a combination of xmlParserOption.
5506  *
5507  * Returns the new reader or NULL in case of error.
5508  */
5509 xmlTextReaderPtr
xmlReaderForMemory(const char * buffer,int size,const char * URL,const char * encoding,int options)5510 xmlReaderForMemory(const char *buffer, int size, const char *URL,
5511                    const char *encoding, int options)
5512 {
5513     xmlTextReaderPtr reader;
5514     xmlParserInputBufferPtr buf;
5515 
5516     buf = xmlParserInputBufferCreateStatic(buffer, size,
5517                                       XML_CHAR_ENCODING_NONE);
5518     if (buf == NULL) {
5519         return (NULL);
5520     }
5521     reader = xmlNewTextReader(buf, URL);
5522     if (reader == NULL) {
5523         xmlFreeParserInputBuffer(buf);
5524         return (NULL);
5525     }
5526     reader->allocs |= XML_TEXTREADER_INPUT;
5527     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5528     return (reader);
5529 }
5530 
5531 /**
5532  * xmlReaderForFd:
5533  * @fd:  an open file descriptor
5534  * @URL:  the base URL to use for the document
5535  * @encoding:  the document encoding, or NULL
5536  * @options:  a combination of xmlParserOption
5537  *
5538  * Create an xmltextReader for an XML from a file descriptor.
5539  * The parsing flags @options are a combination of xmlParserOption.
5540  * NOTE that the file descriptor will not be closed when the
5541  *      reader is closed or reset.
5542  *
5543  * Returns the new reader or NULL in case of error.
5544  */
5545 xmlTextReaderPtr
xmlReaderForFd(int fd,const char * URL,const char * encoding,int options)5546 xmlReaderForFd(int fd, const char *URL, const char *encoding, int options)
5547 {
5548     xmlTextReaderPtr reader;
5549     xmlParserInputBufferPtr input;
5550 
5551     if (fd < 0)
5552         return (NULL);
5553 
5554     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5555     if (input == NULL)
5556         return (NULL);
5557     input->closecallback = NULL;
5558     reader = xmlNewTextReader(input, URL);
5559     if (reader == NULL) {
5560         xmlFreeParserInputBuffer(input);
5561         return (NULL);
5562     }
5563     reader->allocs |= XML_TEXTREADER_INPUT;
5564     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5565     return (reader);
5566 }
5567 
5568 /**
5569  * xmlReaderForIO:
5570  * @ioread:  an I/O read function
5571  * @ioclose:  an I/O close function
5572  * @ioctx:  an I/O handler
5573  * @URL:  the base URL to use for the document
5574  * @encoding:  the document encoding, or NULL
5575  * @options:  a combination of xmlParserOption
5576  *
5577  * Create an xmltextReader for an XML document from I/O functions and source.
5578  * The parsing flags @options are a combination of xmlParserOption.
5579  *
5580  * Returns the new reader or NULL in case of error.
5581  */
5582 xmlTextReaderPtr
xmlReaderForIO(xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,const char * URL,const char * encoding,int options)5583 xmlReaderForIO(xmlInputReadCallback ioread, xmlInputCloseCallback ioclose,
5584                void *ioctx, const char *URL, const char *encoding,
5585                int options)
5586 {
5587     xmlTextReaderPtr reader;
5588     xmlParserInputBufferPtr input;
5589 
5590     if (ioread == NULL)
5591         return (NULL);
5592 
5593     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5594                                          XML_CHAR_ENCODING_NONE);
5595     if (input == NULL) {
5596         if (ioclose != NULL)
5597             ioclose(ioctx);
5598         return (NULL);
5599     }
5600     reader = xmlNewTextReader(input, URL);
5601     if (reader == NULL) {
5602         xmlFreeParserInputBuffer(input);
5603         return (NULL);
5604     }
5605     reader->allocs |= XML_TEXTREADER_INPUT;
5606     xmlTextReaderSetup(reader, NULL, URL, encoding, options);
5607     return (reader);
5608 }
5609 
5610 /**
5611  * xmlReaderNewWalker:
5612  * @reader:  an XML reader
5613  * @doc:  a preparsed document
5614  *
5615  * Setup an xmltextReader to parse a preparsed XML document.
5616  * This reuses the existing @reader xmlTextReader.
5617  *
5618  * Returns 0 in case of success and -1 in case of error
5619  */
5620 int
xmlReaderNewWalker(xmlTextReaderPtr reader,xmlDocPtr doc)5621 xmlReaderNewWalker(xmlTextReaderPtr reader, xmlDocPtr doc)
5622 {
5623     if (doc == NULL)
5624         return (-1);
5625     if (reader == NULL)
5626         return (-1);
5627 
5628     if (reader->input != NULL) {
5629         xmlFreeParserInputBuffer(reader->input);
5630     }
5631     if (reader->ctxt != NULL) {
5632 	xmlCtxtReset(reader->ctxt);
5633     }
5634 
5635     reader->entNr = 0;
5636     reader->input = NULL;
5637     reader->mode = XML_TEXTREADER_MODE_INITIAL;
5638     reader->node = NULL;
5639     reader->curnode = NULL;
5640     reader->base = 0;
5641     reader->cur = 0;
5642     reader->allocs = XML_TEXTREADER_CTXT;
5643     reader->doc = doc;
5644     reader->state = XML_TEXTREADER_START;
5645     if (reader->dict == NULL) {
5646         if ((reader->ctxt != NULL) && (reader->ctxt->dict != NULL))
5647 	    reader->dict = reader->ctxt->dict;
5648 	else
5649 	    reader->dict = xmlDictCreate();
5650     }
5651     return(0);
5652 }
5653 
5654 /**
5655  * xmlReaderNewDoc:
5656  * @reader:  an XML reader
5657  * @cur:  a pointer to a zero terminated string
5658  * @URL:  the base URL to use for the document
5659  * @encoding:  the document encoding, or NULL
5660  * @options:  a combination of xmlParserOption
5661  *
5662  * Setup an xmltextReader to parse an XML in-memory document.
5663  * The parsing flags @options are a combination of xmlParserOption.
5664  * This reuses the existing @reader xmlTextReader.
5665  *
5666  * Returns 0 in case of success and -1 in case of error
5667  */
5668 int
xmlReaderNewDoc(xmlTextReaderPtr reader,const xmlChar * cur,const char * URL,const char * encoding,int options)5669 xmlReaderNewDoc(xmlTextReaderPtr reader, const xmlChar * cur,
5670                 const char *URL, const char *encoding, int options)
5671 {
5672 
5673     int len;
5674 
5675     if (cur == NULL)
5676         return (-1);
5677     if (reader == NULL)
5678         return (-1);
5679 
5680     len = xmlStrlen(cur);
5681     return (xmlReaderNewMemory(reader, (const char *)cur, len,
5682                                URL, encoding, options));
5683 }
5684 
5685 /**
5686  * xmlReaderNewFile:
5687  * @reader:  an XML reader
5688  * @filename:  a file or URL
5689  * @encoding:  the document encoding, or NULL
5690  * @options:  a combination of xmlParserOption
5691  *
5692  * parse an XML file from the filesystem or the network.
5693  * The parsing flags @options are a combination of xmlParserOption.
5694  * This reuses the existing @reader xmlTextReader.
5695  *
5696  * Returns 0 in case of success and -1 in case of error
5697  */
5698 int
xmlReaderNewFile(xmlTextReaderPtr reader,const char * filename,const char * encoding,int options)5699 xmlReaderNewFile(xmlTextReaderPtr reader, const char *filename,
5700                  const char *encoding, int options)
5701 {
5702     xmlParserInputBufferPtr input;
5703 
5704     if (filename == NULL)
5705         return (-1);
5706     if (reader == NULL)
5707         return (-1);
5708 
5709     input =
5710         xmlParserInputBufferCreateFilename(filename,
5711                                            XML_CHAR_ENCODING_NONE);
5712     if (input == NULL)
5713         return (-1);
5714     return (xmlTextReaderSetup(reader, input, filename, encoding, options));
5715 }
5716 
5717 /**
5718  * xmlReaderNewMemory:
5719  * @reader:  an XML reader
5720  * @buffer:  a pointer to a char array
5721  * @size:  the size of the array
5722  * @URL:  the base URL to use for the document
5723  * @encoding:  the document encoding, or NULL
5724  * @options:  a combination of xmlParserOption
5725  *
5726  * Setup an xmltextReader to parse an XML in-memory document.
5727  * The parsing flags @options are a combination of xmlParserOption.
5728  * This reuses the existing @reader xmlTextReader.
5729  *
5730  * Returns 0 in case of success and -1 in case of error
5731  */
5732 int
xmlReaderNewMemory(xmlTextReaderPtr reader,const char * buffer,int size,const char * URL,const char * encoding,int options)5733 xmlReaderNewMemory(xmlTextReaderPtr reader, const char *buffer, int size,
5734                    const char *URL, const char *encoding, int options)
5735 {
5736     xmlParserInputBufferPtr input;
5737 
5738     if (reader == NULL)
5739         return (-1);
5740     if (buffer == NULL)
5741         return (-1);
5742 
5743     input = xmlParserInputBufferCreateStatic(buffer, size,
5744                                       XML_CHAR_ENCODING_NONE);
5745     if (input == NULL) {
5746         return (-1);
5747     }
5748     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5749 }
5750 
5751 /**
5752  * xmlReaderNewFd:
5753  * @reader:  an XML reader
5754  * @fd:  an open file descriptor
5755  * @URL:  the base URL to use for the document
5756  * @encoding:  the document encoding, or NULL
5757  * @options:  a combination of xmlParserOption
5758  *
5759  * Setup an xmltextReader to parse an XML from a file descriptor.
5760  * NOTE that the file descriptor will not be closed when the
5761  *      reader is closed or reset.
5762  * The parsing flags @options are a combination of xmlParserOption.
5763  * This reuses the existing @reader xmlTextReader.
5764  *
5765  * Returns 0 in case of success and -1 in case of error
5766  */
5767 int
xmlReaderNewFd(xmlTextReaderPtr reader,int fd,const char * URL,const char * encoding,int options)5768 xmlReaderNewFd(xmlTextReaderPtr reader, int fd,
5769                const char *URL, const char *encoding, int options)
5770 {
5771     xmlParserInputBufferPtr input;
5772 
5773     if (fd < 0)
5774         return (-1);
5775     if (reader == NULL)
5776         return (-1);
5777 
5778     input = xmlParserInputBufferCreateFd(fd, XML_CHAR_ENCODING_NONE);
5779     if (input == NULL)
5780         return (-1);
5781     input->closecallback = NULL;
5782     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5783 }
5784 
5785 /**
5786  * xmlReaderNewIO:
5787  * @reader:  an XML reader
5788  * @ioread:  an I/O read function
5789  * @ioclose:  an I/O close function
5790  * @ioctx:  an I/O handler
5791  * @URL:  the base URL to use for the document
5792  * @encoding:  the document encoding, or NULL
5793  * @options:  a combination of xmlParserOption
5794  *
5795  * Setup an xmltextReader to parse an XML document from I/O functions
5796  * and source.
5797  * The parsing flags @options are a combination of xmlParserOption.
5798  * This reuses the existing @reader xmlTextReader.
5799  *
5800  * Returns 0 in case of success and -1 in case of error
5801  */
5802 int
xmlReaderNewIO(xmlTextReaderPtr reader,xmlInputReadCallback ioread,xmlInputCloseCallback ioclose,void * ioctx,const char * URL,const char * encoding,int options)5803 xmlReaderNewIO(xmlTextReaderPtr reader, xmlInputReadCallback ioread,
5804                xmlInputCloseCallback ioclose, void *ioctx,
5805                const char *URL, const char *encoding, int options)
5806 {
5807     xmlParserInputBufferPtr input;
5808 
5809     if (ioread == NULL)
5810         return (-1);
5811     if (reader == NULL)
5812         return (-1);
5813 
5814     input = xmlParserInputBufferCreateIO(ioread, ioclose, ioctx,
5815                                          XML_CHAR_ENCODING_NONE);
5816     if (input == NULL) {
5817         if (ioclose != NULL)
5818             ioclose(ioctx);
5819         return (-1);
5820     }
5821     return (xmlTextReaderSetup(reader, input, URL, encoding, options));
5822 }
5823 
5824 /************************************************************************
5825  *									*
5826  *			Utilities					*
5827  *									*
5828  ************************************************************************/
5829 #ifdef NOT_USED_YET
5830 
5831 /**
5832  * xmlBase64Decode:
5833  * @in:  the input buffer
5834  * @inlen:  the size of the input (in), the size read from it (out)
5835  * @to:  the output buffer
5836  * @tolen:  the size of the output (in), the size written to (out)
5837  *
5838  * Base64 decoder, reads from @in and save in @to
5839  * TODO: tell jody when this is actually exported
5840  *
5841  * Returns 0 if all the input was consumer, 1 if the Base64 end was reached,
5842  *         2 if there wasn't enough space on the output or -1 in case of error.
5843  */
5844 static int
xmlBase64Decode(const unsigned char * in,unsigned long * inlen,unsigned char * to,unsigned long * tolen)5845 xmlBase64Decode(const unsigned char *in, unsigned long *inlen,
5846                 unsigned char *to, unsigned long *tolen)
5847 {
5848     unsigned long incur;        /* current index in in[] */
5849 
5850     unsigned long inblk;        /* last block index in in[] */
5851 
5852     unsigned long outcur;       /* current index in out[] */
5853 
5854     unsigned long inmax;        /* size of in[] */
5855 
5856     unsigned long outmax;       /* size of out[] */
5857 
5858     unsigned char cur;          /* the current value read from in[] */
5859 
5860     unsigned char intmp[4], outtmp[4];  /* temporary buffers for the convert */
5861 
5862     int nbintmp;                /* number of byte in intmp[] */
5863 
5864     int is_ignore;              /* cur should be ignored */
5865 
5866     int is_end = 0;             /* the end of the base64 was found */
5867 
5868     int retval = 1;
5869 
5870     int i;
5871 
5872     if ((in == NULL) || (inlen == NULL) || (to == NULL) || (tolen == NULL))
5873         return (-1);
5874 
5875     incur = 0;
5876     inblk = 0;
5877     outcur = 0;
5878     inmax = *inlen;
5879     outmax = *tolen;
5880     nbintmp = 0;
5881 
5882     while (1) {
5883         if (incur >= inmax)
5884             break;
5885         cur = in[incur++];
5886         is_ignore = 0;
5887         if ((cur >= 'A') && (cur <= 'Z'))
5888             cur = cur - 'A';
5889         else if ((cur >= 'a') && (cur <= 'z'))
5890             cur = cur - 'a' + 26;
5891         else if ((cur >= '0') && (cur <= '9'))
5892             cur = cur - '0' + 52;
5893         else if (cur == '+')
5894             cur = 62;
5895         else if (cur == '/')
5896             cur = 63;
5897         else if (cur == '.')
5898             cur = 0;
5899         else if (cur == '=')    /*no op , end of the base64 stream */
5900             is_end = 1;
5901         else {
5902             is_ignore = 1;
5903             if (nbintmp == 0)
5904                 inblk = incur;
5905         }
5906 
5907         if (!is_ignore) {
5908             int nbouttmp = 3;
5909 
5910             int is_break = 0;
5911 
5912             if (is_end) {
5913                 if (nbintmp == 0)
5914                     break;
5915                 if ((nbintmp == 1) || (nbintmp == 2))
5916                     nbouttmp = 1;
5917                 else
5918                     nbouttmp = 2;
5919                 nbintmp = 3;
5920                 is_break = 1;
5921             }
5922             intmp[nbintmp++] = cur;
5923             /*
5924              * if intmp is full, push the 4byte sequence as a 3 byte
5925              * sequence out
5926              */
5927             if (nbintmp == 4) {
5928                 nbintmp = 0;
5929                 outtmp[0] = (intmp[0] << 2) | ((intmp[1] & 0x30) >> 4);
5930                 outtmp[1] =
5931                     ((intmp[1] & 0x0F) << 4) | ((intmp[2] & 0x3C) >> 2);
5932                 outtmp[2] = ((intmp[2] & 0x03) << 6) | (intmp[3] & 0x3F);
5933                 if (outcur + 3 >= outmax) {
5934                     retval = 2;
5935                     break;
5936                 }
5937 
5938                 for (i = 0; i < nbouttmp; i++)
5939                     to[outcur++] = outtmp[i];
5940                 inblk = incur;
5941             }
5942 
5943             if (is_break) {
5944                 retval = 0;
5945                 break;
5946             }
5947         }
5948     }
5949 
5950     *tolen = outcur;
5951     *inlen = inblk;
5952     return (retval);
5953 }
5954 
5955 /*
5956  * Test routine for the xmlBase64Decode function
5957  */
5958 #if 0
5959 int
5960 main(int argc, char **argv)
5961 {
5962     char *input = "  VW4 gcGV0        \n      aXQgdGVzdCAuCg== ";
5963 
5964     char output[100];
5965 
5966     char output2[100];
5967 
5968     char output3[100];
5969 
5970     unsigned long inlen = strlen(input);
5971 
5972     unsigned long outlen = 100;
5973 
5974     int ret;
5975 
5976     unsigned long cons, tmp, tmp2, prod;
5977 
5978     /*
5979      * Direct
5980      */
5981     ret = xmlBase64Decode(input, &inlen, output, &outlen);
5982 
5983     output[outlen] = 0;
5984     printf("ret: %d, inlen: %ld , outlen: %ld, output: '%s'\n", ret, inlen,
5985            outlen, output)indent: Standard input:179: Error:Unmatched #endif
5986 ;
5987 
5988     /*
5989      * output chunking
5990      */
5991     cons = 0;
5992     prod = 0;
5993     while (cons < inlen) {
5994         tmp = 5;
5995         tmp2 = inlen - cons;
5996 
5997         printf("%ld %ld\n", cons, prod);
5998         ret = xmlBase64Decode(&input[cons], &tmp2, &output2[prod], &tmp);
5999         cons += tmp2;
6000         prod += tmp;
6001         printf("%ld %ld\n", cons, prod);
6002     }
6003     output2[outlen] = 0;
6004     printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
6005            prod, output2);
6006 
6007     /*
6008      * input chunking
6009      */
6010     cons = 0;
6011     prod = 0;
6012     while (cons < inlen) {
6013         tmp = 100 - prod;
6014         tmp2 = inlen - cons;
6015         if (tmp2 > 5)
6016             tmp2 = 5;
6017 
6018         printf("%ld %ld\n", cons, prod);
6019         ret = xmlBase64Decode(&input[cons], &tmp2, &output3[prod], &tmp);
6020         cons += tmp2;
6021         prod += tmp;
6022         printf("%ld %ld\n", cons, prod);
6023     }
6024     output3[outlen] = 0;
6025     printf("ret: %d, cons: %ld , prod: %ld, output: '%s'\n", ret, cons,
6026            prod, output3);
6027     return (0);
6028 
6029 }
6030 #endif
6031 #endif /* NOT_USED_YET */
6032 #define bottom_xmlreader
6033 #include "elfgcchack.h"
6034 #endif /* LIBXML_READER_ENABLED */
6035