• 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 
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
xmlXIncludeErrMemory(xmlXIncludeCtxtPtr ctxt,xmlNodePtr node,const char * extra)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
xmlXIncludeErr(xmlXIncludeCtxtPtr ctxt,xmlNodePtr node,int error,const char * msg,const xmlChar * extra)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 *
xmlXIncludeGetProp(xmlXIncludeCtxtPtr ctxt,xmlNodePtr cur,const xmlChar * name)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
xmlXIncludeFreeRef(xmlXIncludeRefPtr ref)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
xmlXIncludeNewRef(xmlXIncludeCtxtPtr ctxt,const xmlChar * URI,xmlNodePtr ref)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
xmlXIncludeNewContext(xmlDocPtr doc)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
xmlXIncludeURLPush(xmlXIncludeCtxtPtr ctxt,const xmlChar * value)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
xmlXIncludeURLPop(xmlXIncludeCtxtPtr ctxt)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
xmlXIncludeFreeContext(xmlXIncludeCtxtPtr ctxt)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
xmlXIncludeParseFile(xmlXIncludeCtxtPtr ctxt,const char * URL)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
xmlXIncludeAddNode(xmlXIncludeCtxtPtr ctxt,xmlNodePtr cur)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
xmlXIncludeRecurseDoc(xmlXIncludeCtxtPtr ctxt,xmlDocPtr doc,const xmlURL url ATTRIBUTE_UNUSED)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
xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt,xmlNodePtr txt,const xmlURL url)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
xmlXIncludeCopyNode(xmlXIncludeCtxtPtr ctxt,xmlDocPtr target,xmlDocPtr source,xmlNodePtr elem)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
xmlXIncludeCopyNodeList(xmlXIncludeCtxtPtr ctxt,xmlDocPtr target,xmlDocPtr source,xmlNodePtr elem)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
xmlXIncludeGetNthChild(xmlNodePtr cur,int no)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
xmlXIncludeCopyRange(xmlXIncludeCtxtPtr ctxt,xmlDocPtr target,xmlDocPtr source,xmlXPathObjectPtr range)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
xmlXIncludeCopyXPointer(xmlXIncludeCtxtPtr ctxt,xmlDocPtr target,xmlDocPtr source,xmlXPathObjectPtr obj)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
xmlXIncludeMergeEntity(xmlEntityPtr ent,xmlXIncludeMergeDataPtr data,xmlChar * name ATTRIBUTE_UNUSED)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
xmlXIncludeMergeEntities(xmlXIncludeCtxtPtr ctxt,xmlDocPtr doc,xmlDocPtr from)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
xmlXIncludeLoadDoc(xmlXIncludeCtxtPtr ctxt,const xmlChar * url,int nr)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
xmlXIncludeLoadTxt(xmlXIncludeCtxtPtr ctxt,const xmlChar * url,int nr)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
xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt,xmlNodePtr fallback,int nr)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
xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt,xmlNodePtr node)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
xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt,int nr)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
xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt,int nr)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
xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt,xmlNodePtr node)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
xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt,xmlDocPtr doc,xmlNodePtr tree)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
xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt,int flags)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
xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree,int flags,void * data)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
xmlXIncludeProcessFlagsData(xmlDocPtr doc,int flags,void * data)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
xmlXIncludeProcessFlags(xmlDocPtr doc,int flags)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
xmlXIncludeProcess(xmlDocPtr doc)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
xmlXIncludeProcessTreeFlags(xmlNodePtr tree,int flags)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
xmlXIncludeProcessTree(xmlNodePtr tree)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
xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt,xmlNodePtr node)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"
2592