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