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