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