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