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