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

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