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