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