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