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