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