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