source: trunk/third/libxml2/xinclude.c @ 19097

Revision 19097, 51.9 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r19096, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * xinclude.c : Code to implement XInclude processing
3 *
4 * World Wide Web Consortium W3C Last Call Working Draft 16 May 2001
5 * http://www.w3.org/TR/2001/WD-xinclude-20010516/
6 *
7 * See Copyright for the status of this software.
8 *
9 * daniel@veillard.com
10 */
11
12/*
13 * TODO: compute XPointers nodesets
14 * TODO: add an node intermediate API and handle recursion at this level
15 */
16
17#define IN_LIBXML
18#include "libxml.h"
19
20#include <string.h>
21#include <libxml/xmlmemory.h>
22#include <libxml/tree.h>
23#include <libxml/parser.h>
24#include <libxml/uri.h>
25#include <libxml/xpointer.h>
26#include <libxml/parserInternals.h>
27#include <libxml/xmlerror.h>
28#include <libxml/encoding.h>
29#include <libxml/globals.h>
30
31#ifdef LIBXML_XINCLUDE_ENABLED
32#include <libxml/xinclude.h>
33
34#define XINCLUDE_NS (const xmlChar *) "http://www.w3.org/2001/XInclude"
35#define XINCLUDE_NODE (const xmlChar *) "include"
36#define XINCLUDE_FALLBACK (const xmlChar *) "fallback"
37#define XINCLUDE_HREF (const xmlChar *) "href"
38#define XINCLUDE_PARSE (const xmlChar *) "parse"
39#define XINCLUDE_PARSE_XML (const xmlChar *) "xml"
40#define XINCLUDE_PARSE_TEXT (const xmlChar *) "text"
41#define XINCLUDE_PARSE_ENCODING (const xmlChar *) "encoding"
42
43#define XINCLUDE_MAX_DEPTH 40
44
45/* #define DEBUG_XINCLUDE  */
46#ifdef DEBUG_XINCLUDE
47#ifdef LIBXML_DEBUG_ENABLED
48#include <libxml/debugXML.h>
49#endif
50#endif
51
52/************************************************************************
53 *                                                                      *
54 *                      XInclude contexts handling                      *
55 *                                                                      *
56 ************************************************************************/
57
58/*
59 * An XInclude context
60 */
61typedef xmlChar *xmlURL;
62
63typedef struct _xmlXIncludeRef xmlXIncludeRef;
64typedef xmlXIncludeRef *xmlXIncludeRefPtr;
65struct _xmlXIncludeRef {
66    xmlChar              *URI; /* the rully resolved resource URL */
67    xmlChar         *fragment; /* the fragment in the URI */
68    xmlDocPtr             doc; /* the parsed document */
69    xmlNodePtr            ref; /* the node making the reference in the source */
70    xmlNodePtr            inc; /* the included copy */
71    int                   xml; /* xml or txt */
72    int                 count; /* how many refs use that specific doc */
73    xmlXPathObjectPtr    xptr; /* the xpointer if needed */
74};
75
76typedef struct _xmlXIncludeCtxt xmlXIncludeCtxt;
77typedef xmlXIncludeCtxt *xmlXIncludeCtxtPtr;
78struct _xmlXIncludeCtxt {
79    xmlDocPtr             doc; /* the source document */
80    int               incBase; /* the first include for this document */
81    int                 incNr; /* number of includes */
82    int                incMax; /* size of includes tab */
83    xmlXIncludeRefPtr *incTab; /* array of included references */
84
85    int                 txtNr; /* number of unparsed documents */
86    int                txtMax; /* size of unparsed documents tab */
87    xmlNodePtr        *txtTab; /* array of unparsed text nodes */
88    xmlURL         *txturlTab; /* array of unparsed txtuments URLs */
89
90    xmlChar *             url; /* the current URL processed */
91    int                 urlNr; /* number of url stacked */
92    int                urlMax; /* size of url stack */
93    xmlChar *         *urlTab; /* url stack */
94
95    int              nbErrors; /* the number of errors detected */
96};
97
98static int
99xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc);
100
101/**
102 * xmlXIncludeFreeRef:
103 * @ref: the XInclude reference
104 *
105 * Free an XInclude reference
106 */
107static void
108xmlXIncludeFreeRef(xmlXIncludeRefPtr ref) {
109    if (ref == NULL)
110        return;
111#ifdef DEBUG_XINCLUDE
112    xmlGenericError(xmlGenericErrorContext, "Freeing ref\n");
113#endif
114    if (ref->doc != NULL) {
115#ifdef DEBUG_XINCLUDE
116        xmlGenericError(xmlGenericErrorContext, "Freeing doc %s\n", ref->URI);
117#endif
118        xmlFreeDoc(ref->doc);
119    }
120    if (ref->URI != NULL)
121        xmlFree(ref->URI);
122    if (ref->fragment != NULL)
123        xmlFree(ref->fragment);
124    if (ref->xptr != NULL)
125        xmlXPathFreeObject(ref->xptr);
126    xmlFree(ref);
127}
128
129/**
130 * xmlXIncludeNewRef:
131 * @ctxt: the XInclude context
132 * @URI:  the resource URI
133 *
134 * Creates a new reference within an XInclude context
135 *
136 * Returns the new set
137 */
138static xmlXIncludeRefPtr
139xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt, const xmlChar *URI,
140                  xmlNodePtr ref) {
141    xmlXIncludeRefPtr ret;
142
143#ifdef DEBUG_XINCLUDE
144    xmlGenericError(xmlGenericErrorContext, "New ref %s\n", URI);
145#endif
146    ret = (xmlXIncludeRefPtr) xmlMalloc(sizeof(xmlXIncludeRef));
147    if (ret == NULL)
148        return(NULL);
149    memset(ret, 0, sizeof(xmlXIncludeRef));
150    if (URI == NULL)
151        ret->URI = NULL;
152    else
153        ret->URI = xmlStrdup(URI);
154    ret->fragment = NULL;
155    ret->ref = ref;
156    ret->doc = 0;
157    ret->count = 0;
158    ret->xml = 0;
159    ret->inc = NULL;
160    if (ctxt->incMax == 0) {
161        ctxt->incMax = 4;
162        ctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(ctxt->incMax *
163                                              sizeof(ctxt->incTab[0]));
164        if (ctxt->incTab == NULL) {
165            xmlGenericError(xmlGenericErrorContext,
166                    "malloc failed !\n");
167            ctxt->nbErrors++;
168            xmlXIncludeFreeRef(ret);
169            return(NULL);
170        }
171    }
172    if (ctxt->incNr >= ctxt->incMax) {
173        ctxt->incMax *= 2;
174        ctxt->incTab = (xmlXIncludeRefPtr *) xmlRealloc(ctxt->incTab,
175                     ctxt->incMax * sizeof(ctxt->incTab[0]));
176        if (ctxt->incTab == NULL) {
177            xmlGenericError(xmlGenericErrorContext,
178                    "realloc failed !\n");
179            xmlXIncludeFreeRef(ret);
180            return(NULL);
181        }
182    }
183    ctxt->incTab[ctxt->incNr++] = ret;
184    return(ret);
185}
186
187/**
188 * xmlXIncludeNewContext:
189 * @doc:  an XML Document
190 *
191 * Creates a new XInclude context
192 *
193 * Returns the new set
194 */
195static xmlXIncludeCtxtPtr
196xmlXIncludeNewContext(xmlDocPtr doc) {
197    xmlXIncludeCtxtPtr ret;
198
199#ifdef DEBUG_XINCLUDE
200    xmlGenericError(xmlGenericErrorContext, "New context\n");
201#endif
202    if (doc == NULL)
203        return(NULL);
204    ret = (xmlXIncludeCtxtPtr) xmlMalloc(sizeof(xmlXIncludeCtxt));
205    if (ret == NULL)
206        return(NULL);
207    memset(ret, 0, sizeof(xmlXIncludeCtxt));
208    ret->doc = doc;
209    ret->incNr = 0;
210    ret->incBase = 0;
211    ret->incMax = 0;
212    ret->incTab = NULL;
213    ret->nbErrors = 0;
214    return(ret);
215}
216
217/**
218 * xmlXIncludeURLPush:
219 * @ctxt:  the parser context
220 * @value:  the url
221 *
222 * Pushes a new url on top of the url stack
223 *
224 * Returns -1 in case of error, the index in the stack otherwise
225 */
226static int
227xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,
228                   const xmlChar *value)
229{
230    if (ctxt->urlNr > XINCLUDE_MAX_DEPTH) {
231        xmlGenericError(xmlGenericErrorContext,
232            "XInclude: detected a recursion in %s\n",
233                        value);
234        ctxt->nbErrors++;
235        return(-1);
236    }
237    if (ctxt->urlTab == NULL) {
238        ctxt->urlMax = 4;
239        ctxt->urlNr = 0;
240        ctxt->urlTab = (xmlChar * *) xmlMalloc(
241                        ctxt->urlMax * sizeof(ctxt->urlTab[0]));
242        if (ctxt->urlTab == NULL) {
243            xmlGenericError(xmlGenericErrorContext, "malloc failed !\n");
244            return (-1);
245        }
246    }
247    if (ctxt->urlNr >= ctxt->urlMax) {
248        ctxt->urlMax *= 2;
249        ctxt->urlTab =
250            (xmlChar * *) xmlRealloc(ctxt->urlTab,
251                                      ctxt->urlMax *
252                                      sizeof(ctxt->urlTab[0]));
253        if (ctxt->urlTab == NULL) {
254            xmlGenericError(xmlGenericErrorContext, "realloc failed !\n");
255            return (-1);
256        }
257    }
258    ctxt->url = ctxt->urlTab[ctxt->urlNr] = xmlStrdup(value);
259    return (ctxt->urlNr++);
260}
261
262/**
263 * xmlXIncludeURLPop:
264 * @ctxt: the parser context
265 *
266 * Pops the top url from the url stack
267 */
268static void
269xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)
270{
271    xmlChar * ret;
272
273    if (ctxt->urlNr <= 0)
274        return;
275    ctxt->urlNr--;
276    if (ctxt->urlNr > 0)
277        ctxt->url = ctxt->urlTab[ctxt->urlNr - 1];
278    else
279        ctxt->url = NULL;
280    ret = ctxt->urlTab[ctxt->urlNr];
281    ctxt->urlTab[ctxt->urlNr] = 0;
282    if (ret != NULL)
283        xmlFree(ret);
284}
285
286/**
287 * xmlXIncludeFreeContext:
288 * @ctxt: the XInclude context
289 *
290 * Free an XInclude context
291 */
292static void
293xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt) {
294    int i;
295
296#ifdef DEBUG_XINCLUDE
297    xmlGenericError(xmlGenericErrorContext, "Freeing context\n");
298#endif
299    if (ctxt == NULL)
300        return;
301    while (ctxt->urlNr > 0)
302        xmlXIncludeURLPop(ctxt);
303    if (ctxt->urlTab != NULL)
304        xmlFree(ctxt->urlTab);
305    for (i = 0;i < ctxt->incNr;i++) {
306        if (ctxt->incTab[i] != NULL)
307            xmlXIncludeFreeRef(ctxt->incTab[i]);
308    }
309    for (i = 0;i < ctxt->txtNr;i++) {
310        if (ctxt->txturlTab[i] != NULL)
311            xmlFree(ctxt->txturlTab[i]);
312    }
313    if (ctxt->incTab != NULL)
314        xmlFree(ctxt->incTab);
315    if (ctxt->txtTab != NULL)
316        xmlFree(ctxt->txtTab);
317    if (ctxt->txturlTab != NULL)
318        xmlFree(ctxt->txturlTab);
319    xmlFree(ctxt);
320}
321
322/**
323 * xmlXIncludeAddNode:
324 * @ctxt:  the XInclude context
325 * @cur:  the new node
326 *
327 * Add a new node to process to an XInclude context
328 */
329static int
330xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr cur) {
331    xmlXIncludeRefPtr ref;
332    xmlURIPtr uri;
333    xmlChar *URL;
334    xmlChar *fragment = NULL;
335    xmlChar *href;
336    xmlChar *parse;
337    xmlChar *base;
338    xmlChar *URI;
339    int xml = 1, i; /* default Issue 64 */
340    int local = 0;
341
342
343    if (ctxt == NULL)
344        return(-1);
345    if (cur == NULL)
346        return(-1);
347
348#ifdef DEBUG_XINCLUDE
349    xmlGenericError(xmlGenericErrorContext, "Add node\n");
350#endif
351    /*
352     * read the attributes
353     */
354    href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
355    if (href == NULL) {
356        href = xmlGetProp(cur, XINCLUDE_HREF);
357        if (href == NULL) {
358            xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
359            ctxt->nbErrors++;
360            return(-1);
361        }
362    }
363    if (href[0] == '#')
364        local = 1;
365    parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
366    if (parse == NULL) {
367        parse = xmlGetProp(cur, XINCLUDE_PARSE);
368    }
369    if (parse != NULL) {
370        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
371            xml = 1;
372        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
373            xml = 0;
374        else {
375            xmlGenericError(xmlGenericErrorContext,
376                    "XInclude: invalid value %s for %s\n",
377                            parse, XINCLUDE_PARSE);
378            ctxt->nbErrors++;
379            if (href != NULL)
380                xmlFree(href);
381            if (parse != NULL)
382                xmlFree(parse);
383            return(-1);
384        }
385    }
386
387    /*
388     * compute the URI
389     */
390    base = xmlNodeGetBase(ctxt->doc, cur);
391    if (base == NULL) {
392        URI = xmlBuildURI(href, ctxt->doc->URL);
393    } else {
394        URI = xmlBuildURI(href, base);
395    }
396    if (URI == NULL) {
397        xmlChar *escbase;
398        xmlChar *eschref;
399        /*
400         * Some escaping may be needed
401         */
402        escbase = xmlURIEscape(base);
403        eschref = xmlURIEscape(href);
404        URI = xmlBuildURI(eschref, escbase);
405        if (escbase != NULL)
406            xmlFree(escbase);
407        if (eschref != NULL)
408            xmlFree(eschref);
409    }
410    if (parse != NULL)
411        xmlFree(parse);
412    if (href != NULL)
413        xmlFree(href);
414    if (base != NULL)
415        xmlFree(base);
416    if (URI == NULL) {
417        xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
418        ctxt->nbErrors++;
419        return(-1);
420    }
421
422    /*
423     * Check the URL and remove any fragment identifier
424     */
425    uri = xmlParseURI((const char *)URI);
426    if (uri == NULL) {
427        xmlGenericError(xmlGenericErrorContext,
428                    "XInclude: invalid value URI %s\n", URI);
429        ctxt->nbErrors++;
430        return(-1);
431    }
432    if (uri->fragment != NULL) {
433        fragment = (xmlChar *) uri->fragment;
434        uri->fragment = NULL;
435    }
436    URL = xmlSaveUri(uri);
437    xmlFreeURI(uri);
438    xmlFree(URI);
439    if (URL == NULL) {
440        xmlGenericError(xmlGenericErrorContext,
441                    "XInclude: invalid value URI %s\n", URI);
442        ctxt->nbErrors++;
443        if (fragment != NULL)
444            xmlFree(fragment);
445        return(-1);
446    }
447
448    /*
449     * Check the URL against the stack for recursions
450     */
451    if (!local) {
452        for (i = 0;i < ctxt->urlNr;i++) {
453            if (xmlStrEqual(URL, ctxt->urlTab[i])) {
454                xmlGenericError(xmlGenericErrorContext,
455                    "XInclude: detected a recursion in %s\n",
456                                URL);
457                ctxt->nbErrors++;
458                return(-1);
459            }
460        }
461    }
462
463    ref = xmlXIncludeNewRef(ctxt, URL, cur);
464    if (ref == NULL) {
465        return(-1);
466    }
467    ref->fragment = fragment;
468    ref->doc = NULL;
469    ref->xml = xml;
470    ref->count = 1;
471    xmlFree(URL);
472    return(0);
473}
474
475/**
476 * xmlXIncludeRecurseDoc:
477 * @ctxt:  the XInclude context
478 * @doc:  the new document
479 * @url:  the associated URL
480 *
481 * The XInclude recursive nature is handled at this point.
482 */
483static void
484xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
485                      const xmlURL url ATTRIBUTE_UNUSED) {
486    xmlXIncludeCtxtPtr newctxt;
487    int i;
488
489    /*
490     * Avoid recursion in already substitued resources
491    for (i = 0;i < ctxt->urlNr;i++) {
492        if (xmlStrEqual(doc->URL, ctxt->urlTab[i]))
493            return;
494    }
495     */
496
497#ifdef DEBUG_XINCLUDE
498    xmlGenericError(xmlGenericErrorContext, "Recursing in doc %s\n", doc->URL);
499#endif
500    /*
501     * Handle recursion here.
502     */
503
504    newctxt = xmlXIncludeNewContext(doc);
505    if (newctxt != NULL) {
506        /*
507         * Copy the existing document set
508         */
509        newctxt->incMax = ctxt->incMax;
510        newctxt->incNr = ctxt->incNr;
511        newctxt->incTab = (xmlXIncludeRefPtr *) xmlMalloc(newctxt->incMax *
512                                          sizeof(newctxt->incTab[0]));
513        if (newctxt->incTab == NULL) {
514            xmlGenericError(xmlGenericErrorContext,
515                    "malloc failed !\n");
516            ctxt->nbErrors++;
517            xmlFree(newctxt);
518            return;
519        }
520        /*
521         * copy the urlTab
522         */
523        newctxt->urlMax = ctxt->urlMax;
524        newctxt->urlNr = ctxt->urlNr;
525        newctxt->urlTab = ctxt->urlTab;
526
527        /*
528         * Inherit the documents already in use by others includes
529         */
530        newctxt->incBase = ctxt->incNr;
531        for (i = 0;i < ctxt->incNr;i++) {
532            newctxt->incTab[i] = ctxt->incTab[i];
533            newctxt->incTab[i]->count++; /* prevent the recursion from
534                                            freeing it */
535        }
536        xmlXIncludeDoProcess(newctxt, doc);
537        for (i = 0;i < ctxt->incNr;i++) {
538            newctxt->incTab[i]->count--;
539            newctxt->incTab[i] = NULL;
540        }
541        newctxt->urlMax = 0;
542        newctxt->urlNr = 0;
543        newctxt->urlTab = NULL;
544
545        xmlXIncludeFreeContext(newctxt);
546    }
547#ifdef DEBUG_XINCLUDE
548    xmlGenericError(xmlGenericErrorContext, "Done recursing in doc %s\n", url);
549#endif
550}
551
552/**
553 * xmlXIncludeAddTxt:
554 * @ctxt:  the XInclude context
555 * @txt:  the new text node
556 * @url:  the associated URL
557 *
558 * Add a new txtument to the list
559 */
560static void
561xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
562#ifdef DEBUG_XINCLUDE
563    xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
564#endif
565    if (ctxt->txtMax == 0) {
566        ctxt->txtMax = 4;
567        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
568                                          sizeof(ctxt->txtTab[0]));
569        if (ctxt->txtTab == NULL) {
570            xmlGenericError(xmlGenericErrorContext,
571                    "malloc failed !\n");
572            ctxt->nbErrors++;
573            return;
574        }
575        ctxt->txturlTab = (xmlURL *) xmlMalloc(ctxt->txtMax *
576                                          sizeof(ctxt->txturlTab[0]));
577        if (ctxt->txturlTab == NULL) {
578            xmlGenericError(xmlGenericErrorContext,
579                    "malloc failed !\n");
580            ctxt->nbErrors++;
581            return;
582        }
583    }
584    if (ctxt->txtNr >= ctxt->txtMax) {
585        ctxt->txtMax *= 2;
586        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
587                     ctxt->txtMax * sizeof(ctxt->txtTab[0]));
588        if (ctxt->txtTab == NULL) {
589            xmlGenericError(xmlGenericErrorContext,
590                    "realloc failed !\n");
591            ctxt->nbErrors++;
592            return;
593        }
594        ctxt->txturlTab = (xmlURL *) xmlRealloc(ctxt->txturlTab,
595                     ctxt->txtMax * sizeof(ctxt->txturlTab[0]));
596        if (ctxt->txturlTab == NULL) {
597            xmlGenericError(xmlGenericErrorContext,
598                    "realloc failed !\n");
599            ctxt->nbErrors++;
600            return;
601        }
602    }
603    ctxt->txtTab[ctxt->txtNr] = txt;
604    ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
605    ctxt->txtNr++;
606}
607
608/************************************************************************
609 *                                                                      *
610 *                      Node copy with specific semantic                *
611 *                                                                      *
612 ************************************************************************/
613
614/**
615 * xmlXIncludeCopyNode:
616 * @ctxt:  the XInclude context
617 * @target:  the document target
618 * @source:  the document source
619 * @elem:  the element
620 *
621 * Make a copy of the node while preserving the XInclude semantic
622 * of the Infoset copy
623 */
624static xmlNodePtr
625xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
626                    xmlDocPtr source, xmlNodePtr elem) {
627    xmlNodePtr result = NULL;
628
629    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
630        (elem == NULL))
631        return(NULL);
632    if (elem->type == XML_DTD_NODE)
633        return(NULL);
634    result = xmlDocCopyNode(elem, target, 1);
635    return(result);
636}
637
638/**
639 * xmlXIncludeCopyNodeList:
640 * @ctxt:  the XInclude context
641 * @target:  the document target
642 * @source:  the document source
643 * @elem:  the element list
644 *
645 * Make a copy of the node list while preserving the XInclude semantic
646 * of the Infoset copy
647 */
648static xmlNodePtr
649xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
650                        xmlDocPtr source, xmlNodePtr elem) {
651    xmlNodePtr cur, res, result = NULL, last = NULL;
652
653    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
654        (elem == NULL))
655        return(NULL);
656    cur = elem;
657    while (cur != NULL) {
658        res = xmlXIncludeCopyNode(ctxt, target, source, cur);
659        if (res != NULL) {
660            if (result == NULL) {
661                result = last = res;
662            } else {
663                last->next = res;
664                res->prev = last;
665                last = res;
666            }
667        }
668        cur = cur->next;
669    }
670    return(result);
671}
672
673/**
674 * xmlXInclueGetNthChild:
675 * @cur:  the node
676 * @no:  the child number
677 *
678 * Returns the @no'th element child of @cur or NULL
679 */
680static xmlNodePtr
681xmlXIncludeGetNthChild(xmlNodePtr cur, int no) {
682    int i;
683    if (cur == NULL)
684        return(cur);
685    cur = cur->children;
686    for (i = 0;i <= no;cur = cur->next) {
687        if (cur == NULL)
688            return(cur);
689        if ((cur->type == XML_ELEMENT_NODE) ||
690            (cur->type == XML_DOCUMENT_NODE) ||
691            (cur->type == XML_HTML_DOCUMENT_NODE)) {
692            i++;
693            if (i == no)
694                break;
695        }
696    }
697    return(cur);
698}
699
700xmlNodePtr xmlXPtrAdvanceNode(xmlNodePtr cur);
701
702/**
703 * xmlXIncludeCopyRange:
704 * @ctxt:  the XInclude context
705 * @target:  the document target
706 * @source:  the document source
707 * @obj:  the XPointer result from the evaluation.
708 *
709 * Build a node list tree copy of the XPointer result.
710 *
711 * Returns an xmlNodePtr list or NULL.
712 *         the caller has to free the node tree.
713 */
714static xmlNodePtr
715xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
716                        xmlDocPtr source, xmlXPathObjectPtr range) {
717    /* pointers to generated nodes */
718    xmlNodePtr list = NULL, last = NULL, parent = NULL, tmp;
719    /* pointers to traversal nodes */
720    xmlNodePtr start, cur, end;
721    int index1, index2;
722
723    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
724        (range == NULL))
725        return(NULL);
726    if (range->type != XPATH_RANGE)
727        return(NULL);
728    start = (xmlNodePtr) range->user;
729
730    if (start == NULL)
731        return(NULL);
732    end = range->user2;
733    if (end == NULL)
734        return(xmlDocCopyNode(start, target, 1));
735
736    cur = start;
737    index1 = range->index;
738    index2 = range->index2;
739    while (cur != NULL) {
740        if (cur == end) {
741            if (cur->type == XML_TEXT_NODE) {
742                const xmlChar *content = cur->content;
743                int len;
744
745                if (content == NULL) {
746                    tmp = xmlNewTextLen(NULL, 0);
747                } else {
748                    len = index2;
749                    if ((cur == start) && (index1 > 1)) {
750                        content += (index1 - 1);
751                        len -= (index1 - 1);
752                        index1 = 0;
753                    } else {
754                        len = index2;
755                    }
756                    tmp = xmlNewTextLen(content, len);
757                }
758                /* single sub text node selection */
759                if (list == NULL)
760                    return(tmp);
761                /* prune and return full set */
762                if (last != NULL)
763                    xmlAddNextSibling(last, tmp);
764                else
765                    xmlAddChild(parent, tmp);
766                return(list);
767            } else {
768                tmp = xmlDocCopyNode(cur, target, 0);
769                if (list == NULL)
770                    list = tmp;
771                else {
772                    if (last != NULL)
773                        xmlAddNextSibling(last, tmp);
774                    else
775                        xmlAddChild(parent, tmp);
776                }
777                last = NULL;
778                parent = tmp;
779
780                if (index2 > 1) {
781                    end = xmlXIncludeGetNthChild(cur, index2 - 1);
782                    index2 = 0;
783                }
784                if ((cur == start) && (index1 > 1)) {
785                    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
786                    index1 = 0;
787                } else {
788                    cur = cur->children;
789                }
790                /*
791                 * Now gather the remaining nodes from cur to end
792                 */
793                continue; /* while */
794            }
795        } else if ((cur == start) &&
796                   (list == NULL) /* looks superfluous but ... */ ) {
797            if ((cur->type == XML_TEXT_NODE) ||
798                (cur->type == XML_CDATA_SECTION_NODE)) {
799                const xmlChar *content = cur->content;
800
801                if (content == NULL) {
802                    tmp = xmlNewTextLen(NULL, 0);
803                } else {
804                    if (index1 > 1) {
805                        content += (index1 - 1);
806                    }
807                    tmp = xmlNewText(content);
808                }
809                last = list = tmp;
810            } else {
811                if ((cur == start) && (index1 > 1)) {
812                    tmp = xmlDocCopyNode(cur, target, 0);
813                    list = tmp;
814                    parent = tmp;
815                    last = NULL;
816                    cur = xmlXIncludeGetNthChild(cur, index1 - 1);
817                    index1 = 0;
818                    /*
819                     * Now gather the remaining nodes from cur to end
820                     */
821                    continue; /* while */
822                }
823                tmp = xmlDocCopyNode(cur, target, 1);
824                list = tmp;
825                parent = NULL;
826                last = tmp;
827            }
828        } else {
829            tmp = NULL;
830            switch (cur->type) {
831                case XML_DTD_NODE:
832                case XML_ELEMENT_DECL:
833                case XML_ATTRIBUTE_DECL:
834                case XML_ENTITY_NODE:
835                    /* Do not copy DTD informations */
836                    break;
837                case XML_ENTITY_DECL:
838                    /* handle crossing entities -> stack needed */
839                    break;
840                case XML_XINCLUDE_START:
841                case XML_XINCLUDE_END:
842                    /* don't consider it part of the tree content */
843                    break;
844                case XML_ATTRIBUTE_NODE:
845                    /* Humm, should not happen ! */
846                    break;
847                default:
848                    tmp = xmlDocCopyNode(cur, target, 1);
849                    break;
850            }
851            if (tmp != NULL) {
852                if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
853                    return(NULL);
854                }
855                if (last != NULL)
856                    xmlAddNextSibling(last, tmp);
857                else {
858                    xmlAddChild(parent, tmp);
859                    last = tmp;
860                }
861            }
862        }
863        /*
864         * Skip to next node in document order
865         */
866        if ((list == NULL) || ((last == NULL) && (parent == NULL)))  {
867            return(NULL);
868        }
869        cur = xmlXPtrAdvanceNode(cur);
870    }
871    return(list);
872}
873
874/**
875 * xmlXIncludeBuildNodeList:
876 * @ctxt:  the XInclude context
877 * @target:  the document target
878 * @source:  the document source
879 * @obj:  the XPointer result from the evaluation.
880 *
881 * Build a node list tree copy of the XPointer result.
882 * This will drop Attributes and Namespace declarations.
883 *
884 * Returns an xmlNodePtr list or NULL.
885 *         the caller has to free the node tree.
886 */
887static xmlNodePtr
888xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt, xmlDocPtr target,
889                        xmlDocPtr source, xmlXPathObjectPtr obj) {
890    xmlNodePtr list = NULL, last = NULL;
891    int i;
892
893    if (source == NULL)
894        source = ctxt->doc;
895    if ((ctxt == NULL) || (target == NULL) || (source == NULL) ||
896        (obj == NULL))
897        return(NULL);
898    switch (obj->type) {
899        case XPATH_NODESET: {
900            xmlNodeSetPtr set = obj->nodesetval;
901            if (set == NULL)
902                return(NULL);
903            for (i = 0;i < set->nodeNr;i++) {
904                if (set->nodeTab[i] == NULL)
905                    continue;
906                switch (set->nodeTab[i]->type) {
907                    case XML_TEXT_NODE:
908                    case XML_CDATA_SECTION_NODE:
909                    case XML_ELEMENT_NODE:
910                    case XML_ENTITY_REF_NODE:
911                    case XML_ENTITY_NODE:
912                    case XML_PI_NODE:
913                    case XML_COMMENT_NODE:
914                    case XML_DOCUMENT_NODE:
915                    case XML_HTML_DOCUMENT_NODE:
916#ifdef LIBXML_DOCB_ENABLED
917                    case XML_DOCB_DOCUMENT_NODE:
918#endif
919                    case XML_XINCLUDE_END:
920                        break;
921                    case XML_XINCLUDE_START: {
922                        xmlNodePtr tmp, cur = set->nodeTab[i];
923
924                        cur = cur->next;
925                        while (cur != NULL) {
926                            switch(cur->type) {
927                                case XML_TEXT_NODE:
928                                case XML_CDATA_SECTION_NODE:
929                                case XML_ELEMENT_NODE:
930                                case XML_ENTITY_REF_NODE:
931                                case XML_ENTITY_NODE:
932                                case XML_PI_NODE:
933                                case XML_COMMENT_NODE:
934                                    tmp = xmlXIncludeCopyNode(ctxt, target,
935                                                              source, cur);
936                                    if (last == NULL) {
937                                        list = last = tmp;
938                                    } else {
939                                        xmlAddNextSibling(last, tmp);
940                                        last = tmp;
941                                    }
942                                    cur = cur->next;
943                                    continue;
944                                default:
945                                    break;
946                            }
947                            break;
948                        }
949                        continue;
950                    }
951                    case XML_ATTRIBUTE_NODE:
952                    case XML_NAMESPACE_DECL:
953                    case XML_DOCUMENT_TYPE_NODE:
954                    case XML_DOCUMENT_FRAG_NODE:
955                    case XML_NOTATION_NODE:
956                    case XML_DTD_NODE:
957                    case XML_ELEMENT_DECL:
958                    case XML_ATTRIBUTE_DECL:
959                    case XML_ENTITY_DECL:
960                        continue; /* for */
961                }
962                if (last == NULL)
963                    list = last = xmlXIncludeCopyNode(ctxt, target, source,
964                                                      set->nodeTab[i]);
965                else {
966                    xmlAddNextSibling(last,
967                            xmlXIncludeCopyNode(ctxt, target, source,
968                                                set->nodeTab[i]));
969                    if (last->next != NULL)
970                        last = last->next;
971                }
972            }
973            break;
974        }
975        case XPATH_LOCATIONSET: {
976            xmlLocationSetPtr set = (xmlLocationSetPtr) obj->user;
977            if (set == NULL)
978                return(NULL);
979            for (i = 0;i < set->locNr;i++) {
980                if (last == NULL)
981                    list = last = xmlXIncludeCopyXPointer(ctxt, target, source,
982                                                          set->locTab[i]);
983                else
984                    xmlAddNextSibling(last,
985                            xmlXIncludeCopyXPointer(ctxt, target, source,
986                                                    set->locTab[i]));
987                if (last != NULL) {
988                    while (last->next != NULL)
989                        last = last->next;
990                }
991            }
992            break;
993        }
994        case XPATH_RANGE:
995            return(xmlXIncludeCopyRange(ctxt, target, source, obj));
996        case XPATH_POINT:
997            /* points are ignored in XInclude */
998            break;
999        default:
1000            break;
1001    }
1002    return(list);
1003}
1004/************************************************************************
1005 *                                                                      *
1006 *                      XInclude I/O handling                           *
1007 *                                                                      *
1008 ************************************************************************/
1009
1010typedef struct _xmlXIncludeMergeData xmlXIncludeMergeData;
1011typedef xmlXIncludeMergeData *xmlXIncludeMergeDataPtr;
1012struct _xmlXIncludeMergeData {
1013    xmlDocPtr doc;
1014    xmlXIncludeCtxtPtr ctxt;
1015};
1016
1017/**
1018 * xmlXIncludeMergeOneEntity:
1019 * @ent: the entity
1020 * @doc:  the including doc
1021 * @nr: the entity name
1022 *
1023 * Inplements the merge of one entity
1024 */
1025static void
1026xmlXIncludeMergeEntity(xmlEntityPtr ent, xmlXIncludeMergeDataPtr data,
1027                       xmlChar *name ATTRIBUTE_UNUSED) {
1028    xmlEntityPtr ret, prev;
1029    xmlDocPtr doc;
1030    xmlXIncludeCtxtPtr ctxt;
1031
1032    if ((ent == NULL) || (data == NULL))
1033        return;
1034    ctxt = data->ctxt;
1035    doc = data->doc;
1036    if ((ctxt == NULL) || (doc == NULL))
1037        return;
1038    switch (ent->etype) {
1039        case XML_INTERNAL_PARAMETER_ENTITY:
1040        case XML_EXTERNAL_PARAMETER_ENTITY:
1041        case XML_INTERNAL_PREDEFINED_ENTITY:
1042            return;
1043        case XML_INTERNAL_GENERAL_ENTITY:
1044        case XML_EXTERNAL_GENERAL_PARSED_ENTITY:
1045        case XML_EXTERNAL_GENERAL_UNPARSED_ENTITY:
1046            break;
1047    }
1048    ret = xmlAddDocEntity(doc, ent->name, ent->etype, ent->ExternalID,
1049                          ent->SystemID, ent->content);
1050    if (ret != NULL) {
1051        if (ent->URI != NULL)
1052            ret->URI = xmlStrdup(ent->URI);
1053    } else {
1054        prev = xmlGetDocEntity(doc, ent->name);
1055        if (prev != NULL) {
1056            if (ent->etype != prev->etype)
1057                goto error;
1058       
1059            if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1060                if (!xmlStrEqual(ent->SystemID, prev->SystemID))
1061                    goto error;
1062            } else if ((ent->SystemID != NULL) && (prev->SystemID != NULL)) {
1063                if (!xmlStrEqual(ent->ExternalID, prev->ExternalID))
1064                    goto error;
1065            } else if ((ent->content != NULL) && (prev->content != NULL)) {
1066                if (!xmlStrEqual(ent->content, prev->content))
1067                    goto error;
1068            } else {
1069                goto error;
1070            }
1071
1072        }
1073    }
1074    return;
1075error:
1076    xmlGenericError(xmlGenericErrorContext,
1077                "XInclude: mismatch in redefinition of entity %s\n", ent->name);
1078    ctxt->nbErrors++;
1079}
1080
1081/**
1082 * xmlXIncludeMergeEntities:
1083 * @ctxt: an XInclude context
1084 * @doc:  the including doc
1085 * @from:  the included doc
1086 *
1087 * Inplements the entity merge
1088 *
1089 * Returns 0 if merge succeeded, -1 if some processing failed
1090 */
1091static int
1092xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc,
1093                         xmlDocPtr from) {
1094    xmlNodePtr cur;
1095    xmlDtdPtr target, source;
1096
1097    if (ctxt == NULL)
1098        return(-1);
1099
1100    if ((from == NULL) || (from->intSubset == NULL))
1101        return(0);
1102
1103    target = doc->intSubset;
1104    if (target == NULL) {
1105        cur = xmlDocGetRootElement(doc);
1106        if (cur == NULL)
1107            return(-1);
1108        target = xmlCreateIntSubset(doc, cur->name, NULL, NULL);
1109        if (target == NULL)
1110            return(-1);
1111    }
1112
1113    source = from->intSubset;
1114    if ((source != NULL) && (source->entities != NULL)) {
1115        xmlXIncludeMergeData data;
1116
1117        data.ctxt = ctxt;
1118        data.doc = doc;
1119
1120        xmlHashScan((xmlHashTablePtr) source->entities,
1121                    (xmlHashScanner) xmlXIncludeMergeEntity, &data);
1122    }
1123    source = from->extSubset;
1124    if ((source != NULL) && (source->entities != NULL)) {
1125        xmlXIncludeMergeData data;
1126
1127        data.ctxt = ctxt;
1128        data.doc = doc;
1129
1130        /*
1131         * don't duplicate existing stuff when external subsets are the same
1132         */
1133        if ((!xmlStrEqual(target->ExternalID, source->ExternalID)) &&
1134            (!xmlStrEqual(target->SystemID, source->SystemID))) {
1135            xmlHashScan((xmlHashTablePtr) source->entities,
1136                        (xmlHashScanner) xmlXIncludeMergeEntity, &data);
1137        }
1138    }
1139    return(0);
1140}
1141
1142/**
1143 * xmlXIncludeLoadDoc:
1144 * @ctxt:  the XInclude context
1145 * @url:  the associated URL
1146 * @nr:  the xinclude node number
1147 *
1148 * Load the document, and store the result in the XInclude context
1149 *
1150 * Returns 0 in case of success, -1 in case of failure
1151 */
1152static int
1153xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1154    xmlDocPtr doc;
1155    xmlURIPtr uri;
1156    xmlChar *URL;
1157    xmlChar *fragment = NULL;
1158    int i = 0;
1159
1160#ifdef DEBUG_XINCLUDE
1161    xmlGenericError(xmlGenericErrorContext, "Loading doc %s:%d\n", url, nr);
1162#endif
1163    /*
1164     * Check the URL and remove any fragment identifier
1165     */
1166    uri = xmlParseURI((const char *)url);
1167    if (uri == NULL) {
1168        xmlGenericError(xmlGenericErrorContext,
1169                    "XInclude: invalid value URI %s\n", url);
1170        ctxt->nbErrors++;
1171        return(-1);
1172    }
1173    if (uri->fragment != NULL) {
1174        fragment = (xmlChar *) uri->fragment;
1175        uri->fragment = NULL;
1176    }
1177    URL = xmlSaveUri(uri);
1178    xmlFreeURI(uri);
1179    if (URL == NULL) {
1180        xmlGenericError(xmlGenericErrorContext,
1181                    "XInclude: invalid value URI %s\n", url);
1182        ctxt->nbErrors++;
1183        if (fragment != NULL)
1184            xmlFree(fragment);
1185        return(-1);
1186    }
1187
1188    /*
1189     * Handling of references to the local document are done
1190     * directly through ctxt->doc.
1191     */
1192    if ((URL[0] == 0) || (URL[0] == '#') ||
1193        ((ctxt->doc != NULL) && (xmlStrEqual(URL, ctxt->doc->URL)))) {
1194        doc = NULL;
1195        goto loaded;
1196    }
1197
1198    /*
1199     * Prevent reloading twice the document.
1200     */
1201    for (i = 0; i < ctxt->incNr; i++) {
1202        if ((xmlStrEqual(URL, ctxt->incTab[i]->URI)) &&
1203            (ctxt->incTab[i]->doc != NULL)) {
1204            doc = ctxt->incTab[i]->doc;
1205#ifdef DEBUG_XINCLUDE
1206            printf("Already loaded %s\n", URL);
1207#endif
1208            goto loaded;
1209        }
1210    }
1211
1212    /*
1213     * Load it.
1214     */
1215#ifdef DEBUG_XINCLUDE
1216    printf("loading %s\n", URL);
1217#endif
1218    doc = xmlParseFile((const char *)URL);
1219    if (doc == NULL) {
1220        xmlFree(URL);
1221        if (fragment != NULL)
1222            xmlFree(fragment);
1223        return(-1);
1224    }
1225    ctxt->incTab[nr]->doc = doc;
1226
1227    /*
1228     * Make sure we have all entities fixed up
1229     */
1230    xmlXIncludeMergeEntities(ctxt, ctxt->doc, doc);
1231
1232    /*
1233     * We don't need the DTD anymore, free up space
1234    if (doc->intSubset != NULL) {
1235        xmlUnlinkNode((xmlNodePtr) doc->intSubset);
1236        xmlFreeNode((xmlNodePtr) doc->intSubset);
1237        doc->intSubset = NULL;
1238    }
1239    if (doc->extSubset != NULL) {
1240        xmlUnlinkNode((xmlNodePtr) doc->extSubset);
1241        xmlFreeNode((xmlNodePtr) doc->extSubset);
1242        doc->extSubset = NULL;
1243    }
1244     */
1245    xmlXIncludeRecurseDoc(ctxt, doc, URL);
1246
1247loaded:
1248    if (fragment == NULL) {
1249        /*
1250         * Add the top children list as the replacement copy.
1251         */
1252        if (doc == NULL)
1253        {
1254            /* Hopefully a DTD declaration won't be copied from
1255             * the same document */
1256            ctxt->incTab[nr]->inc = xmlCopyNodeList(ctxt->doc->children);
1257        } else {
1258            ctxt->incTab[nr]->inc = xmlXIncludeCopyNodeList(ctxt, ctxt->doc,
1259                                                       doc, doc->children);
1260        }
1261    } else {
1262        /*
1263         * Computes the XPointer expression and make a copy used
1264         * as the replacement copy.
1265         */
1266        xmlXPathObjectPtr xptr;
1267        xmlXPathContextPtr xptrctxt;
1268        xmlNodeSetPtr set;
1269
1270        if (doc == NULL) {
1271            xptrctxt = xmlXPtrNewContext(ctxt->doc, ctxt->incTab[nr]->ref,
1272                                         NULL);
1273        } else {
1274            xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
1275        }
1276        if (xptrctxt == NULL) {
1277            xmlGenericError(xmlGenericErrorContext,
1278                        "XInclude: could create XPointer context\n");
1279            ctxt->nbErrors++;
1280            xmlFree(URL);
1281            xmlFree(fragment);
1282            return(-1);
1283        }
1284        xptr = xmlXPtrEval(fragment, xptrctxt);
1285        if (xptr == NULL) {
1286            xmlGenericError(xmlGenericErrorContext,
1287                        "XInclude: XPointer evaluation failed: #%s\n",
1288                        fragment);
1289            ctxt->nbErrors++;
1290            xmlXPathFreeContext(xptrctxt);
1291            xmlFree(URL);
1292            xmlFree(fragment);
1293            return(-1);
1294        }
1295        switch (xptr->type) {
1296            case XPATH_UNDEFINED:
1297            case XPATH_BOOLEAN:
1298            case XPATH_NUMBER:
1299            case XPATH_STRING:
1300            case XPATH_POINT:
1301            case XPATH_USERS:
1302            case XPATH_XSLT_TREE:
1303                xmlGenericError(xmlGenericErrorContext,
1304                        "XInclude: XPointer is not a range: #%s\n",
1305                                fragment);
1306                ctxt->nbErrors++;
1307                xmlXPathFreeContext(xptrctxt);
1308                xmlFree(URL);
1309                xmlFree(fragment);
1310                return(-1);
1311            case XPATH_NODESET:
1312            case XPATH_RANGE:
1313            case XPATH_LOCATIONSET:
1314                break;
1315        }
1316        set = xptr->nodesetval;
1317        if (set != NULL) {
1318            for (i = 0;i < set->nodeNr;i++) {
1319                if (set->nodeTab[i] == NULL)
1320                    continue;
1321                switch (set->nodeTab[i]->type) {
1322                    case XML_TEXT_NODE:
1323                    case XML_CDATA_SECTION_NODE:
1324                    case XML_ELEMENT_NODE:
1325                    case XML_ENTITY_REF_NODE:
1326                    case XML_ENTITY_NODE:
1327                    case XML_PI_NODE:
1328                    case XML_COMMENT_NODE:
1329                    case XML_DOCUMENT_NODE:
1330                    case XML_HTML_DOCUMENT_NODE:
1331#ifdef LIBXML_DOCB_ENABLED
1332                    case XML_DOCB_DOCUMENT_NODE:
1333#endif
1334                        continue;
1335                    case XML_ATTRIBUTE_NODE:
1336                        xmlGenericError(xmlGenericErrorContext,
1337                        "XInclude: XPointer selects an attribute: #%s\n",
1338                                        fragment);
1339                        ctxt->nbErrors++;
1340                        set->nodeTab[i] = NULL;
1341                        continue;
1342                    case XML_NAMESPACE_DECL:
1343                        xmlGenericError(xmlGenericErrorContext,
1344                        "XInclude: XPointer selects a namespace: #%s\n",
1345                                        fragment);
1346                        ctxt->nbErrors++;
1347                        set->nodeTab[i] = NULL;
1348                        continue;
1349                    case XML_DOCUMENT_TYPE_NODE:
1350                    case XML_DOCUMENT_FRAG_NODE:
1351                    case XML_NOTATION_NODE:
1352                    case XML_DTD_NODE:
1353                    case XML_ELEMENT_DECL:
1354                    case XML_ATTRIBUTE_DECL:
1355                    case XML_ENTITY_DECL:
1356                    case XML_XINCLUDE_START:
1357                    case XML_XINCLUDE_END:
1358                        xmlGenericError(xmlGenericErrorContext,
1359                        "XInclude: XPointer selects unexpected nodes: #%s\n",
1360                                        fragment);
1361                        ctxt->nbErrors++;
1362                        set->nodeTab[i] = NULL;
1363                        set->nodeTab[i] = NULL;
1364                        continue; /* for */
1365                }
1366            }
1367        }
1368        if (doc == NULL) {
1369            ctxt->incTab[nr]->xptr = xptr;
1370            ctxt->incTab[nr]->inc = NULL;
1371        } else {
1372            ctxt->incTab[nr]->inc =
1373                xmlXIncludeCopyXPointer(ctxt, ctxt->doc, doc, xptr);
1374            xmlXPathFreeObject(xptr);
1375        }
1376        xmlXPathFreeContext(xptrctxt);
1377        xmlFree(fragment);
1378    }
1379
1380    /*
1381     * Do the xml:base fixup if needed
1382     */
1383    if ((doc != NULL) && (URL != NULL) && (xmlStrchr(URL, (xmlChar) '/'))) {
1384        xmlNodePtr node;
1385
1386        node = ctxt->incTab[nr]->inc;
1387        while (node != NULL) {
1388            if (node->type == XML_ELEMENT_NODE)
1389                xmlNodeSetBase(node, URL);
1390            node = node->next;
1391        }
1392    }
1393    if ((nr < ctxt->incNr) && (ctxt->incTab[nr]->doc != NULL) &&
1394        (ctxt->incTab[nr]->count <= 1)) {
1395#ifdef DEBUG_XINCLUDE
1396        printf("freeing %s\n", ctxt->incTab[nr]->doc->URL);
1397#endif
1398        xmlFreeDoc(ctxt->incTab[nr]->doc);
1399        ctxt->incTab[nr]->doc = NULL;
1400    }
1401    xmlFree(URL);
1402    return(0);
1403}
1404
1405/**
1406 * xmlXIncludeLoadTxt:
1407 * @ctxt:  the XInclude context
1408 * @url:  the associated URL
1409 * @nr:  the xinclude node number
1410 *
1411 * Load the content, and store the result in the XInclude context
1412 *
1413 * Returns 0 in case of success, -1 in case of failure
1414 */
1415static int
1416xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *url, int nr) {
1417    xmlParserInputBufferPtr buf;
1418    xmlNodePtr node;
1419    xmlURIPtr uri;
1420    xmlChar *URL;
1421    int i;
1422    xmlChar *encoding = NULL;
1423    xmlCharEncoding enc = 0;
1424
1425    /*
1426     * Check the URL and remove any fragment identifier
1427     */
1428    uri = xmlParseURI((const char *)url);
1429    if (uri == NULL) {
1430        xmlGenericError(xmlGenericErrorContext,
1431                    "XInclude: invalid value URI %s\n", url);
1432        ctxt->nbErrors++;
1433        return(-1);
1434    }
1435    if (uri->fragment != NULL) {
1436        xmlGenericError(xmlGenericErrorContext,
1437                "XInclude: fragment identifier forbidden for text: %s\n",
1438                uri->fragment);
1439        ctxt->nbErrors++;
1440        xmlFreeURI(uri);
1441        return(-1);
1442    }
1443    URL = xmlSaveUri(uri);
1444    xmlFreeURI(uri);
1445    if (URL == NULL) {
1446        xmlGenericError(xmlGenericErrorContext,
1447                    "XInclude: invalid value URI %s\n", url);
1448        ctxt->nbErrors++;
1449        return(-1);
1450    }
1451
1452    /*
1453     * Handling of references to the local document are done
1454     * directly through ctxt->doc.
1455     */
1456    if (URL[0] == 0) {
1457        xmlGenericError(xmlGenericErrorContext,
1458                "XInclude: text serialization of document not available\n");
1459        ctxt->nbErrors++;
1460        xmlFree(URL);
1461        return(-1);
1462    }
1463
1464    /*
1465     * Prevent reloading twice the document.
1466     */
1467    for (i = 0; i < ctxt->txtNr; i++) {
1468        if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1469            node = xmlCopyNode(ctxt->txtTab[i], 1);
1470            goto loaded;
1471        }
1472    }
1473    /*
1474     * Try to get the encoding if available
1475     */
1476    if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1477        encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1478    }
1479    if (encoding != NULL) {
1480        /*
1481         * TODO: we should not have to remap to the xmlCharEncoding
1482         *       predefined set, a better interface than
1483         *       xmlParserInputBufferCreateFilename should allow any
1484         *       encoding supported by iconv
1485         */
1486        enc = xmlParseCharEncoding((const char *) encoding);
1487        if (enc == XML_CHAR_ENCODING_ERROR) {
1488            xmlGenericError(xmlGenericErrorContext,
1489                    "XInclude: encoding %s not supported\n", encoding);
1490            ctxt->nbErrors++;
1491            xmlFree(encoding);
1492            xmlFree(URL);
1493            return(-1);
1494        }
1495        xmlFree(encoding);
1496    }
1497
1498    /*
1499     * Load it.
1500     */
1501    buf = xmlParserInputBufferCreateFilename((const char *)URL, enc);
1502    if (buf == NULL) {
1503        xmlFree(URL);
1504        return(-1);
1505    }
1506    node = xmlNewText(NULL);
1507
1508    /*
1509     * Scan all chars from the resource and add the to the node
1510     */
1511    while (xmlParserInputBufferRead(buf, 128) > 0) {
1512        int len;
1513        const xmlChar *content;
1514
1515        content = xmlBufferContent(buf->buffer);
1516        len = xmlBufferLength(buf->buffer);
1517        for (i = 0;i < len;) {
1518            int cur;
1519            int l;
1520
1521            cur = xmlStringCurrentChar(NULL, &content[i], &l);
1522            if (!IS_CHAR(cur)) {
1523                xmlGenericError(xmlGenericErrorContext,
1524                    "XInclude: %s contains invalid char %d\n", URL, cur);
1525                ctxt->nbErrors++;
1526            } else {
1527                xmlNodeAddContentLen(node, &content[i], l);
1528            }
1529            i += l;
1530        }
1531        xmlBufferShrink(buf->buffer, len);
1532    }
1533    xmlFreeParserInputBuffer(buf);
1534    xmlXIncludeAddTxt(ctxt, node, URL);
1535
1536loaded:
1537    /*
1538     * Add the element as the replacement copy.
1539     */
1540    ctxt->incTab[nr]->inc = node;
1541    xmlFree(URL);
1542    return(0);
1543}
1544
1545/**
1546 * xmlXIncludeLoadFallback:
1547 * @ctxt:  the XInclude context
1548 * @fallback:  the fallback node
1549 * @nr:  the xinclude node number
1550 *
1551 * Load the content of the fallback node, and store the result
1552 * in the XInclude context
1553 *
1554 * Returns 0 in case of success, -1 in case of failure
1555 */
1556static int
1557xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1558    if ((fallback == NULL) || (ctxt == NULL))
1559        return(-1);
1560
1561    ctxt->incTab[nr]->inc = xmlCopyNodeList(fallback->children);
1562    return(0);
1563}
1564
1565/************************************************************************
1566 *                                                                      *
1567 *                      XInclude Processing                             *
1568 *                                                                      *
1569 ************************************************************************/
1570
1571/**
1572 * xmlXIncludePreProcessNode:
1573 * @ctxt: an XInclude context
1574 * @node: an XInclude node
1575 *
1576 * Implement the XInclude preprocessing, currently just adding the element
1577 * for further processing.
1578 *
1579 * Returns the result list or NULL in case of error
1580 */
1581static xmlNodePtr
1582xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1583    xmlXIncludeAddNode(ctxt, node);
1584    return(0);
1585}
1586
1587#if 0
1588/**
1589 * xmlXIncludePreloadNode:
1590 * @ctxt: an XInclude context
1591 * @nr: the node number
1592 *
1593 * Do some precomputations and preload shared documents
1594 *
1595 * Returns 0 if substitution succeeded, -1 if some processing failed
1596 */
1597static int
1598xmlXIncludePreloadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1599    xmlNodePtr cur;
1600    xmlChar *href;
1601    xmlChar *parse;
1602    xmlChar *base;
1603    xmlChar *URI;
1604    int xml = 1; /* default Issue 64 */
1605    xmlURIPtr uri;
1606    xmlChar *URL;
1607    xmlChar *fragment = NULL;
1608    int i;
1609
1610
1611    if (ctxt == NULL)
1612        return(-1);
1613    if ((nr < 0) || (nr >= ctxt->incNr))
1614        return(-1);
1615    cur = ctxt->incTab[nr]->ref;
1616    if (cur == NULL)
1617        return(-1);
1618
1619    /*
1620     * read the attributes
1621     */
1622    href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1623    if (href == NULL) {
1624        href = xmlGetProp(cur, XINCLUDE_HREF);
1625        if (href == NULL) {
1626            xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1627            return(-1);
1628        }
1629    }
1630    parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1631    if (parse == NULL) {
1632        parse = xmlGetProp(cur, XINCLUDE_PARSE);
1633    }
1634    if (parse != NULL) {
1635        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1636            xml = 1;
1637        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1638            xml = 0;
1639        else {
1640            xmlGenericError(xmlGenericErrorContext,
1641                    "XInclude: invalid value %s for %s\n",
1642                            parse, XINCLUDE_PARSE);
1643            if (href != NULL)
1644                xmlFree(href);
1645            if (parse != NULL)
1646                xmlFree(parse);
1647            return(-1);
1648        }
1649    }
1650
1651    /*
1652     * compute the URI
1653     */
1654    base = xmlNodeGetBase(ctxt->doc, cur);
1655    if (base == NULL) {
1656        URI = xmlBuildURI(href, ctxt->doc->URL);
1657    } else {
1658        URI = xmlBuildURI(href, base);
1659    }
1660    if (URI == NULL) {
1661        xmlChar *escbase;
1662        xmlChar *eschref;
1663        /*
1664         * Some escaping may be needed
1665         */
1666        escbase = xmlURIEscape(base);
1667        eschref = xmlURIEscape(href);
1668        URI = xmlBuildURI(eschref, escbase);
1669        if (escbase != NULL)
1670            xmlFree(escbase);
1671        if (eschref != NULL)
1672            xmlFree(eschref);
1673    }
1674    if (parse != NULL)
1675        xmlFree(parse);
1676    if (href != NULL)
1677        xmlFree(href);
1678    if (base != NULL)
1679        xmlFree(base);
1680    if (URI == NULL) {
1681        xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1682        ctxt->nbErrors++;
1683        return(-1);
1684    }
1685
1686    /*
1687     * Check the URL and remove any fragment identifier
1688     */
1689    uri = xmlParseURI((const char *)URI);
1690    if (uri == NULL) {
1691        xmlGenericError(xmlGenericErrorContext,
1692                    "XInclude: invalid value URI %s\n", URI);
1693        ctxt->nbErrors++;
1694        xmlFree(URI);
1695        return(-1);
1696    }
1697    if (uri->fragment != NULL) {
1698        fragment = (xmlChar *) uri->fragment;
1699        uri->fragment = NULL;
1700    }
1701    URL = xmlSaveUri(uri);
1702    xmlFreeURI(uri);
1703    if (URL == NULL) {
1704        xmlGenericError(xmlGenericErrorContext,
1705                    "XInclude: invalid value URI %s\n", URI);
1706        ctxt->nbErrors++;
1707        if (fragment != NULL)
1708            xmlFree(fragment);
1709        xmlFree(URI);
1710        return(-1);
1711    }
1712    xmlFree(URI);
1713    if (fragment != NULL)
1714        xmlFree(fragment);
1715
1716    for (i = 0; i < nr; i++) {
1717        if (xmlStrEqual(URL, ctxt->incTab[i]->URI)) {
1718#ifdef DEBUG_XINCLUDE
1719            printf("Incrementing count for %d : %s\n", i, ctxt->incTab[i]->URI);
1720#endif
1721            ctxt->incTab[i]->count++;
1722            break;
1723        }
1724    }
1725    xmlFree(URL);
1726    return(0);
1727}
1728#endif
1729
1730/**
1731 * xmlXIncludeLoadNode:
1732 * @ctxt: an XInclude context
1733 * @nr: the node number
1734 *
1735 * Find and load the infoset replacement for the given node.
1736 *
1737 * Returns 0 if substitution succeeded, -1 if some processing failed
1738 */
1739static int
1740xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1741    xmlNodePtr cur;
1742    xmlChar *href;
1743    xmlChar *parse;
1744    xmlChar *base;
1745    xmlChar *URI;
1746    int xml = 1; /* default Issue 64 */
1747    int ret;
1748
1749    if (ctxt == NULL)
1750        return(-1);
1751    if ((nr < 0) || (nr >= ctxt->incNr))
1752        return(-1);
1753    cur = ctxt->incTab[nr]->ref;
1754    if (cur == NULL)
1755        return(-1);
1756
1757    /*
1758     * read the attributes
1759     */
1760    href = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_HREF);
1761    if (href == NULL) {
1762        href = xmlGetProp(cur, XINCLUDE_HREF);
1763        if (href == NULL) {
1764            xmlGenericError(xmlGenericErrorContext, "XInclude: no href\n");
1765            ctxt->nbErrors++;
1766            return(-1);
1767        }
1768    }
1769    parse = xmlGetNsProp(cur, XINCLUDE_NS, XINCLUDE_PARSE);
1770    if (parse == NULL) {
1771        parse = xmlGetProp(cur, XINCLUDE_PARSE);
1772    }
1773    if (parse != NULL) {
1774        if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
1775            xml = 1;
1776        else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
1777            xml = 0;
1778        else {
1779            xmlGenericError(xmlGenericErrorContext,
1780                    "XInclude: invalid value %s for %s\n",
1781                            parse, XINCLUDE_PARSE);
1782            ctxt->nbErrors++;
1783            if (href != NULL)
1784                xmlFree(href);
1785            if (parse != NULL)
1786                xmlFree(parse);
1787            return(-1);
1788        }
1789    }
1790
1791    /*
1792     * compute the URI
1793     */
1794    base = xmlNodeGetBase(ctxt->doc, cur);
1795    if (base == NULL) {
1796        URI = xmlBuildURI(href, ctxt->doc->URL);
1797    } else {
1798        URI = xmlBuildURI(href, base);
1799    }
1800    if (URI == NULL) {
1801        xmlChar *escbase;
1802        xmlChar *eschref;
1803        /*
1804         * Some escaping may be needed
1805         */
1806        escbase = xmlURIEscape(base);
1807        eschref = xmlURIEscape(href);
1808        URI = xmlBuildURI(eschref, escbase);
1809        if (escbase != NULL)
1810            xmlFree(escbase);
1811        if (eschref != NULL)
1812            xmlFree(eschref);
1813    }
1814    if (URI == NULL) {
1815        xmlGenericError(xmlGenericErrorContext, "XInclude: failed build URL\n");
1816        ctxt->nbErrors++;
1817        if (parse != NULL)
1818            xmlFree(parse);
1819        if (href != NULL)
1820            xmlFree(href);
1821        if (base != NULL)
1822            xmlFree(base);
1823        return(-1);
1824    }
1825#ifdef DEBUG_XINCLUDE
1826    xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
1827            xml ? "xml": "text");
1828    xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
1829#endif
1830
1831    /*
1832     * Cleanup
1833     */
1834    if (xml) {
1835        ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
1836        /* xmlXIncludeGetFragment(ctxt, cur, URI); */
1837    } else {
1838        ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
1839    }
1840    if (ret < 0) {
1841        xmlNodePtr children;
1842
1843        /*
1844         * Time to try a fallback if availble
1845         */
1846#ifdef DEBUG_XINCLUDE
1847        xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
1848#endif
1849        children = cur->children;
1850        while (children != NULL) {
1851            if ((children->type == XML_ELEMENT_NODE) &&
1852                (children->ns != NULL) &&
1853                (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
1854                (xmlStrEqual(children->ns->href, XINCLUDE_NS))) {
1855                ret = xmlXIncludeLoadFallback(ctxt, children, nr);
1856                if (ret == 0)
1857                    break;
1858            }
1859            children = children->next;
1860        }
1861    }
1862    if (ret < 0) {
1863        xmlGenericError(xmlGenericErrorContext,
1864                    "XInclude: could not load %s, and no fallback was found\n",
1865                        URI);
1866        ctxt->nbErrors++;
1867    }
1868
1869    /*
1870     * Cleanup
1871     */
1872    if (URI != NULL)
1873        xmlFree(URI);
1874    if (parse != NULL)
1875        xmlFree(parse);
1876    if (href != NULL)
1877        xmlFree(href);
1878    if (base != NULL)
1879        xmlFree(base);
1880    return(0);
1881}
1882
1883/**
1884 * xmlXIncludeIncludeNode:
1885 * @ctxt: an XInclude context
1886 * @nr: the node number
1887 *
1888 * Inplement the infoset replacement for the given node
1889 *
1890 * Returns 0 if substitution succeeded, -1 if some processing failed
1891 */
1892static int
1893xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
1894    xmlNodePtr cur, end, list, tmp;
1895
1896    if (ctxt == NULL)
1897        return(-1);
1898    if ((nr < 0) || (nr >= ctxt->incNr))
1899        return(-1);
1900    cur = ctxt->incTab[nr]->ref;
1901    if (cur == NULL)
1902        return(-1);
1903
1904    /*
1905     * If we stored an XPointer a late computation may be needed
1906     */
1907    if ((ctxt->incTab[nr]->inc == NULL) &&
1908        (ctxt->incTab[nr]->xptr != NULL)) {
1909        ctxt->incTab[nr]->inc =
1910            xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
1911                                    ctxt->incTab[nr]->xptr);
1912        xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
1913        ctxt->incTab[nr]->xptr = NULL;
1914    }
1915    list = ctxt->incTab[nr]->inc;
1916    ctxt->incTab[nr]->inc = NULL;
1917
1918    /*
1919     * Check against the risk of generating a multi-rooted document
1920     */
1921    if ((cur->parent != NULL) &&
1922        (cur->parent->type != XML_ELEMENT_NODE)) {
1923        int nb_elem = 0;
1924
1925        tmp = list;
1926        while (tmp != NULL) {
1927            if (tmp->type == XML_ELEMENT_NODE)
1928                nb_elem++;
1929            tmp = tmp->next;
1930        }
1931        if (nb_elem > 1) {
1932            xmlGenericError(xmlGenericErrorContext,
1933                    "XInclude error: would result in multiple root nodes\n");
1934            ctxt->nbErrors++;
1935            return(-1);
1936        }
1937    }
1938
1939    /*
1940     * Change the current node as an XInclude start one, and add an
1941     * entity end one
1942     */
1943    cur->type = XML_XINCLUDE_START;
1944    end = xmlNewNode(cur->ns, cur->name);
1945    if (end == NULL) {
1946        xmlGenericError(xmlGenericErrorContext,
1947                "XInclude: failed to build node\n");
1948        ctxt->nbErrors++;
1949        return(-1);
1950    }
1951    end->type = XML_XINCLUDE_END;
1952    xmlAddNextSibling(cur, end);
1953
1954    /*
1955     * Add the list of nodes
1956     */
1957    while (list != NULL) {
1958        cur = list;
1959        list = list->next;
1960
1961        xmlAddPrevSibling(end, cur);
1962    }
1963
1964   
1965    return(0);
1966}
1967
1968/**
1969 * xmlXIncludeTestNode:
1970 * @ctxt: the XInclude processing context
1971 * @node: an XInclude node
1972 *
1973 * test if the node is an XInclude node
1974 *
1975 * Returns 1 true, 0 otherwise
1976 */
1977static int
1978xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1979    if (node == NULL)
1980        return(0);
1981    if (node->ns == NULL)
1982        return(0);
1983    if (xmlStrEqual(node->ns->href, XINCLUDE_NS)) {
1984        if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
1985            xmlNodePtr child = node->children;
1986            int nb_fallback = 0;
1987
1988            while (child != NULL) {
1989                if ((child->type == XML_ELEMENT_NODE) &&
1990                    (child->ns != NULL) &&
1991                    (xmlStrEqual(child->ns->href, XINCLUDE_NS))) {
1992                    if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
1993                        xmlGenericError(xmlGenericErrorContext,
1994                            "XInclude: %s has an %s child\n",
1995                                        XINCLUDE_NODE, XINCLUDE_NODE);
1996                        ctxt->nbErrors++;
1997                        return(0);
1998                    }
1999                    if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2000                        nb_fallback++;
2001                    }
2002                }
2003                child = child->next;
2004            }
2005            if (nb_fallback > 1) {
2006                xmlGenericError(xmlGenericErrorContext,
2007                    "XInclude: %s has %d %s children\n",
2008                                XINCLUDE_NODE, nb_fallback, XINCLUDE_FALLBACK);
2009                ctxt->nbErrors++;
2010                return(0);
2011            }
2012            return(1);
2013        }
2014        if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2015            if ((node->parent == NULL) ||
2016                (node->parent->type != XML_ELEMENT_NODE) ||
2017                (node->parent->ns == NULL) ||
2018                (!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) ||
2019                (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2020                xmlGenericError(xmlGenericErrorContext,
2021                    "XInclude: %s is not the child of an %s\n",
2022                                XINCLUDE_FALLBACK, XINCLUDE_NODE);
2023                ctxt->nbErrors++;
2024            }
2025        }
2026    }
2027    return(0);
2028}
2029
2030/**
2031 * xmlXIncludeDoProcess:
2032 * @ctxt: the XInclude processing context
2033 * @doc: an XML document
2034 *
2035 * Implement the XInclude substitution on the XML document @doc
2036 *
2037 * Returns 0 if no substitution were done, -1 if some processing failed
2038 *    or the number of substitutions done.
2039 */
2040static int
2041xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc) {
2042    xmlNodePtr cur;
2043    int ret = 0;
2044    int i;
2045
2046    if (doc == NULL)
2047        return(-1);
2048    if (ctxt == NULL)
2049        return(-1);
2050
2051    if (doc->URL != NULL) {
2052        ret = xmlXIncludeURLPush(ctxt, doc->URL);
2053        if (ret < 0)
2054            return(-1);
2055    }
2056
2057    /*
2058     * First phase: lookup the elements in the document
2059     */
2060    cur = xmlDocGetRootElement(doc);
2061    if (xmlXIncludeTestNode(ctxt, cur) == 1)
2062        xmlXIncludePreProcessNode(ctxt, cur);
2063    while (cur != NULL) {
2064        /* TODO: need to work on entities -> stack */
2065        if ((cur->children != NULL) &&
2066            (cur->children->type != XML_ENTITY_DECL)) {
2067            cur = cur->children;
2068            if (xmlXIncludeTestNode(ctxt, cur))
2069                xmlXIncludePreProcessNode(ctxt, cur);
2070        } else if (cur->next != NULL) {
2071            cur = cur->next;
2072            if (xmlXIncludeTestNode(ctxt, cur))
2073                xmlXIncludePreProcessNode(ctxt, cur);
2074        } else {
2075            do {
2076                cur = cur->parent;
2077                if (cur == NULL) break; /* do */
2078                if (cur->next != NULL) {
2079                    cur = cur->next;
2080                    if (xmlXIncludeTestNode(ctxt, cur))
2081                        xmlXIncludePreProcessNode(ctxt, cur);
2082                    break; /* do */
2083                }
2084            } while (cur != NULL);
2085        }
2086    }
2087
2088    /*
2089     * Second Phase : collect the infosets fragments
2090     */
2091    for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2092        xmlXIncludeLoadNode(ctxt, i);
2093        ret++;
2094    }
2095
2096    /*
2097     * Third phase: extend the original document infoset.
2098     */
2099    if (ctxt->nbErrors == 0) {
2100        for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2101            xmlXIncludeIncludeNode(ctxt, i);
2102        }
2103    }
2104
2105    if (doc->URL != NULL)
2106        xmlXIncludeURLPop(ctxt);
2107    return(ret);
2108}
2109
2110/**
2111 * xmlXIncludeProcess:
2112 * @doc: an XML document
2113 *
2114 * Implement the XInclude substitution on the XML document @doc
2115 *
2116 * Returns 0 if no substitution were done, -1 if some processing failed
2117 *    or the number of substitutions done.
2118 */
2119int
2120xmlXIncludeProcess(xmlDocPtr doc) {
2121    xmlXIncludeCtxtPtr ctxt;
2122    int ret = 0;
2123
2124    if (doc == NULL)
2125        return(-1);
2126    ctxt = xmlXIncludeNewContext(doc);
2127    if (ctxt == NULL)
2128        return(-1);
2129    ret = xmlXIncludeDoProcess(ctxt, doc);
2130    if ((ret >= 0) && (ctxt->nbErrors > 0))
2131        ret = -1;
2132
2133    xmlXIncludeFreeContext(ctxt);
2134    return(ret);
2135}
2136
2137#else /* !LIBXML_XINCLUDE_ENABLED */
2138#endif
Note: See TracBrowser for help on using the repository browser.