Annotation of embedaddon/libxml2/xinclude.c, revision 1.1.1.2
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;
1.1.1.2 ! misho 1799: xmlParserCtxtPtr pctxt;
! 1800: xmlParserInputPtr inputStream;
1.1 misho 1801:
1802: /*
1803: * Check the URL and remove any fragment identifier
1804: */
1805: uri = xmlParseURI((const char *)url);
1806: if (uri == NULL) {
1807: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1808: "invalid value URI %s\n", url);
1809: return(-1);
1810: }
1811: if (uri->fragment != NULL) {
1812: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_TEXT_FRAGMENT,
1813: "fragment identifier forbidden for text: %s\n",
1814: (const xmlChar *) uri->fragment);
1815: xmlFreeURI(uri);
1816: return(-1);
1817: }
1818: URL = xmlSaveUri(uri);
1819: xmlFreeURI(uri);
1820: if (URL == NULL) {
1821: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref, XML_XINCLUDE_HREF_URI,
1822: "invalid value URI %s\n", url);
1823: return(-1);
1824: }
1825:
1826: /*
1827: * Handling of references to the local document are done
1828: * directly through ctxt->doc.
1829: */
1830: if (URL[0] == 0) {
1831: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1832: XML_XINCLUDE_TEXT_DOCUMENT,
1833: "text serialization of document not available\n", NULL);
1834: xmlFree(URL);
1835: return(-1);
1836: }
1837:
1838: /*
1839: * Prevent reloading twice the document.
1840: */
1841: for (i = 0; i < ctxt->txtNr; i++) {
1842: if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
1843: node = xmlCopyNode(ctxt->txtTab[i], 1);
1844: goto loaded;
1845: }
1846: }
1847: /*
1848: * Try to get the encoding if available
1849: */
1850: if ((ctxt->incTab[nr] != NULL) && (ctxt->incTab[nr]->ref != NULL)) {
1851: encoding = xmlGetProp(ctxt->incTab[nr]->ref, XINCLUDE_PARSE_ENCODING);
1852: }
1853: if (encoding != NULL) {
1854: /*
1855: * TODO: we should not have to remap to the xmlCharEncoding
1856: * predefined set, a better interface than
1857: * xmlParserInputBufferCreateFilename should allow any
1858: * encoding supported by iconv
1859: */
1860: enc = xmlParseCharEncoding((const char *) encoding);
1861: if (enc == XML_CHAR_ENCODING_ERROR) {
1862: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1863: XML_XINCLUDE_UNKNOWN_ENCODING,
1864: "encoding %s not supported\n", encoding);
1865: xmlFree(encoding);
1866: xmlFree(URL);
1867: return(-1);
1868: }
1869: xmlFree(encoding);
1870: }
1871:
1872: /*
1873: * Load it.
1874: */
1.1.1.2 ! misho 1875: pctxt = xmlNewParserCtxt();
! 1876: inputStream = xmlLoadExternalEntity((const char*)URL, NULL, pctxt);
! 1877: if(inputStream == NULL) {
! 1878: xmlFreeParserCtxt(pctxt);
! 1879: xmlFree(URL);
! 1880: return(-1);
! 1881: }
! 1882: buf = inputStream->buf;
1.1 misho 1883: if (buf == NULL) {
1.1.1.2 ! misho 1884: xmlFreeInputStream (inputStream);
! 1885: xmlFreeParserCtxt(pctxt);
1.1 misho 1886: xmlFree(URL);
1887: return(-1);
1888: }
1.1.1.2 ! misho 1889: if (buf->encoder)
! 1890: xmlCharEncCloseFunc(buf->encoder);
! 1891: buf->encoder = xmlGetCharEncodingHandler(enc);
1.1 misho 1892: node = xmlNewText(NULL);
1893:
1894: /*
1895: * Scan all chars from the resource and add the to the node
1896: */
1897: while (xmlParserInputBufferRead(buf, 128) > 0) {
1898: int len;
1899: const xmlChar *content;
1900:
1901: content = xmlBufferContent(buf->buffer);
1902: len = xmlBufferLength(buf->buffer);
1903: for (i = 0;i < len;) {
1904: int cur;
1905: int l;
1906:
1907: cur = xmlStringCurrentChar(NULL, &content[i], &l);
1908: if (!IS_CHAR(cur)) {
1909: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
1910: XML_XINCLUDE_INVALID_CHAR,
1911: "%s contains invalid char\n", URL);
1912: xmlFreeParserInputBuffer(buf);
1913: xmlFree(URL);
1914: return(-1);
1915: } else {
1916: xmlNodeAddContentLen(node, &content[i], l);
1917: }
1918: i += l;
1919: }
1920: xmlBufferShrink(buf->buffer, len);
1921: }
1.1.1.2 ! misho 1922: xmlFreeParserCtxt(pctxt);
1.1 misho 1923: xmlXIncludeAddTxt(ctxt, node, URL);
1.1.1.2 ! misho 1924: xmlFreeInputStream(inputStream);
1.1 misho 1925:
1926: loaded:
1927: /*
1928: * Add the element as the replacement copy.
1929: */
1930: ctxt->incTab[nr]->inc = node;
1931: xmlFree(URL);
1932: return(0);
1933: }
1934:
1935: /**
1936: * xmlXIncludeLoadFallback:
1937: * @ctxt: the XInclude context
1938: * @fallback: the fallback node
1939: * @nr: the xinclude node number
1940: *
1941: * Load the content of the fallback node, and store the result
1942: * in the XInclude context
1943: *
1944: * Returns 0 in case of success, -1 in case of failure
1945: */
1946: static int
1947: xmlXIncludeLoadFallback(xmlXIncludeCtxtPtr ctxt, xmlNodePtr fallback, int nr) {
1948: xmlXIncludeCtxtPtr newctxt;
1949: int ret = 0;
1950:
1951: if ((fallback == NULL) || (ctxt == NULL))
1952: return(-1);
1953: if (fallback->children != NULL) {
1954: /*
1955: * It's possible that the fallback also has 'includes'
1956: * (Bug 129969), so we re-process the fallback just in case
1957: */
1958: newctxt = xmlXIncludeNewContext(ctxt->doc);
1959: if (newctxt == NULL)
1960: return (-1);
1961: newctxt->_private = ctxt->_private;
1962: newctxt->base = xmlStrdup(ctxt->base); /* Inherit the base from the existing context */
1963: xmlXIncludeSetFlags(newctxt, ctxt->parseFlags);
1964: ret = xmlXIncludeDoProcess(newctxt, ctxt->doc, fallback->children);
1965: if (ctxt->nbErrors > 0)
1966: ret = -1;
1967: else if (ret > 0)
1968: ret = 0; /* xmlXIncludeDoProcess can return +ve number */
1969: xmlXIncludeFreeContext(newctxt);
1970:
1971: ctxt->incTab[nr]->inc = xmlDocCopyNodeList(ctxt->doc,
1972: fallback->children);
1973: } else {
1974: ctxt->incTab[nr]->inc = NULL;
1975: ctxt->incTab[nr]->emptyFb = 1; /* flag empty callback */
1976: }
1977: return(ret);
1978: }
1979:
1980: /************************************************************************
1981: * *
1982: * XInclude Processing *
1983: * *
1984: ************************************************************************/
1985:
1986: /**
1987: * xmlXIncludePreProcessNode:
1988: * @ctxt: an XInclude context
1989: * @node: an XInclude node
1990: *
1991: * Implement the XInclude preprocessing, currently just adding the element
1992: * for further processing.
1993: *
1994: * Returns the result list or NULL in case of error
1995: */
1996: static xmlNodePtr
1997: xmlXIncludePreProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
1998: xmlXIncludeAddNode(ctxt, node);
1999: return(NULL);
2000: }
2001:
2002: /**
2003: * xmlXIncludeLoadNode:
2004: * @ctxt: an XInclude context
2005: * @nr: the node number
2006: *
2007: * Find and load the infoset replacement for the given node.
2008: *
2009: * Returns 0 if substitution succeeded, -1 if some processing failed
2010: */
2011: static int
2012: xmlXIncludeLoadNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2013: xmlNodePtr cur;
2014: xmlChar *href;
2015: xmlChar *parse;
2016: xmlChar *base;
2017: xmlChar *oldBase;
2018: xmlChar *URI;
2019: int xml = 1; /* default Issue 64 */
2020: int ret;
2021:
2022: if (ctxt == NULL)
2023: return(-1);
2024: if ((nr < 0) || (nr >= ctxt->incNr))
2025: return(-1);
2026: cur = ctxt->incTab[nr]->ref;
2027: if (cur == NULL)
2028: return(-1);
2029:
2030: /*
2031: * read the attributes
2032: */
2033: href = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_HREF);
2034: if (href == NULL) {
2035: href = xmlStrdup(BAD_CAST ""); /* @@@@ href is now optional */
2036: if (href == NULL)
2037: return(-1);
2038: }
2039: parse = xmlXIncludeGetProp(ctxt, cur, XINCLUDE_PARSE);
2040: if (parse != NULL) {
2041: if (xmlStrEqual(parse, XINCLUDE_PARSE_XML))
2042: xml = 1;
2043: else if (xmlStrEqual(parse, XINCLUDE_PARSE_TEXT))
2044: xml = 0;
2045: else {
2046: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2047: XML_XINCLUDE_PARSE_VALUE,
2048: "invalid value %s for 'parse'\n", parse);
2049: if (href != NULL)
2050: xmlFree(href);
2051: if (parse != NULL)
2052: xmlFree(parse);
2053: return(-1);
2054: }
2055: }
2056:
2057: /*
2058: * compute the URI
2059: */
2060: base = xmlNodeGetBase(ctxt->doc, cur);
2061: if (base == NULL) {
2062: URI = xmlBuildURI(href, ctxt->doc->URL);
2063: } else {
2064: URI = xmlBuildURI(href, base);
2065: }
2066: if (URI == NULL) {
2067: xmlChar *escbase;
2068: xmlChar *eschref;
2069: /*
2070: * Some escaping may be needed
2071: */
2072: escbase = xmlURIEscape(base);
2073: eschref = xmlURIEscape(href);
2074: URI = xmlBuildURI(eschref, escbase);
2075: if (escbase != NULL)
2076: xmlFree(escbase);
2077: if (eschref != NULL)
2078: xmlFree(eschref);
2079: }
2080: if (URI == NULL) {
2081: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2082: XML_XINCLUDE_HREF_URI, "failed build URL\n", NULL);
2083: if (parse != NULL)
2084: xmlFree(parse);
2085: if (href != NULL)
2086: xmlFree(href);
2087: if (base != NULL)
2088: xmlFree(base);
2089: return(-1);
2090: }
2091: #ifdef DEBUG_XINCLUDE
2092: xmlGenericError(xmlGenericErrorContext, "parse: %s\n",
2093: xml ? "xml": "text");
2094: xmlGenericError(xmlGenericErrorContext, "URI: %s\n", URI);
2095: #endif
2096:
2097: /*
2098: * Save the base for this include (saving the current one)
2099: */
2100: oldBase = ctxt->base;
2101: ctxt->base = base;
2102:
2103: if (xml) {
2104: ret = xmlXIncludeLoadDoc(ctxt, URI, nr);
2105: /* xmlXIncludeGetFragment(ctxt, cur, URI); */
2106: } else {
2107: ret = xmlXIncludeLoadTxt(ctxt, URI, nr);
2108: }
2109:
2110: /*
2111: * Restore the original base before checking for fallback
2112: */
2113: ctxt->base = oldBase;
2114:
2115: if (ret < 0) {
2116: xmlNodePtr children;
2117:
2118: /*
2119: * Time to try a fallback if availble
2120: */
2121: #ifdef DEBUG_XINCLUDE
2122: xmlGenericError(xmlGenericErrorContext, "error looking for fallback\n");
2123: #endif
2124: children = cur->children;
2125: while (children != NULL) {
2126: if ((children->type == XML_ELEMENT_NODE) &&
2127: (children->ns != NULL) &&
2128: (xmlStrEqual(children->name, XINCLUDE_FALLBACK)) &&
2129: ((xmlStrEqual(children->ns->href, XINCLUDE_NS)) ||
2130: (xmlStrEqual(children->ns->href, XINCLUDE_OLD_NS)))) {
2131: ret = xmlXIncludeLoadFallback(ctxt, children, nr);
2132: if (ret == 0)
2133: break;
2134: }
2135: children = children->next;
2136: }
2137: }
2138: if (ret < 0) {
2139: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2140: XML_XINCLUDE_NO_FALLBACK,
2141: "could not load %s, and no fallback was found\n",
2142: URI);
2143: }
2144:
2145: /*
2146: * Cleanup
2147: */
2148: if (URI != NULL)
2149: xmlFree(URI);
2150: if (parse != NULL)
2151: xmlFree(parse);
2152: if (href != NULL)
2153: xmlFree(href);
2154: if (base != NULL)
2155: xmlFree(base);
2156: return(0);
2157: }
2158:
2159: /**
2160: * xmlXIncludeIncludeNode:
2161: * @ctxt: an XInclude context
2162: * @nr: the node number
2163: *
2164: * Inplement the infoset replacement for the given node
2165: *
2166: * Returns 0 if substitution succeeded, -1 if some processing failed
2167: */
2168: static int
2169: xmlXIncludeIncludeNode(xmlXIncludeCtxtPtr ctxt, int nr) {
2170: xmlNodePtr cur, end, list, tmp;
2171:
2172: if (ctxt == NULL)
2173: return(-1);
2174: if ((nr < 0) || (nr >= ctxt->incNr))
2175: return(-1);
2176: cur = ctxt->incTab[nr]->ref;
2177: if (cur == NULL)
2178: return(-1);
2179:
2180: /*
2181: * If we stored an XPointer a late computation may be needed
2182: */
2183: if ((ctxt->incTab[nr]->inc == NULL) &&
2184: (ctxt->incTab[nr]->xptr != NULL)) {
2185: ctxt->incTab[nr]->inc =
2186: xmlXIncludeCopyXPointer(ctxt, ctxt->doc, ctxt->doc,
2187: ctxt->incTab[nr]->xptr);
2188: xmlXPathFreeObject(ctxt->incTab[nr]->xptr);
2189: ctxt->incTab[nr]->xptr = NULL;
2190: }
2191: list = ctxt->incTab[nr]->inc;
2192: ctxt->incTab[nr]->inc = NULL;
2193:
2194: /*
2195: * Check against the risk of generating a multi-rooted document
2196: */
2197: if ((cur->parent != NULL) &&
2198: (cur->parent->type != XML_ELEMENT_NODE)) {
2199: int nb_elem = 0;
2200:
2201: tmp = list;
2202: while (tmp != NULL) {
2203: if (tmp->type == XML_ELEMENT_NODE)
2204: nb_elem++;
2205: tmp = tmp->next;
2206: }
2207: if (nb_elem > 1) {
2208: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2209: XML_XINCLUDE_MULTIPLE_ROOT,
2210: "XInclude error: would result in multiple root nodes\n",
2211: NULL);
2212: return(-1);
2213: }
2214: }
2215:
2216: if (ctxt->parseFlags & XML_PARSE_NOXINCNODE) {
2217: /*
2218: * Add the list of nodes
2219: */
2220: while (list != NULL) {
2221: end = list;
2222: list = list->next;
2223:
2224: xmlAddPrevSibling(cur, end);
2225: }
2226: xmlUnlinkNode(cur);
2227: xmlFreeNode(cur);
2228: } else {
2229: /*
2230: * Change the current node as an XInclude start one, and add an
2231: * XInclude end one
2232: */
2233: cur->type = XML_XINCLUDE_START;
2234: end = xmlNewDocNode(cur->doc, cur->ns, cur->name, NULL);
2235: if (end == NULL) {
2236: xmlXIncludeErr(ctxt, ctxt->incTab[nr]->ref,
2237: XML_XINCLUDE_BUILD_FAILED,
2238: "failed to build node\n", NULL);
2239: return(-1);
2240: }
2241: end->type = XML_XINCLUDE_END;
2242: xmlAddNextSibling(cur, end);
2243:
2244: /*
2245: * Add the list of nodes
2246: */
2247: while (list != NULL) {
2248: cur = list;
2249: list = list->next;
2250:
2251: xmlAddPrevSibling(end, cur);
2252: }
2253: }
2254:
2255:
2256: return(0);
2257: }
2258:
2259: /**
2260: * xmlXIncludeTestNode:
2261: * @ctxt: the XInclude processing context
2262: * @node: an XInclude node
2263: *
2264: * test if the node is an XInclude node
2265: *
2266: * Returns 1 true, 0 otherwise
2267: */
2268: static int
2269: xmlXIncludeTestNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2270: if (node == NULL)
2271: return(0);
2272: if (node->type != XML_ELEMENT_NODE)
2273: return(0);
2274: if (node->ns == NULL)
2275: return(0);
2276: if ((xmlStrEqual(node->ns->href, XINCLUDE_NS)) ||
2277: (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS))) {
2278: if (xmlStrEqual(node->ns->href, XINCLUDE_OLD_NS)) {
2279: if (ctxt->legacy == 0) {
2280: #if 0 /* wait for the XML Core Working Group to get something stable ! */
2281: xmlXIncludeWarn(ctxt, node, XML_XINCLUDE_DEPRECATED_NS,
2282: "Deprecated XInclude namespace found, use %s",
2283: XINCLUDE_NS);
2284: #endif
2285: ctxt->legacy = 1;
2286: }
2287: }
2288: if (xmlStrEqual(node->name, XINCLUDE_NODE)) {
2289: xmlNodePtr child = node->children;
2290: int nb_fallback = 0;
2291:
2292: while (child != NULL) {
2293: if ((child->type == XML_ELEMENT_NODE) &&
2294: (child->ns != NULL) &&
2295: ((xmlStrEqual(child->ns->href, XINCLUDE_NS)) ||
2296: (xmlStrEqual(child->ns->href, XINCLUDE_OLD_NS)))) {
2297: if (xmlStrEqual(child->name, XINCLUDE_NODE)) {
2298: xmlXIncludeErr(ctxt, node,
2299: XML_XINCLUDE_INCLUDE_IN_INCLUDE,
2300: "%s has an 'include' child\n",
2301: XINCLUDE_NODE);
2302: return(0);
2303: }
2304: if (xmlStrEqual(child->name, XINCLUDE_FALLBACK)) {
2305: nb_fallback++;
2306: }
2307: }
2308: child = child->next;
2309: }
2310: if (nb_fallback > 1) {
2311: xmlXIncludeErr(ctxt, node, XML_XINCLUDE_FALLBACKS_IN_INCLUDE,
2312: "%s has multiple fallback children\n",
2313: XINCLUDE_NODE);
2314: return(0);
2315: }
2316: return(1);
2317: }
2318: if (xmlStrEqual(node->name, XINCLUDE_FALLBACK)) {
2319: if ((node->parent == NULL) ||
2320: (node->parent->type != XML_ELEMENT_NODE) ||
2321: (node->parent->ns == NULL) ||
2322: ((!xmlStrEqual(node->parent->ns->href, XINCLUDE_NS)) &&
2323: (!xmlStrEqual(node->parent->ns->href, XINCLUDE_OLD_NS))) ||
2324: (!xmlStrEqual(node->parent->name, XINCLUDE_NODE))) {
2325: xmlXIncludeErr(ctxt, node,
2326: XML_XINCLUDE_FALLBACK_NOT_IN_INCLUDE,
2327: "%s is not the child of an 'include'\n",
2328: XINCLUDE_FALLBACK);
2329: }
2330: }
2331: }
2332: return(0);
2333: }
2334:
2335: /**
2336: * xmlXIncludeDoProcess:
2337: * @ctxt: the XInclude processing context
2338: * @doc: an XML document
2339: * @tree: the top of the tree to process
2340: *
2341: * Implement the XInclude substitution on the XML document @doc
2342: *
2343: * Returns 0 if no substitution were done, -1 if some processing failed
2344: * or the number of substitutions done.
2345: */
2346: static int
2347: xmlXIncludeDoProcess(xmlXIncludeCtxtPtr ctxt, xmlDocPtr doc, xmlNodePtr tree) {
2348: xmlNodePtr cur;
2349: int ret = 0;
2350: int i, start;
2351:
2352: if ((doc == NULL) || (tree == NULL))
2353: return(-1);
2354: if (ctxt == NULL)
2355: return(-1);
2356:
2357: if (doc->URL != NULL) {
2358: ret = xmlXIncludeURLPush(ctxt, doc->URL);
2359: if (ret < 0)
2360: return(-1);
2361: }
2362: start = ctxt->incNr;
2363:
2364: /*
2365: * First phase: lookup the elements in the document
2366: */
2367: cur = tree;
2368: if (xmlXIncludeTestNode(ctxt, cur) == 1)
2369: xmlXIncludePreProcessNode(ctxt, cur);
2370: while ((cur != NULL) && (cur != tree->parent)) {
2371: /* TODO: need to work on entities -> stack */
2372: if ((cur->children != NULL) &&
2373: (cur->children->type != XML_ENTITY_DECL) &&
2374: (cur->children->type != XML_XINCLUDE_START) &&
2375: (cur->children->type != XML_XINCLUDE_END)) {
2376: cur = cur->children;
2377: if (xmlXIncludeTestNode(ctxt, cur))
2378: xmlXIncludePreProcessNode(ctxt, cur);
2379: } else if (cur->next != NULL) {
2380: cur = cur->next;
2381: if (xmlXIncludeTestNode(ctxt, cur))
2382: xmlXIncludePreProcessNode(ctxt, cur);
2383: } else {
2384: if (cur == tree)
2385: break;
2386: do {
2387: cur = cur->parent;
2388: if ((cur == NULL) || (cur == tree->parent))
2389: break; /* do */
2390: if (cur->next != NULL) {
2391: cur = cur->next;
2392: if (xmlXIncludeTestNode(ctxt, cur))
2393: xmlXIncludePreProcessNode(ctxt, cur);
2394: break; /* do */
2395: }
2396: } while (cur != NULL);
2397: }
2398: }
2399:
2400: /*
2401: * Second Phase : collect the infosets fragments
2402: */
2403: for (i = start;i < ctxt->incNr; i++) {
2404: xmlXIncludeLoadNode(ctxt, i);
2405: ret++;
2406: }
2407:
2408: /*
2409: * Third phase: extend the original document infoset.
2410: *
2411: * Originally we bypassed the inclusion if there were any errors
2412: * encountered on any of the XIncludes. A bug was raised (bug
2413: * 132588) requesting that we output the XIncludes without error,
2414: * so the check for inc!=NULL || xptr!=NULL was put in. This may
2415: * give some other problems in the future, but for now it seems to
2416: * work ok.
2417: *
2418: */
2419: for (i = ctxt->incBase;i < ctxt->incNr; i++) {
2420: if ((ctxt->incTab[i]->inc != NULL) ||
2421: (ctxt->incTab[i]->xptr != NULL) ||
2422: (ctxt->incTab[i]->emptyFb != 0)) /* (empty fallback) */
2423: xmlXIncludeIncludeNode(ctxt, i);
2424: }
2425:
2426: if (doc->URL != NULL)
2427: xmlXIncludeURLPop(ctxt);
2428: return(ret);
2429: }
2430:
2431: /**
2432: * xmlXIncludeSetFlags:
2433: * @ctxt: an XInclude processing context
2434: * @flags: a set of xmlParserOption used for parsing XML includes
2435: *
2436: * Set the flags used for further processing of XML resources.
2437: *
2438: * Returns 0 in case of success and -1 in case of error.
2439: */
2440: int
2441: xmlXIncludeSetFlags(xmlXIncludeCtxtPtr ctxt, int flags) {
2442: if (ctxt == NULL)
2443: return(-1);
2444: ctxt->parseFlags = flags;
2445: return(0);
2446: }
2447:
2448: /**
2449: * xmlXIncludeProcessTreeFlagsData:
2450: * @tree: an XML node
2451: * @flags: a set of xmlParserOption used for parsing XML includes
2452: * @data: application data that will be passed to the parser context
2453: * in the _private field of the parser context(s)
2454: *
2455: * Implement the XInclude substitution on the XML node @tree
2456: *
2457: * Returns 0 if no substitution were done, -1 if some processing failed
2458: * or the number of substitutions done.
2459: */
2460:
2461: int
2462: xmlXIncludeProcessTreeFlagsData(xmlNodePtr tree, int flags, void *data) {
2463: xmlXIncludeCtxtPtr ctxt;
2464: int ret = 0;
2465:
2466: if ((tree == NULL) || (tree->doc == NULL))
2467: return(-1);
2468:
2469: ctxt = xmlXIncludeNewContext(tree->doc);
2470: if (ctxt == NULL)
2471: return(-1);
2472: ctxt->_private = data;
2473: ctxt->base = xmlStrdup((xmlChar *)tree->doc->URL);
2474: xmlXIncludeSetFlags(ctxt, flags);
2475: ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
2476: if ((ret >= 0) && (ctxt->nbErrors > 0))
2477: ret = -1;
2478:
2479: xmlXIncludeFreeContext(ctxt);
2480: return(ret);
2481: }
2482:
2483: /**
2484: * xmlXIncludeProcessFlagsData:
2485: * @doc: an XML document
2486: * @flags: a set of xmlParserOption used for parsing XML includes
2487: * @data: application data that will be passed to the parser context
2488: * in the _private field of the parser context(s)
2489: *
2490: * Implement the XInclude substitution on the XML document @doc
2491: *
2492: * Returns 0 if no substitution were done, -1 if some processing failed
2493: * or the number of substitutions done.
2494: */
2495: int
2496: xmlXIncludeProcessFlagsData(xmlDocPtr doc, int flags, void *data) {
2497: xmlNodePtr tree;
2498:
2499: if (doc == NULL)
2500: return(-1);
2501: tree = xmlDocGetRootElement(doc);
2502: if (tree == NULL)
2503: return(-1);
2504: return(xmlXIncludeProcessTreeFlagsData(tree, flags, data));
2505: }
2506:
2507: /**
2508: * xmlXIncludeProcessFlags:
2509: * @doc: an XML document
2510: * @flags: a set of xmlParserOption used for parsing XML includes
2511: *
2512: * Implement the XInclude substitution on the XML document @doc
2513: *
2514: * Returns 0 if no substitution were done, -1 if some processing failed
2515: * or the number of substitutions done.
2516: */
2517: int
2518: xmlXIncludeProcessFlags(xmlDocPtr doc, int flags) {
2519: return xmlXIncludeProcessFlagsData(doc, flags, NULL);
2520: }
2521:
2522: /**
2523: * xmlXIncludeProcess:
2524: * @doc: an XML document
2525: *
2526: * Implement the XInclude substitution on the XML document @doc
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: xmlXIncludeProcess(xmlDocPtr doc) {
2533: return(xmlXIncludeProcessFlags(doc, 0));
2534: }
2535:
2536: /**
2537: * xmlXIncludeProcessTreeFlags:
2538: * @tree: a node in an XML document
2539: * @flags: a set of xmlParserOption used for parsing XML includes
2540: *
2541: * Implement the XInclude substitution for the given subtree
2542: *
2543: * Returns 0 if no substitution were done, -1 if some processing failed
2544: * or the number of substitutions done.
2545: */
2546: int
2547: xmlXIncludeProcessTreeFlags(xmlNodePtr tree, int flags) {
2548: xmlXIncludeCtxtPtr ctxt;
2549: int ret = 0;
2550:
2551: if ((tree == NULL) || (tree->doc == NULL))
2552: return(-1);
2553: ctxt = xmlXIncludeNewContext(tree->doc);
2554: if (ctxt == NULL)
2555: return(-1);
2556: ctxt->base = xmlNodeGetBase(tree->doc, tree);
2557: xmlXIncludeSetFlags(ctxt, flags);
2558: ret = xmlXIncludeDoProcess(ctxt, tree->doc, tree);
2559: if ((ret >= 0) && (ctxt->nbErrors > 0))
2560: ret = -1;
2561:
2562: xmlXIncludeFreeContext(ctxt);
2563: return(ret);
2564: }
2565:
2566: /**
2567: * xmlXIncludeProcessTree:
2568: * @tree: a node in an XML document
2569: *
2570: * Implement the XInclude substitution for the given subtree
2571: *
2572: * Returns 0 if no substitution were done, -1 if some processing failed
2573: * or the number of substitutions done.
2574: */
2575: int
2576: xmlXIncludeProcessTree(xmlNodePtr tree) {
2577: return(xmlXIncludeProcessTreeFlags(tree, 0));
2578: }
2579:
2580: /**
2581: * xmlXIncludeProcessNode:
2582: * @ctxt: an existing XInclude context
2583: * @node: a node in an XML document
2584: *
2585: * Implement the XInclude substitution for the given subtree reusing
2586: * the informations and data coming from the given context.
2587: *
2588: * Returns 0 if no substitution were done, -1 if some processing failed
2589: * or the number of substitutions done.
2590: */
2591: int
2592: xmlXIncludeProcessNode(xmlXIncludeCtxtPtr ctxt, xmlNodePtr node) {
2593: int ret = 0;
2594:
2595: if ((node == NULL) || (node->doc == NULL) || (ctxt == NULL))
2596: return(-1);
2597: ret = xmlXIncludeDoProcess(ctxt, node->doc, node);
2598: if ((ret >= 0) && (ctxt->nbErrors > 0))
2599: ret = -1;
2600: return(ret);
2601: }
2602:
2603: #else /* !LIBXML_XINCLUDE_ENABLED */
2604: #endif
2605: #define bottom_xinclude
2606: #include "elfgcchack.h"
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>