source: trunk/third/libxml2/xmlreader.c @ 21532

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