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