PageRenderTime 59ms CodeModel.GetById 7ms app.highlight 45ms RepoModel.GetById 2ms app.codeStats 0ms

/functions.c

http://github.com/fizx/parsley
C | 368 lines | 307 code | 42 blank | 19 comment | 100 complexity | 94c9f19fc4277f6deec1653024243e21 MD5 | raw file
  1#include <stdbool.h>
  2#include <libxml/xpath.h>
  3#include <libxml/xpathInternals.h>
  4#include <libxml/parserInternals.h>
  5#include <libxml/uri.h>
  6#include <libxml/xpointer.h>
  7#include <libxml/xinclude.h>
  8#include <libxml/HTMLparser.h>
  9#include <libxml/HTMLtree.h>
 10#include <libxslt/xslt.h>
 11#include <libxslt/imports.h>
 12#include <libxslt/xsltInternals.h>
 13#include <libxslt/security.h>
 14#include <libxslt/xsltutils.h>
 15#include <libxslt/transform.h>
 16#include <libxslt/extensions.h>
 17#include <libxslt/documents.h>
 18#include "functions.h"
 19
 20
 21void parsley_register_all(){
 22	xsltRegisterExtModuleFunction ((const xmlChar *) "html-document", "http://parselets.com/stdlib",
 23		   xsltHtmlDocumentFunction);
 24  xsltRegisterExtModuleFunction ((const xmlChar *) "outer-xml", "http://parselets.com/stdlib",
 25		   xsltOuterXmlFunction);
 26  xsltRegisterExtModuleFunction ((const xmlChar *) "inner-xml", "http://parselets.com/stdlib",
 27		   xsltInnerXmlFunction);
 28}
 29
 30static void 
 31xsltStarXMLFunction(xmlXPathParserContextPtr ctxt, int nargs, bool is_inner) {
 32	if (nargs != 1) {
 33		xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
 34												"outer-xml() : invalid number of args %d\n",
 35												nargs);
 36		ctxt->error = XPATH_INVALID_ARITY;
 37		return;
 38	}
 39	if (ctxt->value->type == XPATH_NODESET) {
 40		xmlXPathObjectPtr obj, newobj;
 41
 42		obj = valuePop(ctxt);
 43
 44		xmlBufferPtr buf = xmlBufferCreate();
 45		int n = obj->nodesetval->nodeNr;
 46		for(int i = 0; i < n; i++) {
 47			xmlNodePtr node = obj->nodesetval->nodeTab[i];
 48			xmlDocPtr doc = node->doc;
 49			if(is_inner){
 50				xmlNodePtr child = node->children;
 51				while(child != NULL) {
 52					xmlNodeDump(buf, doc, child, 0, 0);
 53					child = child->next;
 54				}
 55			} else {
 56				xmlNodeDump(buf, doc, node, 0, 0);
 57			}
 58		}
 59		newobj = xmlXPathNewCString(xmlBufferContent(buf));
 60		xmlBufferFree(buf);
 61		valuePush(ctxt, newobj);
 62	}
 63}
 64
 65void
 66xsltInnerXmlFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 67	xsltStarXMLFunction(ctxt, nargs, true);
 68}
 69
 70void
 71xsltOuterXmlFunction(xmlXPathParserContextPtr ctxt, int nargs) {
 72	xsltStarXMLFunction(ctxt, nargs, false);
 73}
 74
 75void
 76xsltHtmlDocumentFunction(xmlXPathParserContextPtr ctxt, int nargs)
 77{
 78    xmlXPathObjectPtr obj, obj2 = NULL;
 79    xmlChar *base = NULL, *URI;
 80
 81
 82    if ((nargs < 1) || (nargs > 2)) {
 83        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
 84                         "document() : invalid number of args %d\n",
 85                         nargs);
 86        ctxt->error = XPATH_INVALID_ARITY;
 87        return;
 88    }
 89    if (ctxt->value == NULL) {
 90        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
 91                         "document() : invalid arg value\n");
 92        ctxt->error = XPATH_INVALID_TYPE;
 93        return;
 94    }
 95
 96    if (nargs == 2) {
 97        if (ctxt->value->type != XPATH_NODESET) {
 98            xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
 99                             "document() : invalid arg expecting a nodeset\n");
100            ctxt->error = XPATH_INVALID_TYPE;
101            return;
102        }
103
104        obj2 = valuePop(ctxt);
105    }
106
107    if (ctxt->value->type == XPATH_NODESET) {
108        int i;
109        xmlXPathObjectPtr newobj, ret;
110
111        obj = valuePop(ctxt);
112        ret = xmlXPathNewNodeSet(NULL);
113
114        if (obj->nodesetval) {
115            for (i = 0; i < obj->nodesetval->nodeNr; i++) {
116                valuePush(ctxt,
117                          xmlXPathNewNodeSet(obj->nodesetval->nodeTab[i]));
118                xmlXPathStringFunction(ctxt, 1);
119                if (nargs == 2) {
120                    valuePush(ctxt, xmlXPathObjectCopy(obj2));
121                } else {
122                    valuePush(ctxt,
123                              xmlXPathNewNodeSet(obj->nodesetval->
124                                                 nodeTab[i]));
125                }
126                xsltHtmlDocumentFunction(ctxt, 2);
127                newobj = valuePop(ctxt);
128                ret->nodesetval = xmlXPathNodeSetMerge(ret->nodesetval,
129                                                       newobj->nodesetval);
130                xmlXPathFreeObject(newobj);
131            }
132        }
133
134        xmlXPathFreeObject(obj);
135        if (obj2 != NULL)
136            xmlXPathFreeObject(obj2);
137        valuePush(ctxt, ret);
138        return;
139    }
140    /*
141     * Make sure it's converted to a string
142     */
143    xmlXPathStringFunction(ctxt, 1);
144    if (ctxt->value->type != XPATH_STRING) {
145        xsltTransformError(xsltXPathGetTransformContext(ctxt), NULL, NULL,
146                         "document() : invalid arg expecting a string\n");
147        ctxt->error = XPATH_INVALID_TYPE;
148        if (obj2 != NULL)
149            xmlXPathFreeObject(obj2);
150        return;
151    }
152    obj = valuePop(ctxt);
153    if (obj->stringval == NULL) {
154        valuePush(ctxt, xmlXPathNewNodeSet(NULL));
155    } else {
156        if ((obj2 != NULL) && (obj2->nodesetval != NULL) &&
157            (obj2->nodesetval->nodeNr > 0) &&
158            IS_XSLT_REAL_NODE(obj2->nodesetval->nodeTab[0])) {
159            xmlNodePtr target;
160
161            target = obj2->nodesetval->nodeTab[0];
162            if ((target->type == XML_ATTRIBUTE_NODE) ||
163	        (target->type == XML_PI_NODE)) {
164                target = ((xmlAttrPtr) target)->parent;
165            }
166            base = xmlNodeGetBase(target->doc, target);
167        } else {
168            xsltTransformContextPtr tctxt;
169
170            tctxt = xsltXPathGetTransformContext(ctxt);
171            if ((tctxt != NULL) && (tctxt->inst != NULL)) {
172                base = xmlNodeGetBase(tctxt->inst->doc, tctxt->inst);
173            } else if ((tctxt != NULL) && (tctxt->style != NULL) &&
174                       (tctxt->style->doc != NULL)) {
175                base = xmlNodeGetBase(tctxt->style->doc,
176                                      (xmlNodePtr) tctxt->style->doc);
177            }
178        }
179        URI = xmlBuildURI(obj->stringval, base);
180        if (base != NULL)
181            xmlFree(base);
182        if (URI == NULL) {
183            valuePush(ctxt, xmlXPathNewNodeSet(NULL));
184        } else {
185	    xsltHtmlDocumentFunctionLoadDocument( ctxt, URI );
186	    xmlFree(URI);
187	}
188    }
189    xmlXPathFreeObject(obj);
190    if (obj2 != NULL)
191        xmlXPathFreeObject(obj2);
192}
193
194static void
195xsltHtmlDocumentFunctionLoadDocument(xmlXPathParserContextPtr ctxt, xmlChar* URI)
196{
197    xsltTransformContextPtr tctxt;
198    xmlURIPtr uri;
199    xmlChar *fragment;
200    xsltDocumentPtr idoc; /* document info */
201    xmlDocPtr doc;
202    xmlXPathContextPtr xptrctxt = NULL;
203    xmlXPathObjectPtr resObj = NULL;
204
205    tctxt = xsltXPathGetTransformContext(ctxt);
206    if (tctxt == NULL) {
207	xsltTransformError(NULL, NULL, NULL,
208	    "document() : internal error tctxt == NULL\n");
209	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
210	return;
211    } 
212	
213    uri = xmlParseURI((const char *) URI);
214    if (uri == NULL) {
215	xsltTransformError(tctxt, NULL, NULL,
216	    "document() : failed to parse URI\n");
217	valuePush(ctxt, xmlXPathNewNodeSet(NULL));
218	return;
219    } 
220    
221    /*
222     * check for and remove fragment identifier
223     */
224    fragment = (xmlChar *)uri->fragment;
225    if (fragment != NULL) {
226        xmlChar *newURI;
227	uri->fragment = NULL;
228	newURI = xmlSaveUri(uri);
229	idoc = xsltLoadHtmlDocument(tctxt, newURI);
230	xmlFree(newURI);
231    } else
232	idoc = xsltLoadHtmlDocument(tctxt, URI);
233    xmlFreeURI(uri);
234    
235    if (idoc == NULL) {
236	if ((URI == NULL) ||
237	    (URI[0] == '#') ||
238	    ((tctxt->style->doc != NULL) &&
239	    (xmlStrEqual(tctxt->style->doc->URL, URI)))) 
240	{
241	    /*
242	    * This selects the stylesheet's doc itself.
243	    */
244	    doc = tctxt->style->doc;
245	} else {
246	    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
247
248	    if (fragment != NULL)
249		xmlFree(fragment);
250
251	    return;
252	}
253    } else
254	doc = idoc->doc;
255
256    if (fragment == NULL) {
257	valuePush(ctxt, xmlXPathNewNodeSet((xmlNodePtr) doc));
258	return;
259    }
260	
261    /* use XPointer of HTML location for fragment ID */
262#ifdef LIBXML_XPTR_ENABLED
263    xptrctxt = xmlXPtrNewContext(doc, NULL, NULL);
264    if (xptrctxt == NULL) {
265	xsltTransformError(tctxt, NULL, NULL,
266	    "document() : internal error xptrctxt == NULL\n");
267	goto out_fragment;
268    }
269
270    resObj = xmlXPtrEval(fragment, xptrctxt);
271    xmlXPathFreeContext(xptrctxt);
272#endif
273    xmlFree(fragment);	
274
275    if (resObj == NULL)
276	goto out_fragment;
277	
278    switch (resObj->type) {
279	case XPATH_NODESET:
280	    break;
281	case XPATH_UNDEFINED:
282	case XPATH_BOOLEAN:
283	case XPATH_NUMBER:
284	case XPATH_STRING:
285	case XPATH_POINT:
286	case XPATH_USERS:
287	case XPATH_XSLT_TREE:
288	case XPATH_RANGE:
289	case XPATH_LOCATIONSET:
290	    xsltTransformError(tctxt, NULL, NULL,
291		"document() : XPointer does not select a node set: #%s\n", 
292		fragment);
293	goto out_object;
294    }
295    
296    valuePush(ctxt, resObj);
297    return;
298
299out_object:
300    xmlXPathFreeObject(resObj);
301
302out_fragment:
303    valuePush(ctxt, xmlXPathNewNodeSet(NULL));
304}
305
306xsltDocumentPtr	
307xsltLoadHtmlDocument(xsltTransformContextPtr ctxt, const xmlChar *URI) {
308    xsltDocumentPtr ret;
309    xmlDocPtr doc;
310
311    if ((ctxt == NULL) || (URI == NULL))
312	return(NULL);
313
314    /*
315     * Security framework check
316     */
317    if (ctxt->sec != NULL) {
318	int res;
319	
320	res = xsltCheckRead(ctxt->sec, ctxt, URI);
321	if (res == 0) {
322	    xsltTransformError(ctxt, NULL, NULL,
323		 "xsltLoadHtmlDocument: read rights for %s denied\n",
324			     URI);
325	    return(NULL);
326	}
327    }
328
329    /*
330     * Walk the context list to find the document if preparsed
331     */
332    ret = ctxt->docList;
333    while (ret != NULL) {
334	if ((ret->doc != NULL) && (ret->doc->URL != NULL) &&
335	    (xmlStrEqual(ret->doc->URL, URI)))
336	    return(ret);
337	ret = ret->next;
338    }
339
340    doc = htmlReadFile(URI, NULL, ctxt->parserOptions | HTML_PARSE_RECOVER | HTML_PARSE_NOERROR |HTML_PARSE_NOWARNING);
341
342    if (doc == NULL)
343	return(NULL);
344
345    if (ctxt->xinclude != 0) {
346#ifdef LIBXML_XINCLUDE_ENABLED
347#if LIBXML_VERSION >= 20603
348	xmlXIncludeProcessFlags(doc, ctxt->parserOptions);
349#else
350	xmlXIncludeProcess(doc);
351#endif
352#else
353	xsltTransformError(ctxt, NULL, NULL,
354	    "xsltLoadHtmlDocument(%s) : XInclude processing not compiled in\n",
355	                 URI);
356#endif
357    }
358    /*
359     * Apply white-space stripping if asked for
360     */
361    if (xsltNeedElemSpaceHandling(ctxt))
362	xsltApplyStripSpaces(ctxt, xmlDocGetRootElement(doc));
363    if (ctxt->debugStatus == XSLT_DEBUG_NONE)
364	xmlXPathOrderDocElems(doc);
365
366    ret = xsltNewDocument(ctxt, doc);
367    return(ret);
368}