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