root/trunk/xsltDocHack.c

Revision 32, 11.6 kB (checked in by jesus, 7 years ago)

completely reimplement the document() function minus some evil

Line 
1 #include <unistd.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <libxml/xmlmemory.h>
5 #include <libxml/tree.h>
6 #include <libxml/hash.h>
7 #include <libxml/parser.h>
8 #include <libxml/parserInternals.h>
9 #include <libxml/valid.h>
10 #include <libxml/xmlerror.h>
11 #include <libxml/xpath.h>
12 #include <libxml/xpathInternals.h>
13 #include <libxml/uri.h>
14 #include <libxml/xpointer.h>
15 #include <libxml/xinclude.h>
16 #include <libxslt/xslt.h>
17 #include <libxslt/xsltInternals.h>
18 #include <libxslt/xsltutils.h>
19 #include <libxslt/documents.h>
20 #include <libxslt/transform.h>
21 #include <libxslt/imports.h>
22 #include <libxslt/keys.h>
23 #include <libxslt/security.h>
24 #include <libxslt/extensions.h>
25
26 xsltDocumentPtr
27 HACK_xsltNewDocument(xsltTransformContextPtr ctxt, xmlDocPtr doc) {
28     xsltDocumentPtr cur;
29
30     cur = (xsltDocumentPtr) xmlMalloc(sizeof(xsltDocument));
31     if (cur == NULL) {
32         xsltTransformError(ctxt, NULL, (xmlNodePtr) doc,
33                 "xsltNewDocument : malloc failed\n");
34         return(NULL);
35     }
36     memset(cur, 0, sizeof(xsltDocument));
37     cur->doc = doc;
38     if (ctxt != NULL) {
39 /* THIS IS THE WHOLE REASON FOR THE HACK */
40 /* This cannot run, as it will cause some wicked freeing
41         if (! XSLT_IS_RES_TREE_FRAG(doc)) {
42             cur->next = ctxt->docList;
43             ctxt->docList = cur;
44         }
45 */
46 #ifdef XSLT_REFACTORED_KEYCOMP
47         /*
48         * A key with a specific name for a specific document
49         * will only be computed if there's a call to the key()
50         * function using that specific name for that specific
51         * document. I.e. computation of keys will be done in
52         * xsltGetKey() (keys.c) on an on-demand basis.
53         */
54 #else
55         /*
56         * Old behaviour.
57         */
58         xsltInitCtxtKeys(ctxt, cur);
59 #endif
60     }
61     return(cur);
62 }
63
64 xmlDocPtr
65 HACK_xsltDocDefaultLoaderFunc(const xmlChar * URI, xmlDictPtr dict,
66                                 int options, void *ctxt, xsltLoadType type)
67 {
68     xmlParserCtxtPtr pctxt;
69     xmlParserInputPtr inputStream;
70     xmlDocPtr doc;
71
72     pctxt = xmlNewParserCtxt();
73     if (pctxt == NULL)
74         return(NULL);
75     if ((dict != NULL) && (pctxt->dict != NULL)) {
76         xmlDictFree(pctxt->dict);
77         pctxt->dict = NULL;
78     }
79     if (dict != NULL) {
80         pctxt->dict = dict;
81         xmlDictReference(pctxt->dict);
82 #ifdef WITH_XSLT_DEBUG
83         xsltGenericDebug(xsltGenericDebugContext,
84                      "Reusing dictionary for document\n");
85 #endif
86     }
87     xmlCtxtUseOptions(pctxt, options);
88     inputStream = xmlLoadExternalEntity((const char *) URI, NULL, pctxt);
89     if (inputStream == NULL) {
90         xmlFreeParserCtxt(pctxt);
91         return(NULL);
92     }
93     inputPush(pctxt, inputStream);
94     if (pctxt->directory == NULL)
95         pctxt->directory = xmlParserGetDirectory((const char *) URI);
96
97     xmlParseDocument(pctxt);
98
99     if (pctxt->wellFormed) {
100         doc = pctxt->myDoc;
101     }
102     else {
103         doc = NULL;
104         xmlFreeDoc(pctxt->myDoc);
105         pctxt->myDoc = NULL;
106     }
107     xmlFreeParserCtxt(pctxt);
108
109     return(doc);
110 }
111
112 xsltDocumentPtr
113 HACK_xsltLoadDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
114     xsltDocumentPtr ret;
115     xmlDocPtr doc;
116
117     if ((ctxt == NULL) || (URI == NULL))
118         return(NULL);
119
120     /*
121      * Security framework check
122      */
123     if (ctxt->sec != NULL) {
124         int res;
125
126         res = xsltCheckRead(ctxt->sec, ctxt, URI);
127         if (res == 0) {
128             xsltTransformError(ctxt, NULL, NULL,
129                  "xsltLoadDocument: read rights for %s denied\n",
130                              URI);
131             return(NULL);
132         }
133     }
134
135     /*
136      * Walk the context list to find the document if preparsed
137      */
138 /* HACK point.. we assume it is not prepared..
139    we'd have returned it from cache if it were */
140 /*
141     ret = ctxt->docList;
142     while (ret != NULL) {
143         if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
144             (xmlStrEqual(ret->doc->URL, URI)))
145             return(ret);
146         ret = ret->next;
147     }
148 */
149     doc = HACK_xsltDocDefaultLoaderFunc(URI, /* We don't want this, it's not shared: ctxt->dict */ NULL, ctxt->parserOptions,
150                                         (void *) ctxt, XSLT_LOAD_DOCUMENT);
151
152     if (doc == NULL)
153         return(NULL);
154
155     if (ctxt->xinclude != 0) {
156 #ifdef LIBXML_XINCLUDE_ENABLED
157 #if LIBXML_VERSION >= 20603
158         xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
159 #else
160         xmlXIncludeProcess(doc);
161 #endif
162 #else
163         xsltTransformError(ctxt, NULL, NULL,
164             "xsltLoadDocument(%s) : XInclude processing not compiled in\n",
165                          URI);
166 #endif
167     }
168     /*
169      * Apply white-space stripping if asked for
170      */
171     if (xsltNeedElemSpaceHandling(ctxt))
172         xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
173     if (ctxt->debugStatus == XSLT_DEBUG_NONE)
174         xmlXPathOrderDocElems(doc);
175
176     ret = HACK_xsltNewDocument(ctxt, doc);
177     return(ret);
178 }
179
180 void
181 HACK_xsltDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
182 {
183     xsltTransformContextPtr tctxt;
184     xmlURIPtr uri;
185     xmlChar *fragment;
186     xsltDocumentPtr idoc; /* document info */
187     xmlDocPtr doc;
188     xmlXPathContextPtr xptrctxt = NULL;
189     xmlXPathObjectPtr resObj = NULL;
190
191     tctxt = xsltXPathGetTransformContext(ctxt);
192     if (tctxt == NULL) {
193         xsltTransformError(NULL, NULL, NULL,
194             "document() : internal error tctxt == NULL\n");
195         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
196         return;
197     }
198
199     uri = xmlParseURI((const char *) URI);
200     if (uri == NULL) {
201         xsltTransformError(tctxt, NULL, NULL,
202             "document() : failed to parse URI\n");
203         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
204         return;
205     }
206
207     /*
208      * check for and remove fragment identifier
209      */
210     fragment = (xmlChar *)uri->fragment;
211     if (fragment != NULL) {
212         uri->fragment = NULL;
213         URI = xmlSaveUri(uri);
214         idoc = HACK_xsltLoadDocument(tctxt, URI);
215         xmlFree(URI);
216     } else
217         idoc = HACK_xsltLoadDocument(tctxt, URI);
218     xmlFreeURI(uri);
219
220     if (idoc == NULL) {
221         if ((URI == NULL) ||
222             (URI[0] == '#') ||
223             (xmlStrEqual(tctxt->style->doc->URL, URI)))
224         {
225             /*
226             * This selects the stylesheet's doc itself.
227             */
228             doc = tctxt->style->doc;
229         } else {
230             valuePush(ctxt, xmlXPathNewNodeSet(NULL));
231
232             if (fragment != NULL)
233                 xmlFree(fragment);
234
235             return;
236         }
237     } else
238         doc = idoc->doc;
239
240     if (fragment == NULL) {
241         valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
242         return;
243     }
244
245     /* use XPointer of HTML location for fragment ID */
246 #ifdef LIBXML_XPTR_ENABLED
247     xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
248     if (xptrctxt == NULL) {
249         xsltTransformError(tctxt, NULL, NULL,
250             "document() : internal error xptrctxt == NULL\n");
251         goto out_fragment;
252     }
253
254     resObj = xmlXPtrEval(fragment, xptrctxt);
255     xmlXPathFreeContext(xptrctxt);
256 #endif
257     xmlFree(fragment);
258
259     if (resObj == NULL)
260         goto out_fragment;
261
262     switch (resObj->type) {
263         case XPATH_NODESET:
264             break;
265         case XPATH_UNDEFINED:
266         case XPATH_BOOLEAN:
267         case XPATH_NUMBER:
268         case XPATH_STRING:
269         case XPATH_POINT:
270         case XPATH_USERS:
271         case XPATH_XSLT_TREE:
272         case XPATH_RANGE:
273         case XPATH_LOCATIONSET:
274             xsltTransformError(tctxt, NULL, NULL,
275                 "document() : XPointer does not select a node set: #%s\n",
276                 fragment);
277         goto out_object;
278     }
279
280     valuePush(ctxt, resObj);
281     return;
282
283 out_object:
284     xmlXPathFreeObject(resObj);
285
286 out_fragment:
287     valuePush(ctxt, xmlXPathNewNodeSet(NULL));
288 }
289
290 void
291 HACK_xsltDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
292 {
293     xmlXPathObjectPtr obj, obj2 = NULL;
294     xmlChar *base = NULL, *URI;
295
296
297     if ((nargs < 1) || (nargs > 2)) {
298         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
299                          "document() : invalid number of args %d\n",
300                          nargs);
301         ctxt->error = XPATH_INVALID_ARITY;
302         return;
303     }
304     if (ctxt->value == NULL) {
305         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
306                          "document() : invalid arg value\n");
307         ctxt->error = XPATH_INVALID_TYPE;
308         return;
309     }
310
311     if (nargs == 2) {
312         if (ctxt->value->type != XPATH_NODESET) {
313             xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
314                              "document() : invalid arg expecting a nodeset\n");
315             ctxt->error = XPATH_INVALID_TYPE;
316             return;
317         }
318
319         obj2 = valuePop(ctxt);
320     }
321
322     if (ctxt->value->type == XPATH_NODESET) {
323         int i;
324         xmlXPathObjectPtr newobj, ret;
325
326         obj = valuePop(ctxt);
327         ret = xmlXPathNewNodeSet(NULL);
328
329         if (obj->nodesetval) {
330             for (i = 0; i < obj->nodesetval->nodeNr; i++) {
331                 valuePush(ctxt,
332                           xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
333                 xmlXPathStringFunction(ctxt, 1);
334                 if (nargs == 2) {
335                     valuePush(ctxt, xmlXPathObjectCopy(obj2));
336                 } else {
337                     valuePush(ctxt,
338                               xmlXPathNewNodeSet(obj->nodesetval->
339                                                  nodeTab[i]));
340                 }
341                 HACK_xsltDocumentFunction(ctxt, 2);
342                 newobj = valuePop(ctxt);
343                 ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
344                                                        newobj->nodesetval);
345                 xmlXPathFreeObject(newobj);
346             }
347         }
348
349         xmlXPathFreeObject(obj);
350         if (obj2 != NULL)
351             xmlXPathFreeObject(obj2);
352         valuePush(ctxt, ret);
353         return;
354     }
355     /*
356      * Make sure it's converted to a string
357      */
358     xmlXPathStringFunction(ctxt, 1);
359     if (ctxt->value->type != XPATH_STRING) {
360         xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
361                          "document() : invalid arg expecting a string\n");
362         ctxt->error = XPATH_INVALID_TYPE;
363         if (obj2 != NULL)
364             xmlXPathFreeObject(obj2);
365         return;
366     }
367     obj = valuePop(ctxt);
368     if (obj->stringval == NULL) {
369         valuePush(ctxt, xmlXPathNewNodeSet(NULL));
370     } else {
371         if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
372             (obj2->nodesetval->nodeNr > 0) &&
373             IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
374             xmlNodePtr target;
375
376             target = obj2->nodesetval->nodeTab[0];
377             if ((target->type == XML_ATTRIBUTE_NODE) ||
378                 (target->type == XML_PI_NODE)) {
379                 target = ((xmlAttrPtr) target)->parent;
380             }
381             base = xmlNodeGetBase(target->doc, target);
382         } else {
383             xsltTransformContextPtr tctxt;
384
385             tctxt = xsltXPathGetTransformContext(ctxt);
386             if ((tctxt != NULL) && (tctxt->inst != NULL)) {
387                 base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
388             } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
389                        (tctxt->style->doc != NULL)) {
390                 base = xmlNodeGetBase(tctxt->style->doc,
391                                       (xmlNodePtr) tctxt->style->doc);
392             }
393         }
394         URI = xmlBuildURI(obj->stringval, base);
395         if (base != NULL)
396             xmlFree(base);
397         if (URI == NULL) {
398             valuePush(ctxt, xmlXPathNewNodeSet(NULL));
399         } else {
400             HACK_xsltDocumentFunctionLoadDocument( ctxt, URI );
401             xmlFree(URI);
402         }
403     }
404     xmlXPathFreeObject(obj);
405     if (obj2 != NULL)
406         xmlXPathFreeObject(obj2);
407 }
408
Note: See TracBrowser for help on using the browser.