Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include "XMLConverter.hxx"
31 : : #include <com/sun/star/util/DateTime.hpp>
32 : : #include <tools/datetime.hxx>
33 : : #include <sax/tools/converter.hxx>
34 : : #include <xmloff/xmltoken.hxx>
35 : : #include "rangelst.hxx"
36 : : #include "rangeutl.hxx"
37 : : #include "docuno.hxx"
38 : : #include "convuno.hxx"
39 : : #include "document.hxx"
40 : : #include "ftools.hxx"
41 : :
42 : : using ::rtl::OUString;
43 : : using ::rtl::OUStringBuffer;
44 : : using namespace ::com::sun::star;
45 : : using namespace xmloff::token;
46 : :
47 : :
48 : : //___________________________________________________________________
49 : :
50 : 627 : ScDocument* ScXMLConverter::GetScDocument( uno::Reference< frame::XModel > xModel )
51 : : {
52 [ + - ]: 627 : if (xModel.is())
53 : : {
54 [ + - ]: 627 : ScModelObj* pDocObj = ScModelObj::getImplementation( xModel );
55 [ + - ]: 627 : return pDocObj ? pDocObj->GetDocument() : NULL;
56 : : }
57 : 627 : return NULL;
58 : : }
59 : :
60 : :
61 : : //___________________________________________________________________
62 : 28 : sheet::GeneralFunction ScXMLConverter::GetFunctionFromString( const OUString& sFunction )
63 : : {
64 [ + + ]: 28 : if( IsXMLToken(sFunction, XML_SUM ) )
65 : 8 : return sheet::GeneralFunction_SUM;
66 [ + - ]: 20 : if( IsXMLToken(sFunction, XML_AUTO ) )
67 : 20 : return sheet::GeneralFunction_AUTO;
68 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_COUNT ) )
69 : 0 : return sheet::GeneralFunction_COUNT;
70 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_COUNTNUMS ) )
71 : 0 : return sheet::GeneralFunction_COUNTNUMS;
72 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_PRODUCT ) )
73 : 0 : return sheet::GeneralFunction_PRODUCT;
74 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_AVERAGE ) )
75 : 0 : return sheet::GeneralFunction_AVERAGE;
76 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_MAX ) )
77 : 0 : return sheet::GeneralFunction_MAX;
78 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_MIN ) )
79 : 0 : return sheet::GeneralFunction_MIN;
80 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_STDEV ) )
81 : 0 : return sheet::GeneralFunction_STDEV;
82 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_STDEVP ) )
83 : 0 : return sheet::GeneralFunction_STDEVP;
84 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_VAR ) )
85 : 0 : return sheet::GeneralFunction_VAR;
86 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_VARP ) )
87 : 0 : return sheet::GeneralFunction_VARP;
88 : 28 : return sheet::GeneralFunction_NONE;
89 : : }
90 : :
91 : 0 : ScSubTotalFunc ScXMLConverter::GetSubTotalFuncFromString( const OUString& sFunction )
92 : : {
93 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_SUM ) )
94 : 0 : return SUBTOTAL_FUNC_SUM;
95 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_COUNT ) )
96 : 0 : return SUBTOTAL_FUNC_CNT;
97 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_COUNTNUMS ) )
98 : 0 : return SUBTOTAL_FUNC_CNT2;
99 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_PRODUCT ) )
100 : 0 : return SUBTOTAL_FUNC_PROD;
101 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_AVERAGE ) )
102 : 0 : return SUBTOTAL_FUNC_AVE;
103 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_MAX ) )
104 : 0 : return SUBTOTAL_FUNC_MAX;
105 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_MIN ) )
106 : 0 : return SUBTOTAL_FUNC_MIN;
107 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_STDEV ) )
108 : 0 : return SUBTOTAL_FUNC_STD;
109 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_STDEVP ) )
110 : 0 : return SUBTOTAL_FUNC_STDP;
111 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_VAR ) )
112 : 0 : return SUBTOTAL_FUNC_VAR;
113 [ # # ]: 0 : if( IsXMLToken(sFunction, XML_VARP ) )
114 : 0 : return SUBTOTAL_FUNC_VARP;
115 : 0 : return SUBTOTAL_FUNC_NONE;
116 : : }
117 : :
118 : :
119 : : //___________________________________________________________________
120 : :
121 : 0 : void ScXMLConverter::GetStringFromFunction(
122 : : OUString& rString,
123 : : const sheet::GeneralFunction eFunction,
124 : : bool bAppendStr )
125 : : {
126 : 0 : OUString sFuncStr;
127 [ # # # # : 0 : switch( eFunction )
# # # # #
# # # #
# ]
128 : : {
129 [ # # ]: 0 : case sheet::GeneralFunction_AUTO: sFuncStr = GetXMLToken( XML_AUTO ); break;
130 [ # # ]: 0 : case sheet::GeneralFunction_AVERAGE: sFuncStr = GetXMLToken( XML_AVERAGE ); break;
131 [ # # ]: 0 : case sheet::GeneralFunction_COUNT: sFuncStr = GetXMLToken( XML_COUNT ); break;
132 [ # # ]: 0 : case sheet::GeneralFunction_COUNTNUMS: sFuncStr = GetXMLToken( XML_COUNTNUMS ); break;
133 [ # # ]: 0 : case sheet::GeneralFunction_MAX: sFuncStr = GetXMLToken( XML_MAX ); break;
134 [ # # ]: 0 : case sheet::GeneralFunction_MIN: sFuncStr = GetXMLToken( XML_MIN ); break;
135 [ # # ]: 0 : case sheet::GeneralFunction_NONE: sFuncStr = GetXMLToken( XML_NONE ); break;
136 [ # # ]: 0 : case sheet::GeneralFunction_PRODUCT: sFuncStr = GetXMLToken( XML_PRODUCT ); break;
137 [ # # ]: 0 : case sheet::GeneralFunction_STDEV: sFuncStr = GetXMLToken( XML_STDEV ); break;
138 [ # # ]: 0 : case sheet::GeneralFunction_STDEVP: sFuncStr = GetXMLToken( XML_STDEVP ); break;
139 [ # # ]: 0 : case sheet::GeneralFunction_SUM: sFuncStr = GetXMLToken( XML_SUM ); break;
140 [ # # ]: 0 : case sheet::GeneralFunction_VAR: sFuncStr = GetXMLToken( XML_VAR ); break;
141 [ # # ]: 0 : case sheet::GeneralFunction_VARP: sFuncStr = GetXMLToken( XML_VARP ); break;
142 : : default:
143 : : {
144 : : // added to avoid warnings
145 : : }
146 : : }
147 [ # # ]: 0 : ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
148 : 0 : }
149 : :
150 : 0 : void ScXMLConverter::GetStringFromFunction(
151 : : OUString& rString,
152 : : const ScSubTotalFunc eFunction,
153 : : bool bAppendStr )
154 : : {
155 : 0 : OUString sFuncStr;
156 [ # # # # : 0 : switch( eFunction )
# # # # #
# # # # ]
157 : : {
158 [ # # ]: 0 : case SUBTOTAL_FUNC_AVE: sFuncStr = GetXMLToken( XML_AVERAGE ); break;
159 [ # # ]: 0 : case SUBTOTAL_FUNC_CNT: sFuncStr = GetXMLToken( XML_COUNT ); break;
160 [ # # ]: 0 : case SUBTOTAL_FUNC_CNT2: sFuncStr = GetXMLToken( XML_COUNTNUMS ); break;
161 [ # # ]: 0 : case SUBTOTAL_FUNC_MAX: sFuncStr = GetXMLToken( XML_MAX ); break;
162 [ # # ]: 0 : case SUBTOTAL_FUNC_MIN: sFuncStr = GetXMLToken( XML_MIN ); break;
163 [ # # ]: 0 : case SUBTOTAL_FUNC_NONE: sFuncStr = GetXMLToken( XML_NONE ); break;
164 [ # # ]: 0 : case SUBTOTAL_FUNC_PROD: sFuncStr = GetXMLToken( XML_PRODUCT ); break;
165 [ # # ]: 0 : case SUBTOTAL_FUNC_STD: sFuncStr = GetXMLToken( XML_STDEV ); break;
166 [ # # ]: 0 : case SUBTOTAL_FUNC_STDP: sFuncStr = GetXMLToken( XML_STDEVP ); break;
167 [ # # ]: 0 : case SUBTOTAL_FUNC_SUM: sFuncStr = GetXMLToken( XML_SUM ); break;
168 [ # # ]: 0 : case SUBTOTAL_FUNC_VAR: sFuncStr = GetXMLToken( XML_VAR ); break;
169 [ # # ]: 0 : case SUBTOTAL_FUNC_VARP: sFuncStr = GetXMLToken( XML_VARP ); break;
170 : : }
171 [ # # ]: 0 : ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
172 : 0 : }
173 : :
174 : :
175 : : //___________________________________________________________________
176 : :
177 : 22 : sheet::DataPilotFieldOrientation ScXMLConverter::GetOrientationFromString(
178 : : const OUString& rString )
179 : : {
180 [ + + ]: 22 : if( IsXMLToken(rString, XML_COLUMN ) )
181 : 6 : return sheet::DataPilotFieldOrientation_COLUMN;
182 [ + + ]: 16 : if( IsXMLToken(rString, XML_ROW ) )
183 : 8 : return sheet::DataPilotFieldOrientation_ROW;
184 [ + + ]: 8 : if( IsXMLToken(rString, XML_PAGE ) )
185 : 2 : return sheet::DataPilotFieldOrientation_PAGE;
186 [ + - ]: 6 : if( IsXMLToken(rString, XML_DATA ) )
187 : 6 : return sheet::DataPilotFieldOrientation_DATA;
188 : 22 : return sheet::DataPilotFieldOrientation_HIDDEN;
189 : : }
190 : :
191 : :
192 : : //___________________________________________________________________
193 : :
194 : 0 : void ScXMLConverter::GetStringFromOrientation(
195 : : OUString& rString,
196 : : const sheet::DataPilotFieldOrientation eOrientation,
197 : : bool bAppendStr )
198 : : {
199 : 0 : OUString sOrientStr;
200 [ # # # # : 0 : switch( eOrientation )
# # ]
201 : : {
202 : : case sheet::DataPilotFieldOrientation_HIDDEN:
203 [ # # ]: 0 : sOrientStr = GetXMLToken( XML_HIDDEN );
204 : 0 : break;
205 : : case sheet::DataPilotFieldOrientation_COLUMN:
206 [ # # ]: 0 : sOrientStr = GetXMLToken( XML_COLUMN );
207 : 0 : break;
208 : : case sheet::DataPilotFieldOrientation_ROW:
209 [ # # ]: 0 : sOrientStr = GetXMLToken( XML_ROW );
210 : 0 : break;
211 : : case sheet::DataPilotFieldOrientation_PAGE:
212 [ # # ]: 0 : sOrientStr = GetXMLToken( XML_PAGE );
213 : 0 : break;
214 : : case sheet::DataPilotFieldOrientation_DATA:
215 [ # # ]: 0 : sOrientStr = GetXMLToken( XML_DATA );
216 : 0 : break;
217 : : default:
218 : : {
219 : : // added to avoid warnings
220 : : }
221 : : }
222 [ # # ]: 0 : ScRangeStringConverter::AssignString( rString, sOrientStr, bAppendStr );
223 : 0 : }
224 : :
225 : :
226 : : //___________________________________________________________________
227 : :
228 : 0 : ScDetectiveObjType ScXMLConverter::GetDetObjTypeFromString( const OUString& rString )
229 : : {
230 [ # # ]: 0 : if( IsXMLToken(rString, XML_FROM_SAME_TABLE ) )
231 : 0 : return SC_DETOBJ_ARROW;
232 [ # # ]: 0 : if( IsXMLToken(rString, XML_FROM_ANOTHER_TABLE ) )
233 : 0 : return SC_DETOBJ_FROMOTHERTAB;
234 [ # # ]: 0 : if( IsXMLToken(rString, XML_TO_ANOTHER_TABLE ) )
235 : 0 : return SC_DETOBJ_TOOTHERTAB;
236 : 0 : return SC_DETOBJ_NONE;
237 : : }
238 : :
239 : 0 : bool ScXMLConverter::GetDetOpTypeFromString( ScDetOpType& rDetOpType, const OUString& rString )
240 : : {
241 [ # # ]: 0 : if( IsXMLToken(rString, XML_TRACE_DEPENDENTS ) )
242 : 0 : rDetOpType = SCDETOP_ADDSUCC;
243 [ # # ]: 0 : else if( IsXMLToken(rString, XML_TRACE_PRECEDENTS ) )
244 : 0 : rDetOpType = SCDETOP_ADDPRED;
245 [ # # ]: 0 : else if( IsXMLToken(rString, XML_TRACE_ERRORS ) )
246 : 0 : rDetOpType = SCDETOP_ADDERROR;
247 [ # # ]: 0 : else if( IsXMLToken(rString, XML_REMOVE_DEPENDENTS ) )
248 : 0 : rDetOpType = SCDETOP_DELSUCC;
249 [ # # ]: 0 : else if( IsXMLToken(rString, XML_REMOVE_PRECEDENTS ) )
250 : 0 : rDetOpType = SCDETOP_DELPRED;
251 : : else
252 : 0 : return false;
253 : 0 : return true;
254 : : }
255 : :
256 : :
257 : : //___________________________________________________________________
258 : :
259 : 0 : void ScXMLConverter::GetStringFromDetObjType(
260 : : OUString& rString,
261 : : const ScDetectiveObjType eObjType,
262 : : bool bAppendStr )
263 : : {
264 : 0 : OUString sTypeStr;
265 [ # # # # ]: 0 : switch( eObjType )
266 : : {
267 : : case SC_DETOBJ_ARROW:
268 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_FROM_SAME_TABLE );
269 : 0 : break;
270 : : case SC_DETOBJ_FROMOTHERTAB:
271 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_FROM_ANOTHER_TABLE );
272 : 0 : break;
273 : : case SC_DETOBJ_TOOTHERTAB:
274 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_TO_ANOTHER_TABLE );
275 : 0 : break;
276 : : default:
277 : : {
278 : : // added to avoid warnings
279 : : }
280 : : }
281 [ # # ]: 0 : ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
282 : 0 : }
283 : :
284 : 0 : void ScXMLConverter::GetStringFromDetOpType(
285 : : OUString& rString,
286 : : const ScDetOpType eOpType,
287 : : bool bAppendStr )
288 : : {
289 : 0 : OUString sTypeStr;
290 [ # # # # : 0 : switch( eOpType )
# # ]
291 : : {
292 : : case SCDETOP_ADDSUCC:
293 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_TRACE_DEPENDENTS );
294 : 0 : break;
295 : : case SCDETOP_ADDPRED:
296 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_TRACE_PRECEDENTS );
297 : 0 : break;
298 : : case SCDETOP_ADDERROR:
299 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_TRACE_ERRORS );
300 : 0 : break;
301 : : case SCDETOP_DELSUCC:
302 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_REMOVE_DEPENDENTS );
303 : 0 : break;
304 : : case SCDETOP_DELPRED:
305 [ # # ]: 0 : sTypeStr = GetXMLToken( XML_REMOVE_PRECEDENTS );
306 : 0 : break;
307 : : }
308 [ # # ]: 0 : ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
309 : 0 : }
310 : :
311 : :
312 : : //___________________________________________________________________
313 : :
314 : 68 : void ScXMLConverter::ParseFormula(OUString& sFormula, const bool bIsFormula)
315 : : {
316 : 68 : OUStringBuffer sBuffer(sFormula.getLength());
317 : 68 : bool bInQuotationMarks(false);
318 : 68 : bool bInDoubleQuotationMarks(false);
319 : 68 : sal_Int16 nCountBraces(0);
320 : 68 : sal_Unicode chPrevious('=');
321 [ + + ]: 978 : for (sal_Int32 i = 0; i < sFormula.getLength(); ++i)
322 : : {
323 [ - + ][ # # ]: 910 : if (sFormula[i] == '\'' && !bInDoubleQuotationMarks &&
[ # # ][ - + ]
324 : : chPrevious != '\\')
325 : 0 : bInQuotationMarks = !bInQuotationMarks;
326 [ - + ][ # # ]: 910 : else if (sFormula[i] == '"' && !bInQuotationMarks)
[ - + ]
327 : 0 : bInDoubleQuotationMarks = !bInDoubleQuotationMarks;
328 [ + - ][ - + ]: 910 : if (bInQuotationMarks || bInDoubleQuotationMarks)
329 [ # # ]: 0 : sBuffer.append(sFormula[i]);
330 [ - + ]: 910 : else if (sFormula[i] == '[')
331 : 0 : ++nCountBraces;
332 [ - + ]: 910 : else if (sFormula[i] == ']')
333 : 0 : nCountBraces--;
334 [ + + ][ + - ]: 981 : else if ((sFormula[i] != '.') ||
[ + - ][ + - ]
[ + + ]
335 : : ((nCountBraces == 0) && bIsFormula) ||
336 [ + + ][ + - ]: 71 : !((chPrevious == '[') || (chPrevious == ':') || (chPrevious == ' ') || (chPrevious == '=')))
[ + - ]
337 [ + - ]: 907 : sBuffer.append(sFormula[i]);
338 : 910 : chPrevious = sFormula[i];
339 : : }
340 : :
341 : : OSL_ENSURE(nCountBraces == 0, "there are some braces still open");
342 [ + - ]: 68 : sFormula = sBuffer.makeStringAndClear();
343 : 68 : }
344 : :
345 : :
346 : : //_____________________________________________________________________
347 : :
348 : 0 : void ScXMLConverter::ConvertDateTimeToString(const DateTime& aDateTime, rtl::OUStringBuffer& sDate)
349 : : {
350 : 0 : util::DateTime aAPIDateTime;
351 : 0 : ConvertCoreToAPIDateTime(aDateTime, aAPIDateTime);
352 [ # # ]: 0 : ::sax::Converter::convertDateTime(sDate, aAPIDateTime);
353 : 0 : }
354 : :
355 : 0 : void ScXMLConverter::ConvertCoreToAPIDateTime(const DateTime& aDateTime, util::DateTime& rDateTime)
356 : : {
357 : 0 : rDateTime.Year = aDateTime.GetYear();
358 : 0 : rDateTime.Month = aDateTime.GetMonth();
359 : 0 : rDateTime.Day = aDateTime.GetDay();
360 : 0 : rDateTime.Hours = aDateTime.GetHour();
361 : 0 : rDateTime.Minutes = aDateTime.GetMin();
362 : 0 : rDateTime.Seconds = aDateTime.GetSec();
363 : 0 : rDateTime.HundredthSeconds = aDateTime.Get100Sec();
364 : 0 : }
365 : :
366 : 0 : void ScXMLConverter::ConvertAPIToCoreDateTime(const util::DateTime& aDateTime, DateTime& rDateTime)
367 : : {
368 : 0 : Date aDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
369 [ # # ]: 0 : Time aTime(aDateTime.Hours, aDateTime.Minutes, aDateTime.Seconds, aDateTime.HundredthSeconds);
370 [ # # ]: 0 : DateTime aTempDateTime (aDate, aTime);
371 [ # # ]: 0 : rDateTime = aTempDateTime;
372 : 0 : }
373 : :
374 : : // ============================================================================
375 : :
376 : : namespace {
377 : :
378 : : /** Enumerates different types of condition tokens. */
379 : : enum ScXMLConditionTokenType
380 : : {
381 : : XML_COND_TYPE_KEYWORD, /// Simple keyword without parentheses, e.g. 'and'.
382 : : XML_COND_TYPE_COMPARISON, /// Comparison rule, e.g. 'cell-content()<=2'.
383 : : XML_COND_TYPE_FUNCTION0, /// Function without parameters, e.g. 'cell-content-is-whole-number()'.
384 : : XML_COND_TYPE_FUNCTION1, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'.
385 : : XML_COND_TYPE_FUNCTION2 /// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'.
386 : : };
387 : :
388 : : struct ScXMLConditionInfo
389 : : {
390 : : ScXMLConditionToken meToken;
391 : : ScXMLConditionTokenType meType;
392 : : sheet::ValidationType meValidation;
393 : : sheet::ConditionOperator meOperator;
394 : : const sal_Char* mpcIdentifier;
395 : : sal_Int32 mnIdentLength;
396 : : };
397 : :
398 : : static const ScXMLConditionInfo spConditionInfos[] =
399 : : {
400 : : { XML_COND_AND, XML_COND_TYPE_KEYWORD, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "and" ) },
401 : : { XML_COND_CELLCONTENT, XML_COND_TYPE_COMPARISON, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) },
402 : : { XML_COND_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) },
403 : : { XML_COND_ISNOTBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_NOT_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) },
404 : : { XML_COND_ISWHOLENUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_WHOLE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) },
405 : : { XML_COND_ISDECIMALNUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DECIMAL, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) },
406 : : { XML_COND_ISDATE, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DATE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) },
407 : : { XML_COND_ISTIME, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_TIME, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) },
408 : : { XML_COND_ISINLIST, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_LIST, sheet::ConditionOperator_EQUAL, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) },
409 : : { XML_COND_TEXTLENGTH, XML_COND_TYPE_COMPARISON, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) },
410 : : { XML_COND_TEXTLENGTH_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) },
411 : : { XML_COND_TEXTLENGTH_ISNOTBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_NOT_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-not-between" ) },
412 : : { XML_COND_ISTRUEFORMULA, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_CUSTOM, sheet::ConditionOperator_FORMULA, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) }
413 : : };
414 : :
415 : 99 : void lclSkipWhitespace( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
416 : : {
417 [ + - ][ + + ]: 111 : while( (rpcString < pcEnd) && (*rpcString <= ' ') ) ++rpcString;
[ + + ]
418 : 99 : }
419 : :
420 : 51 : const ScXMLConditionInfo* lclGetConditionInfo( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
421 : : {
422 : 51 : lclSkipWhitespace( rpcString, pcEnd );
423 : : /* Search the end of an identifier name; assuming that valid identifiers
424 : : consist of [a-z-] only. */
425 : 51 : const sal_Unicode* pcIdStart = rpcString;
426 [ + - ][ + + ]: 885 : while( (rpcString < pcEnd) && (((*rpcString >= 'a') && (*rpcString <= 'z')) || (*rpcString == '-')) ) ++rpcString;
[ - + ][ + + ]
[ + + ]
427 : 51 : sal_Int32 nLength = static_cast< sal_Int32 >( rpcString - pcIdStart );
428 : :
429 : : // search the table for an entry
430 [ + - ]: 51 : if( nLength > 0 )
431 [ + - ]: 201 : for( const ScXMLConditionInfo* pInfo = spConditionInfos; pInfo < STATIC_TABLE_END( spConditionInfos ); ++pInfo )
432 [ + + ][ + - ]: 201 : if( (nLength == pInfo->mnIdentLength) && (::rtl_ustr_ascii_shortenedCompare_WithLength( pcIdStart, nLength, pInfo->mpcIdentifier, nLength ) == 0) )
[ + + ]
433 : 51 : return pInfo;
434 : :
435 : 51 : return 0;
436 : : }
437 : :
438 : 21 : sheet::ConditionOperator lclGetConditionOperator( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
439 : : {
440 : : // check for double-char operators
441 [ + - ][ + + ]: 21 : if( (rpcString + 1 < pcEnd) && (rpcString[ 1 ] == '=') )
442 : : {
443 : 6 : sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
444 [ - - + - ]: 6 : switch( *rpcString )
445 : : {
446 : 0 : case '!': eOperator = sheet::ConditionOperator_NOT_EQUAL; break;
447 : 0 : case '<': eOperator = sheet::ConditionOperator_LESS_EQUAL; break;
448 : 6 : case '>': eOperator = sheet::ConditionOperator_GREATER_EQUAL; break;
449 : : }
450 [ + - ]: 6 : if( eOperator != sheet::ConditionOperator_NONE )
451 : : {
452 : 6 : rpcString += 2;
453 : 6 : return eOperator;
454 : : }
455 : : }
456 : :
457 : : // check for single-char operators
458 [ + - ]: 15 : if( rpcString < pcEnd )
459 : : {
460 : 15 : sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
461 [ + + + - ]: 15 : switch( *rpcString )
462 : : {
463 : 6 : case '=': eOperator = sheet::ConditionOperator_EQUAL; break;
464 : 3 : case '<': eOperator = sheet::ConditionOperator_LESS; break;
465 : 6 : case '>': eOperator = sheet::ConditionOperator_GREATER; break;
466 : : }
467 [ + - ]: 15 : if( eOperator != sheet::ConditionOperator_NONE )
468 : : {
469 : 15 : ++rpcString;
470 : 15 : return eOperator;
471 : : }
472 : : }
473 : :
474 : 21 : return sheet::ConditionOperator_NONE;
475 : : }
476 : :
477 : : /** Skips a literal string in a formula expression.
478 : :
479 : : @param rpcString
480 : : (in-out) On call, must point to the first character of the string
481 : : following the leading string delimiter character. On return, points to
482 : : the trailing string delimiter character if existing, otherwise to
483 : : pcEnd.
484 : :
485 : : @param pcEnd
486 : : The end of the string to parse.
487 : :
488 : : @param cQuoteChar
489 : : The string delimiter character enclosing the string.
490 : : */
491 : 0 : void lclSkipExpressionString( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cQuoteChar )
492 : : {
493 [ # # ]: 0 : if( rpcString < pcEnd )
494 : : {
495 : 0 : sal_Int32 nLength = static_cast< sal_Int32 >( pcEnd - rpcString );
496 : 0 : sal_Int32 nNextQuote = ::rtl_ustr_indexOfChar_WithLength( rpcString, nLength, cQuoteChar );
497 [ # # ]: 0 : if( nNextQuote >= 0 )
498 : 0 : rpcString += nNextQuote;
499 : : else
500 : 0 : rpcString = pcEnd;
501 : : }
502 : 0 : }
503 : :
504 : : /** Skips a formula expression. Processes embedded parentheses, braces, and
505 : : literal strings.
506 : :
507 : : @param rpcString
508 : : (in-out) On call, must point to the first character of the expression.
509 : : On return, points to the passed end character if existing, otherwise to
510 : : pcEnd.
511 : :
512 : : @param pcEnd
513 : : The end of the string to parse.
514 : :
515 : : @param cEndChar
516 : : The termination character following the expression.
517 : : */
518 : 36 : void lclSkipExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
519 : : {
520 [ + - ]: 147 : while( rpcString < pcEnd )
521 : : {
522 [ + + ]: 147 : if( *rpcString == cEndChar )
523 : 36 : return;
524 [ + - - - : 111 : switch( *rpcString )
+ ]
525 : : {
526 : 6 : case '(': lclSkipExpression( ++rpcString, pcEnd, ')' ); break;
527 : 0 : case '{': lclSkipExpression( ++rpcString, pcEnd, '}' ); break;
528 : 0 : case '"': lclSkipExpressionString( ++rpcString, pcEnd, '"' ); break;
529 : 0 : case '\'': lclSkipExpressionString( ++rpcString, pcEnd, '\'' ); break;
530 : : }
531 [ + - ]: 111 : if( rpcString < pcEnd ) ++rpcString;
532 : : }
533 : : }
534 : :
535 : : /** Extracts a formula expression. Processes embedded parentheses, braces, and
536 : : literal strings.
537 : :
538 : : @param rpcString
539 : : (in-out) On call, must point to the first character of the expression.
540 : : On return, points *behind* the passed end character if existing,
541 : : otherwise to pcEnd.
542 : :
543 : : @param pcEnd
544 : : The end of the string to parse.
545 : :
546 : : @param cEndChar
547 : : The termination character following the expression.
548 : : */
549 : : /** Tries to skip an empty pair of parentheses (which may contain whitespace
550 : : characters).
551 : :
552 : : @return
553 : : True on success, rpcString points behind the closing parentheses then.
554 : : */
555 : 27 : bool lclSkipEmptyParentheses( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
556 : : {
557 [ + - ][ + - ]: 27 : if( (rpcString < pcEnd) && (*rpcString == '(') )
558 : : {
559 : 27 : lclSkipWhitespace( ++rpcString, pcEnd );
560 [ + - ][ + - ]: 27 : if( (rpcString < pcEnd) && (*rpcString == ')') )
561 : : {
562 : 27 : ++rpcString;
563 : 27 : return true;
564 : : }
565 : : }
566 : 27 : return false;
567 : : }
568 : :
569 : : } // namespace
570 : :
571 : : // ----------------------------------------------------------------------------
572 : :
573 : 51 : void ScXMLConditionHelper::parseCondition(
574 : : ScXMLConditionParseResult& rParseResult, const OUString& rAttribute, sal_Int32 nStartIndex )
575 : : {
576 : 51 : rParseResult.meToken = XML_COND_INVALID;
577 [ + - ][ - + ]: 102 : if( (nStartIndex < 0) || (nStartIndex >= rAttribute.getLength()) ) return;
[ + - ]
578 : :
579 : : // try to find an identifier
580 : 51 : const sal_Unicode* pcBegin = rAttribute.getStr();
581 : 51 : const sal_Unicode* pcString = pcBegin + nStartIndex;
582 : 51 : const sal_Unicode* pcEnd = pcBegin + rAttribute.getLength();
583 [ + - ][ + - ]: 51 : if( const ScXMLConditionInfo* pCondInfo = lclGetConditionInfo( pcString, pcEnd ) )
584 : : {
585 : : // insert default values into parse result (may be changed below)
586 : 51 : rParseResult.meValidation = pCondInfo->meValidation;
587 : 51 : rParseResult.meOperator = pCondInfo->meOperator;
588 : : // continue parsing dependent on token type
589 [ + + + + : 51 : switch( pCondInfo->meType )
+ - ]
590 : : {
591 : : case XML_COND_TYPE_KEYWORD:
592 : : // nothing specific has to follow, success
593 : 6 : rParseResult.meToken = pCondInfo->meToken;
594 : 6 : break;
595 : :
596 : : case XML_COND_TYPE_COMPARISON:
597 : : // format is <condition>()<operator><expression>
598 [ + - ]: 21 : if( lclSkipEmptyParentheses( pcString, pcEnd ) )
599 : : {
600 : 21 : rParseResult.meOperator = lclGetConditionOperator( pcString, pcEnd );
601 [ + - ]: 21 : if( rParseResult.meOperator != sheet::ConditionOperator_NONE )
602 : : {
603 : 21 : lclSkipWhitespace( pcString, pcEnd );
604 [ + - ]: 21 : if( pcString < pcEnd )
605 : : {
606 : 21 : rParseResult.meToken = pCondInfo->meToken;
607 : : // comparison must be at end of attribute, remaining text is the formula
608 : 21 : rParseResult.maOperand1 = OUString( pcString, static_cast< sal_Int32 >( pcEnd - pcString ) );
609 : : }
610 : : }
611 : : }
612 : 21 : break;
613 : :
614 : : case XML_COND_TYPE_FUNCTION0:
615 : : // format is <condition>()
616 [ + - ]: 6 : if( lclSkipEmptyParentheses( pcString, pcEnd ) )
617 : 6 : rParseResult.meToken = pCondInfo->meToken;
618 : 6 : break;
619 : :
620 : : case XML_COND_TYPE_FUNCTION1:
621 : : // format is <condition>(<expression>)
622 [ + - ][ + - ]: 6 : if( (pcString < pcEnd) && (*pcString == '(') )
623 : : {
624 [ + - ]: 6 : rParseResult.maOperand1 = getExpression( ++pcString, pcEnd, ')' );
625 [ + - ]: 6 : if( !rParseResult.maOperand1.isEmpty() )
626 : 6 : rParseResult.meToken = pCondInfo->meToken;
627 : : }
628 : 6 : break;
629 : :
630 : : case XML_COND_TYPE_FUNCTION2:
631 : : // format is <condition>(<expression1>,<expression2>)
632 [ + - ][ + - ]: 12 : if( (pcString < pcEnd) && (*pcString == '(') )
633 : : {
634 [ + - ]: 12 : rParseResult.maOperand1 = getExpression( ++pcString, pcEnd, ',' );
635 [ + - ]: 12 : if( !rParseResult.maOperand1.isEmpty() )
636 : : {
637 [ + - ]: 12 : rParseResult.maOperand2 = getExpression( pcString, pcEnd, ')' );
638 [ + - ]: 12 : if( !rParseResult.maOperand2.isEmpty() )
639 : 12 : rParseResult.meToken = pCondInfo->meToken;
640 : : }
641 : : }
642 : 12 : break;
643 : : }
644 : 51 : rParseResult.mnEndIndex = static_cast< sal_Int32 >( pcString - pcBegin );
645 : : }
646 : : }
647 : :
648 : 30 : OUString ScXMLConditionHelper::getExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
649 : : {
650 : 30 : OUString aExp;
651 : 30 : const sal_Unicode* pcExpStart = rpcString;
652 [ + - ]: 30 : lclSkipExpression( rpcString, pcEnd, cEndChar );
653 [ + - ]: 30 : if( rpcString < pcEnd )
654 : : {
655 : 30 : aExp = OUString( pcExpStart, static_cast< sal_Int32 >( rpcString - pcExpStart ) ).trim();
656 : 30 : ++rpcString;
657 : : }
658 : 30 : return aExp;
659 : : }
660 : :
661 : : // ============================================================================
662 : :
663 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|