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