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