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