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