fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / xml / XMLConverter.cxx
bloba3a9986a0563d5fa89e214da7f2b95cd79278734
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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"
32 using namespace ::com::sun::star;
33 using namespace xmloff::token;
35 ScDocument* ScXMLConverter::GetScDocument( uno::Reference< frame::XModel > xModel )
37 if (xModel.is())
39 ScModelObj* pDocObj = ScModelObj::getImplementation( xModel );
40 return pDocObj ? pDocObj->GetDocument() : NULL;
42 return NULL;
45 sheet::GeneralFunction ScXMLConverter::GetFunctionFromString( const OUString& sFunction )
47 if( IsXMLToken(sFunction, XML_SUM ) )
48 return sheet::GeneralFunction_SUM;
49 if( IsXMLToken(sFunction, XML_AUTO ) )
50 return sheet::GeneralFunction_AUTO;
51 if( IsXMLToken(sFunction, XML_COUNT ) )
52 return sheet::GeneralFunction_COUNT;
53 if( IsXMLToken(sFunction, XML_COUNTNUMS ) )
54 return sheet::GeneralFunction_COUNTNUMS;
55 if( IsXMLToken(sFunction, XML_PRODUCT ) )
56 return sheet::GeneralFunction_PRODUCT;
57 if( IsXMLToken(sFunction, XML_AVERAGE ) )
58 return sheet::GeneralFunction_AVERAGE;
59 if( IsXMLToken(sFunction, XML_MAX ) )
60 return sheet::GeneralFunction_MAX;
61 if( IsXMLToken(sFunction, XML_MIN ) )
62 return sheet::GeneralFunction_MIN;
63 if( IsXMLToken(sFunction, XML_STDEV ) )
64 return sheet::GeneralFunction_STDEV;
65 if( IsXMLToken(sFunction, XML_STDEVP ) )
66 return sheet::GeneralFunction_STDEVP;
67 if( IsXMLToken(sFunction, XML_VAR ) )
68 return sheet::GeneralFunction_VAR;
69 if( IsXMLToken(sFunction, XML_VARP ) )
70 return sheet::GeneralFunction_VARP;
71 return sheet::GeneralFunction_NONE;
74 ScSubTotalFunc ScXMLConverter::GetSubTotalFuncFromString( const OUString& sFunction )
76 if( IsXMLToken(sFunction, XML_SUM ) )
77 return SUBTOTAL_FUNC_SUM;
78 if( IsXMLToken(sFunction, XML_COUNT ) )
79 return SUBTOTAL_FUNC_CNT;
80 if( IsXMLToken(sFunction, XML_COUNTNUMS ) )
81 return SUBTOTAL_FUNC_CNT2;
82 if( IsXMLToken(sFunction, XML_PRODUCT ) )
83 return SUBTOTAL_FUNC_PROD;
84 if( IsXMLToken(sFunction, XML_AVERAGE ) )
85 return SUBTOTAL_FUNC_AVE;
86 if( IsXMLToken(sFunction, XML_MAX ) )
87 return SUBTOTAL_FUNC_MAX;
88 if( IsXMLToken(sFunction, XML_MIN ) )
89 return SUBTOTAL_FUNC_MIN;
90 if( IsXMLToken(sFunction, XML_STDEV ) )
91 return SUBTOTAL_FUNC_STD;
92 if( IsXMLToken(sFunction, XML_STDEVP ) )
93 return SUBTOTAL_FUNC_STDP;
94 if( IsXMLToken(sFunction, XML_VAR ) )
95 return SUBTOTAL_FUNC_VAR;
96 if( IsXMLToken(sFunction, XML_VARP ) )
97 return SUBTOTAL_FUNC_VARP;
98 return SUBTOTAL_FUNC_NONE;
101 void ScXMLConverter::GetStringFromFunction(
102 OUString& rString,
103 const sheet::GeneralFunction eFunction,
104 bool bAppendStr )
106 OUString sFuncStr;
107 switch( eFunction )
109 case sheet::GeneralFunction_AUTO: sFuncStr = GetXMLToken( XML_AUTO ); break;
110 case sheet::GeneralFunction_AVERAGE: sFuncStr = GetXMLToken( XML_AVERAGE ); break;
111 case sheet::GeneralFunction_COUNT: sFuncStr = GetXMLToken( XML_COUNT ); break;
112 case sheet::GeneralFunction_COUNTNUMS: sFuncStr = GetXMLToken( XML_COUNTNUMS ); break;
113 case sheet::GeneralFunction_MAX: sFuncStr = GetXMLToken( XML_MAX ); break;
114 case sheet::GeneralFunction_MIN: sFuncStr = GetXMLToken( XML_MIN ); break;
115 case sheet::GeneralFunction_NONE: sFuncStr = GetXMLToken( XML_NONE ); break;
116 case sheet::GeneralFunction_PRODUCT: sFuncStr = GetXMLToken( XML_PRODUCT ); break;
117 case sheet::GeneralFunction_STDEV: sFuncStr = GetXMLToken( XML_STDEV ); break;
118 case sheet::GeneralFunction_STDEVP: sFuncStr = GetXMLToken( XML_STDEVP ); break;
119 case sheet::GeneralFunction_SUM: sFuncStr = GetXMLToken( XML_SUM ); break;
120 case sheet::GeneralFunction_VAR: sFuncStr = GetXMLToken( XML_VAR ); break;
121 case sheet::GeneralFunction_VARP: sFuncStr = GetXMLToken( XML_VARP ); break;
122 default:
124 // added to avoid warnings
127 ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
130 void ScXMLConverter::GetStringFromFunction(
131 OUString& rString,
132 const ScSubTotalFunc eFunction,
133 bool bAppendStr )
135 OUString sFuncStr;
136 switch( eFunction )
138 case SUBTOTAL_FUNC_AVE: sFuncStr = GetXMLToken( XML_AVERAGE ); break;
139 case SUBTOTAL_FUNC_CNT: sFuncStr = GetXMLToken( XML_COUNT ); break;
140 case SUBTOTAL_FUNC_CNT2: sFuncStr = GetXMLToken( XML_COUNTNUMS ); break;
141 case SUBTOTAL_FUNC_MAX: sFuncStr = GetXMLToken( XML_MAX ); break;
142 case SUBTOTAL_FUNC_MIN: sFuncStr = GetXMLToken( XML_MIN ); break;
143 case SUBTOTAL_FUNC_NONE: sFuncStr = GetXMLToken( XML_NONE ); break;
144 case SUBTOTAL_FUNC_PROD: sFuncStr = GetXMLToken( XML_PRODUCT ); break;
145 case SUBTOTAL_FUNC_STD: sFuncStr = GetXMLToken( XML_STDEV ); break;
146 case SUBTOTAL_FUNC_STDP: sFuncStr = GetXMLToken( XML_STDEVP ); break;
147 case SUBTOTAL_FUNC_SUM: sFuncStr = GetXMLToken( XML_SUM ); break;
148 case SUBTOTAL_FUNC_SELECTION_COUNT: break;
149 // it is not needed as it is only a UI value and not document content
151 case SUBTOTAL_FUNC_VAR: sFuncStr = GetXMLToken( XML_VAR ); break;
152 case SUBTOTAL_FUNC_VARP: sFuncStr = GetXMLToken( XML_VARP ); break;
154 ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
157 sheet::DataPilotFieldOrientation ScXMLConverter::GetOrientationFromString(
158 const OUString& rString )
160 if( IsXMLToken(rString, XML_COLUMN ) )
161 return sheet::DataPilotFieldOrientation_COLUMN;
162 if( IsXMLToken(rString, XML_ROW ) )
163 return sheet::DataPilotFieldOrientation_ROW;
164 if( IsXMLToken(rString, XML_PAGE ) )
165 return sheet::DataPilotFieldOrientation_PAGE;
166 if( IsXMLToken(rString, XML_DATA ) )
167 return sheet::DataPilotFieldOrientation_DATA;
168 return sheet::DataPilotFieldOrientation_HIDDEN;
171 void ScXMLConverter::GetStringFromOrientation(
172 OUString& rString,
173 const sheet::DataPilotFieldOrientation eOrientation,
174 bool bAppendStr )
176 OUString sOrientStr;
177 switch( eOrientation )
179 case sheet::DataPilotFieldOrientation_HIDDEN:
180 sOrientStr = GetXMLToken( XML_HIDDEN );
181 break;
182 case sheet::DataPilotFieldOrientation_COLUMN:
183 sOrientStr = GetXMLToken( XML_COLUMN );
184 break;
185 case sheet::DataPilotFieldOrientation_ROW:
186 sOrientStr = GetXMLToken( XML_ROW );
187 break;
188 case sheet::DataPilotFieldOrientation_PAGE:
189 sOrientStr = GetXMLToken( XML_PAGE );
190 break;
191 case sheet::DataPilotFieldOrientation_DATA:
192 sOrientStr = GetXMLToken( XML_DATA );
193 break;
194 default:
196 // added to avoid warnings
199 ScRangeStringConverter::AssignString( rString, sOrientStr, bAppendStr );
202 ScDetectiveObjType ScXMLConverter::GetDetObjTypeFromString( const OUString& rString )
204 if( IsXMLToken(rString, XML_FROM_SAME_TABLE ) )
205 return SC_DETOBJ_ARROW;
206 if( IsXMLToken(rString, XML_FROM_ANOTHER_TABLE ) )
207 return SC_DETOBJ_FROMOTHERTAB;
208 if( IsXMLToken(rString, XML_TO_ANOTHER_TABLE ) )
209 return SC_DETOBJ_TOOTHERTAB;
210 return SC_DETOBJ_NONE;
213 bool ScXMLConverter::GetDetOpTypeFromString( ScDetOpType& rDetOpType, const OUString& rString )
215 if( IsXMLToken(rString, XML_TRACE_DEPENDENTS ) )
216 rDetOpType = SCDETOP_ADDSUCC;
217 else if( IsXMLToken(rString, XML_TRACE_PRECEDENTS ) )
218 rDetOpType = SCDETOP_ADDPRED;
219 else if( IsXMLToken(rString, XML_TRACE_ERRORS ) )
220 rDetOpType = SCDETOP_ADDERROR;
221 else if( IsXMLToken(rString, XML_REMOVE_DEPENDENTS ) )
222 rDetOpType = SCDETOP_DELSUCC;
223 else if( IsXMLToken(rString, XML_REMOVE_PRECEDENTS ) )
224 rDetOpType = SCDETOP_DELPRED;
225 else
226 return false;
227 return true;
230 void ScXMLConverter::GetStringFromDetObjType(
231 OUString& rString,
232 const ScDetectiveObjType eObjType,
233 bool bAppendStr )
235 OUString sTypeStr;
236 switch( eObjType )
238 case SC_DETOBJ_ARROW:
239 sTypeStr = GetXMLToken( XML_FROM_SAME_TABLE );
240 break;
241 case SC_DETOBJ_FROMOTHERTAB:
242 sTypeStr = GetXMLToken( XML_FROM_ANOTHER_TABLE );
243 break;
244 case SC_DETOBJ_TOOTHERTAB:
245 sTypeStr = GetXMLToken( XML_TO_ANOTHER_TABLE );
246 break;
247 default:
249 // added to avoid warnings
252 ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
255 void ScXMLConverter::GetStringFromDetOpType(
256 OUString& rString,
257 const ScDetOpType eOpType,
258 bool bAppendStr )
260 OUString sTypeStr;
261 switch( eOpType )
263 case SCDETOP_ADDSUCC:
264 sTypeStr = GetXMLToken( XML_TRACE_DEPENDENTS );
265 break;
266 case SCDETOP_ADDPRED:
267 sTypeStr = GetXMLToken( XML_TRACE_PRECEDENTS );
268 break;
269 case SCDETOP_ADDERROR:
270 sTypeStr = GetXMLToken( XML_TRACE_ERRORS );
271 break;
272 case SCDETOP_DELSUCC:
273 sTypeStr = GetXMLToken( XML_REMOVE_DEPENDENTS );
274 break;
275 case SCDETOP_DELPRED:
276 sTypeStr = GetXMLToken( XML_REMOVE_PRECEDENTS );
277 break;
279 ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
282 void ScXMLConverter::ParseFormula(OUString& sFormula, const bool bIsFormula)
284 OUStringBuffer sBuffer(sFormula.getLength());
285 bool bInQuotationMarks(false);
286 bool bInDoubleQuotationMarks(false);
287 sal_Int16 nCountBraces(0);
288 sal_Unicode chPrevious('=');
289 for (sal_Int32 i = 0; i < sFormula.getLength(); ++i)
291 if (sFormula[i] == '\'' && !bInDoubleQuotationMarks &&
292 chPrevious != '\\')
293 bInQuotationMarks = !bInQuotationMarks;
294 else if (sFormula[i] == '"' && !bInQuotationMarks)
295 bInDoubleQuotationMarks = !bInDoubleQuotationMarks;
296 if (bInQuotationMarks || bInDoubleQuotationMarks)
297 sBuffer.append(sFormula[i]);
298 else if (sFormula[i] == '[')
299 ++nCountBraces;
300 else if (sFormula[i] == ']')
301 nCountBraces--;
302 else if ((sFormula[i] != '.') ||
303 ((nCountBraces == 0) && bIsFormula) ||
304 !((chPrevious == '[') || (chPrevious == ':') || (chPrevious == ' ') || (chPrevious == '=')))
305 sBuffer.append(sFormula[i]);
306 chPrevious = sFormula[i];
309 OSL_ENSURE(nCountBraces == 0, "there are some braces still open");
310 sFormula = sBuffer.makeStringAndClear();
313 void ScXMLConverter::ConvertDateTimeToString(const DateTime& aDateTime, OUStringBuffer& sDate)
315 css::util::DateTime aAPIDateTime = aDateTime.GetUNODateTime();
316 ::sax::Converter::convertDateTime(sDate, aAPIDateTime, 0);
319 namespace {
321 /** Enumerates different types of condition tokens. */
322 enum ScXMLConditionTokenType
324 XML_COND_TYPE_KEYWORD, /// Simple keyword without parentheses, e.g. 'and'.
325 XML_COND_TYPE_COMPARISON, /// Comparison rule, e.g. 'cell-content()<=2'.
326 XML_COND_TYPE_FUNCTION0, /// Function without parameters, e.g. 'cell-content-is-whole-number()'.
327 XML_COND_TYPE_FUNCTION1, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'.
328 XML_COND_TYPE_FUNCTION2 /// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'.
331 struct ScXMLConditionInfo
333 ScXMLConditionToken meToken;
334 ScXMLConditionTokenType meType;
335 sheet::ValidationType meValidation;
336 sheet::ConditionOperator meOperator;
337 const sal_Char* mpcIdentifier;
338 sal_Int32 mnIdentLength;
341 static const ScXMLConditionInfo spConditionInfos[] =
343 { XML_COND_AND, XML_COND_TYPE_KEYWORD, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "and" ) },
344 { XML_COND_CELLCONTENT, XML_COND_TYPE_COMPARISON, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) },
345 { XML_COND_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) },
346 { XML_COND_ISNOTBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_NOT_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) },
347 { XML_COND_ISWHOLENUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_WHOLE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) },
348 { XML_COND_ISDECIMALNUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DECIMAL, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) },
349 { XML_COND_ISDATE, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DATE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) },
350 { XML_COND_ISTIME, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_TIME, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) },
351 { XML_COND_ISINLIST, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_LIST, sheet::ConditionOperator_EQUAL, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) },
352 { XML_COND_TEXTLENGTH, XML_COND_TYPE_COMPARISON, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) },
353 { XML_COND_TEXTLENGTH_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) },
354 { 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" ) },
355 { XML_COND_ISTRUEFORMULA, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_CUSTOM, sheet::ConditionOperator_FORMULA, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) }
358 void lclSkipWhitespace( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
360 while( (rpcString < pcEnd) && (*rpcString <= ' ') ) ++rpcString;
363 const ScXMLConditionInfo* lclGetConditionInfo( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
365 lclSkipWhitespace( rpcString, pcEnd );
366 /* Search the end of an identifier name; assuming that valid identifiers
367 consist of [a-z-] only. */
368 const sal_Unicode* pcIdStart = rpcString;
369 while( (rpcString < pcEnd) && (((*rpcString >= 'a') && (*rpcString <= 'z')) || (*rpcString == '-')) ) ++rpcString;
370 sal_Int32 nLength = static_cast< sal_Int32 >( rpcString - pcIdStart );
372 // search the table for an entry
373 if( nLength > 0 )
374 for( const ScXMLConditionInfo* pInfo = spConditionInfos; pInfo < STATIC_ARRAY_END( spConditionInfos ); ++pInfo )
375 if( (nLength == pInfo->mnIdentLength) && (::rtl_ustr_ascii_shortenedCompare_WithLength( pcIdStart, nLength, pInfo->mpcIdentifier, nLength ) == 0) )
376 return pInfo;
378 return 0;
381 sheet::ConditionOperator lclGetConditionOperator( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
383 // check for double-char operators
384 if( (rpcString + 1 < pcEnd) && (rpcString[ 1 ] == '=') )
386 sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
387 switch( *rpcString )
389 case '!': eOperator = sheet::ConditionOperator_NOT_EQUAL; break;
390 case '<': eOperator = sheet::ConditionOperator_LESS_EQUAL; break;
391 case '>': eOperator = sheet::ConditionOperator_GREATER_EQUAL; break;
393 if( eOperator != sheet::ConditionOperator_NONE )
395 rpcString += 2;
396 return eOperator;
400 // check for single-char operators
401 if( rpcString < pcEnd )
403 sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
404 switch( *rpcString )
406 case '=': eOperator = sheet::ConditionOperator_EQUAL; break;
407 case '<': eOperator = sheet::ConditionOperator_LESS; break;
408 case '>': eOperator = sheet::ConditionOperator_GREATER; break;
410 if( eOperator != sheet::ConditionOperator_NONE )
412 ++rpcString;
413 return eOperator;
417 return sheet::ConditionOperator_NONE;
420 /** Skips a literal string in a formula expression.
422 @param rpcString
423 (in-out) On call, must point to the first character of the string
424 following the leading string delimiter character. On return, points to
425 the trailing string delimiter character if existing, otherwise to
426 pcEnd.
428 @param pcEnd
429 The end of the string to parse.
431 @param cQuoteChar
432 The string delimiter character enclosing the string.
434 void lclSkipExpressionString( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cQuoteChar )
436 if( rpcString < pcEnd )
438 sal_Int32 nLength = static_cast< sal_Int32 >( pcEnd - rpcString );
439 sal_Int32 nNextQuote = ::rtl_ustr_indexOfChar_WithLength( rpcString, nLength, cQuoteChar );
440 if( nNextQuote >= 0 )
441 rpcString += nNextQuote;
442 else
443 rpcString = pcEnd;
447 /** Skips a formula expression. Processes embedded parentheses, braces, and
448 literal strings.
450 @param rpcString
451 (in-out) On call, must point to the first character of the expression.
452 On return, points to the passed end character if existing, otherwise to
453 pcEnd.
455 @param pcEnd
456 The end of the string to parse.
458 @param cEndChar
459 The termination character following the expression.
461 void lclSkipExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
463 while( rpcString < pcEnd )
465 if( *rpcString == cEndChar )
466 return;
467 switch( *rpcString )
469 case '(': lclSkipExpression( ++rpcString, pcEnd, ')' ); break;
470 case '{': lclSkipExpression( ++rpcString, pcEnd, '}' ); break;
471 case '"': lclSkipExpressionString( ++rpcString, pcEnd, '"' ); break;
472 case '\'': lclSkipExpressionString( ++rpcString, pcEnd, '\'' ); break;
474 if( rpcString < pcEnd ) ++rpcString;
478 /** Extracts a formula expression. Processes embedded parentheses, braces, and
479 literal strings.
481 @param rpcString
482 (in-out) On call, must point to the first character of the expression.
483 On return, points *behind* the passed end character if existing,
484 otherwise to pcEnd.
486 @param pcEnd
487 The end of the string to parse.
489 @param cEndChar
490 The termination character following the expression.
492 /** Tries to skip an empty pair of parentheses (which may contain whitespace
493 characters).
495 @return
496 True on success, rpcString points behind the closing parentheses then.
498 bool lclSkipEmptyParentheses( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
500 if( (rpcString < pcEnd) && (*rpcString == '(') )
502 lclSkipWhitespace( ++rpcString, pcEnd );
503 if( (rpcString < pcEnd) && (*rpcString == ')') )
505 ++rpcString;
506 return true;
509 return false;
512 } // namespace
514 void ScXMLConditionHelper::parseCondition(
515 ScXMLConditionParseResult& rParseResult, const OUString& rAttribute, sal_Int32 nStartIndex )
517 rParseResult.meToken = XML_COND_INVALID;
518 if( (nStartIndex < 0) || (nStartIndex >= rAttribute.getLength()) ) return;
520 // try to find an identifier
521 const sal_Unicode* pcBegin = rAttribute.getStr();
522 const sal_Unicode* pcString = pcBegin + nStartIndex;
523 const sal_Unicode* pcEnd = pcBegin + rAttribute.getLength();
524 if( const ScXMLConditionInfo* pCondInfo = lclGetConditionInfo( pcString, pcEnd ) )
526 // insert default values into parse result (may be changed below)
527 rParseResult.meValidation = pCondInfo->meValidation;
528 rParseResult.meOperator = pCondInfo->meOperator;
529 // continue parsing dependent on token type
530 switch( pCondInfo->meType )
532 case XML_COND_TYPE_KEYWORD:
533 // nothing specific has to follow, success
534 rParseResult.meToken = pCondInfo->meToken;
535 break;
537 case XML_COND_TYPE_COMPARISON:
538 // format is <condition>()<operator><expression>
539 if( lclSkipEmptyParentheses( pcString, pcEnd ) )
541 rParseResult.meOperator = lclGetConditionOperator( pcString, pcEnd );
542 if( rParseResult.meOperator != sheet::ConditionOperator_NONE )
544 lclSkipWhitespace( pcString, pcEnd );
545 if( pcString < pcEnd )
547 rParseResult.meToken = pCondInfo->meToken;
548 // comparison must be at end of attribute, remaining text is the formula
549 rParseResult.maOperand1 = OUString( pcString, static_cast< sal_Int32 >( pcEnd - pcString ) );
553 break;
555 case XML_COND_TYPE_FUNCTION0:
556 // format is <condition>()
557 if( lclSkipEmptyParentheses( pcString, pcEnd ) )
558 rParseResult.meToken = pCondInfo->meToken;
559 break;
561 case XML_COND_TYPE_FUNCTION1:
562 // format is <condition>(<expression>)
563 if( (pcString < pcEnd) && (*pcString == '(') )
565 rParseResult.maOperand1 = getExpression( ++pcString, pcEnd, ')' );
566 if( !rParseResult.maOperand1.isEmpty() )
567 rParseResult.meToken = pCondInfo->meToken;
569 break;
571 case XML_COND_TYPE_FUNCTION2:
572 // format is <condition>(<expression1>,<expression2>)
573 if( (pcString < pcEnd) && (*pcString == '(') )
575 rParseResult.maOperand1 = getExpression( ++pcString, pcEnd, ',' );
576 if( !rParseResult.maOperand1.isEmpty() )
578 rParseResult.maOperand2 = getExpression( pcString, pcEnd, ')' );
579 if( !rParseResult.maOperand2.isEmpty() )
580 rParseResult.meToken = pCondInfo->meToken;
583 break;
585 rParseResult.mnEndIndex = static_cast< sal_Int32 >( pcString - pcBegin );
589 OUString ScXMLConditionHelper::getExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
591 OUString aExp;
592 const sal_Unicode* pcExpStart = rpcString;
593 lclSkipExpression( rpcString, pcEnd, cEndChar );
594 if( rpcString < pcEnd )
596 aExp = OUString( pcExpStart, static_cast< sal_Int32 >( rpcString - pcExpStart ) ).trim();
597 ++rpcString;
599 return aExp;
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */