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