1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 
29 // MARKER(update_precomp.py): autogen include statement, do not remove
30 #include "precompiled_forms.hxx"
31 #include <string.h>
32 #include <sal/types.h>
33 #include <rtl/alloc.h>
34 #include <rtl/ustring.hxx>
35 #include <rtl/string.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <rtl/strbuf.hxx>
38 #include <tools/date.hxx>
39 #include <tools/time.hxx>
40 #include <tools/datetime.hxx>
41 
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <com/sun/star/uno/Sequence.hxx>
44 #include <com/sun/star/uno/Any.hxx>
45 #include <com/sun/star/xforms/XModel.hpp>
46 #include <com/sun/star/xml/dom/XNode.hpp>
47 #include <com/sun/star/xml/dom/XDocument.hpp>
48 #include <com/sun/star/lang/XUnoTunnel.hpp>
49 
50 #include "xpathlib.hxx"
51 
52 #include "extension.hxx"
53 
54 // C interface
55 
56 using namespace com::sun::star::uno;
57 using namespace com::sun::star::xml::dom;
58 using namespace com::sun::star::xforms;
59 using namespace com::sun::star::lang;
60 
61 xmlXPathFunction xforms_lookupFunc(void *, const xmlChar *xname, const xmlChar *)
62 {
63 
64     const char *name = (char *)xname;
65     if (strcmp("boolean-from-string", name)==0)
66         return xforms_booleanFromStringFunction;
67     else if ((strcmp("if", name))==0)
68         return xforms_ifFunction;
69     else if ((strcmp("avg", name))==0)
70         return xforms_avgFunction;
71     else if ((strcmp("min", name))==0)
72         return xforms_minFunction;
73     else if ((strcmp("max", name))==0)
74         return xforms_maxFunction;
75     else if ((strcmp("count-non-empty", name))==0)
76         return xforms_countNonEmptyFunction;
77     else if ((strcmp("index", name))==0)
78         return xforms_indexFunction;
79     else if ((strcmp("property", name))==0)
80         return xforms_propertyFunction;
81     else if ((strcmp("now", name))==0)
82         return xforms_nowFunction;
83     else if ((strcmp("days-from-date", name))==0)
84         return xforms_daysFromDateFunction;
85     else if ((strcmp("seconds-from-dateTime", name))==0)
86         return xforms_secondsFromDateTimeFunction;
87     else if ((strcmp("seconds", name))==0)
88         return xforms_secondsFuction;
89     else if ((strcmp("months", name))==0)
90         return xforms_monthsFuction;
91     else if ((strcmp("instance", name))==0)
92         return xforms_instanceFuction;
93     else if ((strcmp("current", name))==0)
94         return xforms_currentFunction;
95     else
96         return NULL;
97 }
98 
99 // boolean functions
100 void xforms_booleanFromStringFunction(xmlXPathParserContextPtr ctxt, int nargs)
101 {
102     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
103     xmlChar *pString = xmlXPathPopString(ctxt);
104     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
105     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
106     if (aString.equalsIgnoreAsciiCaseAscii("true") || aString.equalsIgnoreAsciiCaseAscii("1"))
107         xmlXPathReturnTrue(ctxt);
108     else if (aString.equalsIgnoreAsciiCaseAscii("false") || aString.equalsIgnoreAsciiCaseAscii("0"))
109         xmlXPathReturnFalse(ctxt);
110     else
111         XP_ERROR(XPATH_NUMBER_ERROR);
112 }
113 
114 void xforms_ifFunction(xmlXPathParserContextPtr ctxt, int nargs)
115 {
116     if (nargs != 3) XP_ERROR(XPATH_INVALID_ARITY);
117     xmlChar *s2 = xmlXPathPopString(ctxt);
118 
119     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
120     xmlChar *s1 = xmlXPathPopString(ctxt);
121     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
122     bool aBool = xmlXPathPopBoolean(ctxt);
123     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
124 
125     if (aBool)
126         xmlXPathReturnString(ctxt, s1);
127     else
128         xmlXPathReturnString(ctxt, s2);
129 
130 }
131 
132 // Number Functions
133 void xforms_avgFunction(xmlXPathParserContextPtr ctxt, int nargs)
134 {
135     // use sum(), div() and count()
136     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
137 
138     // save nodeset
139     xmlXPathObjectPtr pObject = valuePop(ctxt);
140     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
141     //push back a copy
142     valuePush(ctxt, xmlXPathObjectCopy(pObject));
143     // get the Sum
144     xmlXPathSumFunction(ctxt, 1);
145     double nSum = xmlXPathPopNumber(ctxt);
146     // push a copy once more
147     valuePush(ctxt, xmlXPathObjectCopy(pObject));
148     xmlXPathCountFunction(ctxt, 1);
149     double nCount = xmlXPathPopNumber(ctxt);
150     // push args for div()
151     xmlXPathReturnNumber(ctxt, nSum);
152     xmlXPathReturnNumber(ctxt, nCount);
153     xmlXPathDivValues(ctxt);
154     // the result is now on the ctxt stack
155     xmlXPathFreeObject(pObject);
156 }
157 
158 void xforms_minFunction(xmlXPathParserContextPtr ctxt, int nargs)
159 {
160     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
161     xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt);
162     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
163     double nMinimum = 0;
164     double nNumber = 0;
165     for (int i = 0; i <  xmlXPathNodeSetGetLength(pNodeSet); i++)
166     {
167         nNumber = xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pNodeSet, i));
168         if (xmlXPathIsNaN(nNumber))
169         {
170             xmlXPathReturnNumber(ctxt, xmlXPathNAN);
171             return;
172         }
173         if (i == 0)
174             nMinimum = nNumber;
175         else if (nNumber < nMinimum)
176             nMinimum = nNumber;
177     }
178     xmlXPathReturnNumber(ctxt, nMinimum);
179 }
180 
181 void xforms_maxFunction(xmlXPathParserContextPtr ctxt, int nargs)
182 {
183     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
184     xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt);
185     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
186     double nMaximum = 0;
187     double nNumber = 0;
188     for (int i = 0; i <  xmlXPathNodeSetGetLength(pNodeSet); i++)
189     {
190         nNumber = xmlXPathCastNodeToNumber(xmlXPathNodeSetItem(pNodeSet, i));
191         if (xmlXPathIsNaN(nNumber))
192         {
193             xmlXPathReturnNumber(ctxt, xmlXPathNAN);
194             return;
195         }
196         if (i == 0)
197             nMaximum = nNumber;
198         else if (nNumber > nMaximum)
199             nMaximum = nNumber;
200     }
201     xmlXPathReturnNumber(ctxt, nMaximum);
202 }
203 void xforms_countNonEmptyFunction(xmlXPathParserContextPtr ctxt, int nargs)
204 {
205     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
206     xmlNodeSetPtr pNodeSet = xmlXPathPopNodeSet(ctxt);
207     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
208     xmlChar *aString;
209     sal_Int32 nNotEmpty = 0;
210     for (int i = 0; i <  xmlXPathNodeSetGetLength(pNodeSet); i++)
211     {
212         aString = xmlXPathCastNodeToString(xmlXPathNodeSetItem(pNodeSet, i));
213         if (strlen((char*)aString) > 0) nNotEmpty++;
214     }
215     xmlXPathReturnNumber(ctxt, nNotEmpty);
216 }
217 void xforms_indexFunction(xmlXPathParserContextPtr /*ctxt*/, int /*nargs*/)
218 {
219     // function index takes a string argument that is the IDREF of a
220     // 'repeat' and returns the current 1-based position of the repeat
221     // index of the identified repeat -- see xforms/9.3.1
222 
223     // doc.getElementByID
224     // (...)
225 }
226 
227 // String Functions
228 static const char* _version = "1.0";
229 static const char* _conformance = "conformance";
230 void xforms_propertyFunction(xmlXPathParserContextPtr ctxt, int nargs)
231 {
232     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
233     xmlChar* pString = xmlXPathPopString(ctxt);
234     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
235     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
236     if (aString.equalsIgnoreAsciiCaseAscii("version"))
237         xmlXPathReturnString(ctxt, (xmlChar*)_version);
238     else if (aString.equalsIgnoreAsciiCaseAscii("conformance-level"))
239         xmlXPathReturnString(ctxt, (xmlChar*)_conformance);
240     else
241         xmlXPathReturnEmptyString(ctxt);
242 }
243 
244 // Date and Time Functions
245 
246 static ::rtl::OString makeDateTimeString (const DateTime& aDateTime, sal_Bool bUTC = sal_True)
247 {
248     ::rtl::OStringBuffer aDateTimeString;
249     aDateTimeString.append((sal_Int32)aDateTime.GetYear());
250     aDateTimeString.append("-");
251     if (aDateTime.GetMonth()<10) aDateTimeString.append("0");
252     aDateTimeString.append((sal_Int32)aDateTime.GetMonth());
253     aDateTimeString.append("-");
254     if (aDateTime.GetDay()<10) aDateTimeString.append("0");
255     aDateTimeString.append((sal_Int32)aDateTime.GetDay());
256     aDateTimeString.append("T");
257     if (aDateTime.GetHour()<10) aDateTimeString.append("0");
258     aDateTimeString.append((sal_Int32)aDateTime.GetHour());
259     aDateTimeString.append(":");
260     if (aDateTime.GetMin()<10) aDateTimeString.append("0");
261     aDateTimeString.append((sal_Int32)aDateTime.GetMin());
262     aDateTimeString.append(":");
263     if (aDateTime.GetSec()<10) aDateTimeString.append("0");
264     aDateTimeString.append((sal_Int32)aDateTime.GetSec());
265     if (bUTC) aDateTimeString.append("Z");
266 
267     return aDateTimeString.makeStringAndClear();
268 }
269 
270 // returns current system date and time in canonical xsd:dateTime
271 // format
272 void xforms_nowFunction(xmlXPathParserContextPtr ctxt, int /*nargs*/)
273 {
274     /*
275     A single lexical representation, which is a subset of the lexical representations
276     allowed by [ISO 8601], is allowed for dateTime. This lexical representation is the
277     [ISO 8601] extended format CCYY-MM-DDThh:mm:ss where "CC" represents the century,
278     "YY" the year, "MM" the month and "DD" the day, preceded by an optional leading "-"
279     sign to indicate a negative number. If the sign is omitted, "+" is assumed. The letter
280     "T" is the date/time separator and "hh", "mm", "ss" represent hour, minute and second
281     respectively.
282     */
283 
284     /*
285     3.2.7.2 Canonical representation
286     The canonical representation for dateTime is defined by prohibiting certain options
287     from the Lexical representation (par.3.2.7.1). Specifically, either the time zone must
288     be omitted or, if present, the time zone must be Coordinated Universal Time (UTC)
289     indicated by a "Z".
290     */
291     DateTime aDateTime;
292     ::rtl::OString aDateTimeString = makeDateTimeString(aDateTime);
293     xmlChar *pString = static_cast<xmlChar*>(xmlMalloc(aDateTimeString.getLength()+1));
294     strncpy((char*)pString, (char*)aDateTimeString.getStr(), aDateTimeString.getLength());
295     pString[aDateTimeString.getLength()] = 0;
296     xmlXPathReturnString(ctxt, pString);
297 }
298 
299 static sal_Bool parseDateTime(const ::rtl::OUString& aString, DateTime& aDateTime)
300 {
301     // take apart a canonical literal xsd:dateTime string
302     //CCYY-MM-DDThh:mm:ss(Z)
303 
304     ::rtl::OUString aDateTimeString = aString.trim();
305 
306     // check length
307     if (aDateTimeString.getLength() < 19 || aDateTimeString.getLength() > 20)
308         return sal_False;
309 
310     sal_Int32 nDateLength = 10;
311     sal_Int32 nTimeLength = 8;
312 
313     ::rtl::OUString aDateTimeSep = ::rtl::OUString::createFromAscii("T");
314     ::rtl::OUString aDateSep = ::rtl::OUString::createFromAscii("-");
315     ::rtl::OUString aTimeSep = ::rtl::OUString::createFromAscii(":");
316     ::rtl::OUString aUTCString = ::rtl::OUString::createFromAscii("Z");
317 
318     ::rtl::OUString aDateString = aDateTimeString.copy(0, nDateLength);
319     ::rtl::OUString aTimeString = aDateTimeString.copy(nDateLength+1, nTimeLength);
320 
321     sal_Int32 nIndex = 0;
322     sal_Int32 nYear = aDateString.getToken(0, '-', nIndex).toInt32();
323     sal_Int32 nMonth = aDateString.getToken(0, '-', nIndex).toInt32();
324     sal_Int32 nDay = aDateString.getToken(0, '-', nIndex).toInt32();
325     nIndex = 0;
326     sal_Int32 nHour = aTimeString.getToken(0, ':', nIndex).toInt32();
327     sal_Int32 nMinute = aTimeString.getToken(0, ':', nIndex).toInt32();
328     sal_Int32 nSecond = aTimeString.getToken(0, ':', nIndex).toInt32();
329 
330     Date tmpDate((sal_uInt16)nDay, (sal_uInt16)nMonth, (sal_uInt16)nYear);
331     Time tmpTime(nHour, nMinute, nSecond);
332     DateTime tmpDateTime(tmpDate, tmpTime);
333     if (aString.indexOf(aUTCString) < 0)
334         tmpDateTime.ConvertToUTC();
335 
336     aDateTime = tmpDateTime;
337 
338     return sal_True;
339 }
340 
341 
342 void xforms_daysFromDateFunction(xmlXPathParserContextPtr ctxt, int nargs)
343 {
344     // number of days from 1970-01-01 to supplied xsd:date(Time)
345 
346     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
347     xmlChar* pString = xmlXPathPopString(ctxt);
348     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
349     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
350 
351     DateTime aDateTime;
352     if (parseDateTime(aString, aDateTime))
353     {
354         Date aReferenceDate(1, 1, 1970);
355         sal_Int32 nDays = aDateTime - aReferenceDate;
356         xmlXPathReturnNumber(ctxt, nDays);
357     }
358     else
359         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
360 
361 
362 }
363 
364 
365 void xforms_secondsFromDateTimeFunction(xmlXPathParserContextPtr ctxt, int nargs)
366 {
367     // number of seconds from 1970-01-01T00:00:00Z to supplied xsd:date(Time)
368 
369     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
370     xmlChar* pString = xmlXPathPopString(ctxt);
371     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
372     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
373 
374     DateTime aDateTime;
375 
376     if (parseDateTime(aString, aDateTime))
377     {
378         Date aReferenceDate(1, 1, 1970);
379         Time aReferenceTime(0, 0, 0);
380         sal_Int32 nDays = aDateTime - aReferenceDate;
381         sal_Int32 nSeconds = nDays * 24 * 60 * 60;
382         nSeconds += aDateTime.GetHour() * 60 * 60;
383         nSeconds += aDateTime.GetMin() * 60;
384         nSeconds += aDateTime.GetSec();
385         xmlXPathReturnNumber(ctxt, nSeconds);
386     }
387     else
388         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
389 
390 }
391 
392 static sal_Bool parseDuration(const xmlChar* aString, sal_Bool& bNegative, sal_Int32& nYears, sal_Int32& nMonth, sal_Int32& nDays,
393                               sal_Int32& nHours, sal_Int32& nMinutes, sal_Int32& nSeconds)
394 {
395     sal_Bool bTime = sal_False; // in part after T
396     sal_Int32 nLength = strlen((char*)aString)+1;
397     char *pString = (char*)rtl_allocateMemory(nLength);
398     char *pString0 = pString;
399     strncpy(pString, (char*)aString, nLength);
400 
401     if (pString[0] == '-') {
402         bNegative = sal_True;
403         pString++;
404     }
405 
406     if (pString[0] != 'P')
407         return sal_False;
408     pString++;
409     char* pToken = pString;
410     while(pToken[0] != 0)
411     {
412         switch(pToken[0]) {
413         case 'Y':
414             pToken[0] = 0;
415             nYears = atoi(pString);
416             pString = ++pToken;
417             break;
418         case 'M':
419             pToken[0] = 0;
420             if (!bTime)
421                 nMonth = atoi(pString);
422             else
423                 nMinutes = atoi(pString);
424             pString = ++pToken;
425             break;
426         case 'D':
427             pToken[0] = 0;
428             nDays = atoi(pString);
429             pString = ++pToken;
430             break;
431         case 'H':
432             pToken[0] = 0;
433             nHours = atoi(pString);
434             pString = ++pToken;
435             break;
436         case 'S':
437             pToken[0] = 0;
438             nSeconds = atoi(pString);
439             pString = ++pToken;
440             break;
441         case 'T':
442             bTime = sal_True;
443             pString = ++pToken;
444             break;
445         default:
446             pToken++;
447         }
448     }
449     rtl_freeMemory(pString0);
450     return sal_True;
451 }
452 
453 void xforms_secondsFuction(xmlXPathParserContextPtr ctxt, int nargs)
454 {
455     // convert a xsd:duration to seconds
456     // (-)PnYnMnDTnHnMnS
457     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
458     xmlChar* pString = xmlXPathPopString(ctxt);
459     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
460 
461     sal_Bool bNegative = sal_False;
462     sal_Int32 nYears = 0;
463     sal_Int32 nMonths = 0;
464     sal_Int32 nDays = 0;
465     sal_Int32 nHours = 0;
466     sal_Int32 nMinutes = 0;
467     sal_Int32 nSeconds = 0;
468 
469     if (parseDuration(pString, bNegative, nYears, nMonths, nDays, nHours, nMinutes, nSeconds))
470     {
471         nSeconds += nMinutes*60;
472         nSeconds += nHours*60*60;
473         nSeconds += nDays*24*60*60;
474         // year and month are ignored according to spec
475         if (bNegative)
476             nSeconds = 0 - nSeconds;
477         xmlXPathReturnNumber(ctxt, nSeconds);
478     }
479     else
480         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
481 }
482 
483 void xforms_monthsFuction(xmlXPathParserContextPtr ctxt, int nargs)
484 {
485     // convert a xsd:duration to seconds
486     // (-)PnYnMnDTnHnMnS
487     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
488     xmlChar* pString = xmlXPathPopString(ctxt);
489     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
490 
491     sal_Bool bNegative = sal_False;
492     sal_Int32 nYears = 0;
493     sal_Int32 nMonths = 0;
494     sal_Int32 nDays = 0;
495     sal_Int32 nHours = 0;
496     sal_Int32 nMinutes = 0;
497     sal_Int32 nSeconds = 0;
498 
499     if (parseDuration(pString, bNegative, nYears, nMonths, nDays, nHours, nMinutes, nSeconds))
500     {
501         nMonths += nYears*12;
502         // Days, Houres, Minutes and seconds are ignored, see spec
503         if (bNegative)
504             nMonths = 0 - nMonths;
505         xmlXPathReturnNumber(ctxt, nMonths);
506     }
507     else
508         xmlXPathReturnNumber(ctxt, xmlXPathNAN);
509 
510 }
511 
512 // Node-set Functions
513 void xforms_instanceFuction(xmlXPathParserContextPtr ctxt, int nargs)
514 {
515     if (nargs != 1) XP_ERROR(XPATH_INVALID_ARITY);
516     xmlChar *pString = xmlXPathPopString(ctxt);
517     if (xmlXPathCheckError(ctxt)) XP_ERROR(XPATH_INVALID_TYPE);
518     ::rtl::OUString aString((char*)pString, strlen((char*)pString), RTL_TEXTENCODING_UTF8);
519 
520     Reference< XModel > aModel = ((CLibxml2XFormsExtension*)ctxt->context->funcLookupData)->getModel();
521     if (aModel.is())
522     {
523         Reference< XDocument > aInstance = aModel->getInstanceDocument(aString);
524         if (aInstance.is())
525         {
526             try {
527                 // xmlXPathObjectPtr xmlXPathNewNodeSet        (xmlNodePtr val);
528                 Reference< XUnoTunnel > aTunnel(aInstance, UNO_QUERY_THROW);
529                 xmlNodePtr pNode = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(Sequence< sal_Int8 >()) );
530                 xmlXPathObjectPtr pObject = xmlXPathNewNodeSet(pNode);
531                 xmlXPathReturnNodeSet(ctxt, pObject->nodesetval);
532             } catch (RuntimeException&)
533             {
534                 xmlXPathReturnEmptyNodeSet(ctxt);
535             }
536         }
537         else
538             xmlXPathReturnEmptyNodeSet(ctxt);
539     }
540     else
541         xmlXPathReturnEmptyNodeSet(ctxt);
542 
543 }
544 
545 // Node-set Functions, XForms 1.1
546 void xforms_currentFunction(xmlXPathParserContextPtr ctxt, int nargs)
547 {
548     if (nargs != 0) XP_ERROR(XPATH_INVALID_ARITY);
549 
550     Reference< XNode > aNode = ((CLibxml2XFormsExtension*)ctxt->context->funcLookupData)->getContextNode();
551 
552     if (aNode.is())
553     {
554         try {
555             Reference< XUnoTunnel > aTunnel(aNode, UNO_QUERY_THROW);
556             xmlNodePtr pNode = reinterpret_cast< xmlNodePtr >( aTunnel->getSomething(Sequence< sal_Int8 >()) );
557             xmlXPathObjectPtr pObject = xmlXPathNewNodeSet(pNode);
558             xmlXPathReturnNodeSet(ctxt, pObject->nodesetval);
559         }
560         catch (RuntimeException&)
561         {
562             xmlXPathReturnEmptyNodeSet(ctxt);
563         }
564     }
565     else
566         xmlXPathReturnEmptyNodeSet(ctxt);
567 }
568