1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <com/sun/star/sheet/GeneralFunction2.hpp>
23 #include <comphelper/servicehelper.hxx>
24 #include <tools/datetime.hxx>
25 #include <sax/tools/converter.hxx>
26 #include <xmloff/xmltoken.hxx>
27 #include <rangeutl.hxx>
29 #include <generalfunction.hxx>
31 using namespace ::com::sun::star
;
32 using namespace xmloff::token
;
34 ScDocument
* ScXMLConverter::GetScDocument( const uno::Reference
< frame::XModel
>& xModel
)
38 ScModelObj
* pDocObj
= comphelper::getUnoTunnelImplementation
<ScModelObj
>( xModel
);
39 return pDocObj
? pDocObj
->GetDocument() : nullptr;
44 sheet::GeneralFunction
ScXMLConverter::GetFunctionFromString( const OUString
& sFunction
)
46 if( IsXMLToken(sFunction
, XML_SUM
) )
47 return sheet::GeneralFunction_SUM
;
48 if( IsXMLToken(sFunction
, XML_AUTO
) )
49 return sheet::GeneralFunction_AUTO
;
50 if( IsXMLToken(sFunction
, XML_COUNT
) )
51 return sheet::GeneralFunction_COUNT
;
52 if( IsXMLToken(sFunction
, XML_COUNTNUMS
) )
53 return sheet::GeneralFunction_COUNTNUMS
;
54 if( IsXMLToken(sFunction
, XML_PRODUCT
) )
55 return sheet::GeneralFunction_PRODUCT
;
56 if( IsXMLToken(sFunction
, XML_AVERAGE
) )
57 return sheet::GeneralFunction_AVERAGE
;
58 if( IsXMLToken(sFunction
, XML_MAX
) )
59 return sheet::GeneralFunction_MAX
;
60 if( IsXMLToken(sFunction
, XML_MIN
) )
61 return sheet::GeneralFunction_MIN
;
62 if( IsXMLToken(sFunction
, XML_STDEV
) )
63 return sheet::GeneralFunction_STDEV
;
64 if( IsXMLToken(sFunction
, XML_STDEVP
) )
65 return sheet::GeneralFunction_STDEVP
;
66 if( IsXMLToken(sFunction
, XML_VAR
) )
67 return sheet::GeneralFunction_VAR
;
68 if( IsXMLToken(sFunction
, XML_VARP
) )
69 return sheet::GeneralFunction_VARP
;
70 return sheet::GeneralFunction_NONE
;
73 ScGeneralFunction
ScXMLConverter::GetFunctionFromString2( const OUString
& sFunction
)
75 if( IsXMLToken(sFunction
, XML_SUM
) )
76 return ScGeneralFunction::SUM
;
77 if( IsXMLToken(sFunction
, XML_AUTO
) )
78 return ScGeneralFunction::AUTO
;
79 if( IsXMLToken(sFunction
, XML_COUNT
) )
80 return ScGeneralFunction::COUNT
;
81 if( IsXMLToken(sFunction
, XML_COUNTNUMS
) )
82 return ScGeneralFunction::COUNTNUMS
;
83 if( IsXMLToken(sFunction
, XML_PRODUCT
) )
84 return ScGeneralFunction::PRODUCT
;
85 if( IsXMLToken(sFunction
, XML_AVERAGE
) )
86 return ScGeneralFunction::AVERAGE
;
87 if( IsXMLToken(sFunction
, XML_MEDIAN
) )
88 return ScGeneralFunction::MEDIAN
;
89 if( IsXMLToken(sFunction
, XML_MAX
) )
90 return ScGeneralFunction::MAX
;
91 if( IsXMLToken(sFunction
, XML_MIN
) )
92 return ScGeneralFunction::MIN
;
93 if( IsXMLToken(sFunction
, XML_STDEV
) )
94 return ScGeneralFunction::STDEV
;
95 if( IsXMLToken(sFunction
, XML_STDEVP
) )
96 return ScGeneralFunction::STDEVP
;
97 if( IsXMLToken(sFunction
, XML_VAR
) )
98 return ScGeneralFunction::VAR
;
99 if( IsXMLToken(sFunction
, XML_VARP
) )
100 return ScGeneralFunction::VARP
;
101 return ScGeneralFunction::NONE
;
104 ScSubTotalFunc
ScXMLConverter::GetSubTotalFuncFromString( const OUString
& sFunction
)
106 if( IsXMLToken(sFunction
, XML_SUM
) )
107 return SUBTOTAL_FUNC_SUM
;
108 if( IsXMLToken(sFunction
, XML_COUNT
) )
109 return SUBTOTAL_FUNC_CNT
;
110 if( IsXMLToken(sFunction
, XML_COUNTNUMS
) )
111 return SUBTOTAL_FUNC_CNT2
;
112 if( IsXMLToken(sFunction
, XML_PRODUCT
) )
113 return SUBTOTAL_FUNC_PROD
;
114 if( IsXMLToken(sFunction
, XML_AVERAGE
) )
115 return SUBTOTAL_FUNC_AVE
;
116 if( IsXMLToken(sFunction
, XML_MEDIAN
) )
117 return SUBTOTAL_FUNC_MED
;
118 if( IsXMLToken(sFunction
, XML_MAX
) )
119 return SUBTOTAL_FUNC_MAX
;
120 if( IsXMLToken(sFunction
, XML_MIN
) )
121 return SUBTOTAL_FUNC_MIN
;
122 if( IsXMLToken(sFunction
, XML_STDEV
) )
123 return SUBTOTAL_FUNC_STD
;
124 if( IsXMLToken(sFunction
, XML_STDEVP
) )
125 return SUBTOTAL_FUNC_STDP
;
126 if( IsXMLToken(sFunction
, XML_VAR
) )
127 return SUBTOTAL_FUNC_VAR
;
128 if( IsXMLToken(sFunction
, XML_VARP
) )
129 return SUBTOTAL_FUNC_VARP
;
130 return SUBTOTAL_FUNC_NONE
;
133 void ScXMLConverter::GetStringFromFunction(
135 sal_Int16 eFunction
)
140 case sheet::GeneralFunction2::AUTO
: sFuncStr
= GetXMLToken( XML_AUTO
); break;
141 case sheet::GeneralFunction2::AVERAGE
: sFuncStr
= GetXMLToken( XML_AVERAGE
); break;
142 case sheet::GeneralFunction2::MEDIAN
: sFuncStr
= GetXMLToken( XML_MEDIAN
); break;
143 case sheet::GeneralFunction2::COUNT
: sFuncStr
= GetXMLToken( XML_COUNT
); break;
144 case sheet::GeneralFunction2::COUNTNUMS
: sFuncStr
= GetXMLToken( XML_COUNTNUMS
); break;
145 case sheet::GeneralFunction2::MAX
: sFuncStr
= GetXMLToken( XML_MAX
); break;
146 case sheet::GeneralFunction2::MIN
: sFuncStr
= GetXMLToken( XML_MIN
); break;
147 case sheet::GeneralFunction2::NONE
: sFuncStr
= GetXMLToken( XML_NONE
); break;
148 case sheet::GeneralFunction2::PRODUCT
: sFuncStr
= GetXMLToken( XML_PRODUCT
); break;
149 case sheet::GeneralFunction2::STDEV
: sFuncStr
= GetXMLToken( XML_STDEV
); break;
150 case sheet::GeneralFunction2::STDEVP
: sFuncStr
= GetXMLToken( XML_STDEVP
); break;
151 case sheet::GeneralFunction2::SUM
: sFuncStr
= GetXMLToken( XML_SUM
); break;
152 case sheet::GeneralFunction2::VAR
: sFuncStr
= GetXMLToken( XML_VAR
); break;
153 case sheet::GeneralFunction2::VARP
: sFuncStr
= GetXMLToken( XML_VARP
); break;
159 ScRangeStringConverter::AssignString( rString
, sFuncStr
, false );
162 void ScXMLConverter::GetStringFromFunction(
164 const ScSubTotalFunc eFunction
)
169 case SUBTOTAL_FUNC_AVE
: sFuncStr
= GetXMLToken( XML_AVERAGE
); break;
170 case SUBTOTAL_FUNC_MED
: sFuncStr
= GetXMLToken( XML_MEDIAN
); break;
171 case SUBTOTAL_FUNC_CNT
: sFuncStr
= GetXMLToken( XML_COUNT
); break;
172 case SUBTOTAL_FUNC_CNT2
: sFuncStr
= GetXMLToken( XML_COUNTNUMS
); break;
173 case SUBTOTAL_FUNC_MAX
: sFuncStr
= GetXMLToken( XML_MAX
); break;
174 case SUBTOTAL_FUNC_MIN
: sFuncStr
= GetXMLToken( XML_MIN
); break;
175 case SUBTOTAL_FUNC_NONE
: sFuncStr
= GetXMLToken( XML_NONE
); break;
176 case SUBTOTAL_FUNC_PROD
: sFuncStr
= GetXMLToken( XML_PRODUCT
); break;
177 case SUBTOTAL_FUNC_STD
: sFuncStr
= GetXMLToken( XML_STDEV
); break;
178 case SUBTOTAL_FUNC_STDP
: sFuncStr
= GetXMLToken( XML_STDEVP
); break;
179 case SUBTOTAL_FUNC_SUM
: sFuncStr
= GetXMLToken( XML_SUM
); break;
180 case SUBTOTAL_FUNC_SELECTION_COUNT
: break;
181 // it is not needed as it is only a UI value and not document content
183 case SUBTOTAL_FUNC_VAR
: sFuncStr
= GetXMLToken( XML_VAR
); break;
184 case SUBTOTAL_FUNC_VARP
: sFuncStr
= GetXMLToken( XML_VARP
); break;
186 ScRangeStringConverter::AssignString( rString
, sFuncStr
, false );
189 sheet::DataPilotFieldOrientation
ScXMLConverter::GetOrientationFromString(
190 const OUString
& rString
)
192 if( IsXMLToken(rString
, XML_COLUMN
) )
193 return sheet::DataPilotFieldOrientation_COLUMN
;
194 if( IsXMLToken(rString
, XML_ROW
) )
195 return sheet::DataPilotFieldOrientation_ROW
;
196 if( IsXMLToken(rString
, XML_PAGE
) )
197 return sheet::DataPilotFieldOrientation_PAGE
;
198 if( IsXMLToken(rString
, XML_DATA
) )
199 return sheet::DataPilotFieldOrientation_DATA
;
200 return sheet::DataPilotFieldOrientation_HIDDEN
;
203 void ScXMLConverter::GetStringFromOrientation(
205 const sheet::DataPilotFieldOrientation eOrientation
)
208 switch( eOrientation
)
210 case sheet::DataPilotFieldOrientation_HIDDEN
:
211 sOrientStr
= GetXMLToken( XML_HIDDEN
);
213 case sheet::DataPilotFieldOrientation_COLUMN
:
214 sOrientStr
= GetXMLToken( XML_COLUMN
);
216 case sheet::DataPilotFieldOrientation_ROW
:
217 sOrientStr
= GetXMLToken( XML_ROW
);
219 case sheet::DataPilotFieldOrientation_PAGE
:
220 sOrientStr
= GetXMLToken( XML_PAGE
);
222 case sheet::DataPilotFieldOrientation_DATA
:
223 sOrientStr
= GetXMLToken( XML_DATA
);
227 // added to avoid warnings
230 ScRangeStringConverter::AssignString( rString
, sOrientStr
, false );
233 ScDetectiveObjType
ScXMLConverter::GetDetObjTypeFromString( const OUString
& rString
)
235 if( IsXMLToken(rString
, XML_FROM_SAME_TABLE
) )
236 return SC_DETOBJ_ARROW
;
237 if( IsXMLToken(rString
, XML_FROM_ANOTHER_TABLE
) )
238 return SC_DETOBJ_FROMOTHERTAB
;
239 if( IsXMLToken(rString
, XML_TO_ANOTHER_TABLE
) )
240 return SC_DETOBJ_TOOTHERTAB
;
241 return SC_DETOBJ_NONE
;
244 bool ScXMLConverter::GetDetOpTypeFromString( ScDetOpType
& rDetOpType
, const OUString
& rString
)
246 if( IsXMLToken(rString
, XML_TRACE_DEPENDENTS
) )
247 rDetOpType
= SCDETOP_ADDSUCC
;
248 else if( IsXMLToken(rString
, XML_TRACE_PRECEDENTS
) )
249 rDetOpType
= SCDETOP_ADDPRED
;
250 else if( IsXMLToken(rString
, XML_TRACE_ERRORS
) )
251 rDetOpType
= SCDETOP_ADDERROR
;
252 else if( IsXMLToken(rString
, XML_REMOVE_DEPENDENTS
) )
253 rDetOpType
= SCDETOP_DELSUCC
;
254 else if( IsXMLToken(rString
, XML_REMOVE_PRECEDENTS
) )
255 rDetOpType
= SCDETOP_DELPRED
;
261 void ScXMLConverter::GetStringFromDetObjType(
263 const ScDetectiveObjType eObjType
)
268 case SC_DETOBJ_ARROW
:
269 sTypeStr
= GetXMLToken( XML_FROM_SAME_TABLE
);
271 case SC_DETOBJ_FROMOTHERTAB
:
272 sTypeStr
= GetXMLToken( XML_FROM_ANOTHER_TABLE
);
274 case SC_DETOBJ_TOOTHERTAB
:
275 sTypeStr
= GetXMLToken( XML_TO_ANOTHER_TABLE
);
279 // added to avoid warnings
282 ScRangeStringConverter::AssignString( rString
, sTypeStr
, false );
285 void ScXMLConverter::GetStringFromDetOpType(
287 const ScDetOpType eOpType
)
292 case SCDETOP_ADDSUCC
:
293 sTypeStr
= GetXMLToken( XML_TRACE_DEPENDENTS
);
295 case SCDETOP_ADDPRED
:
296 sTypeStr
= GetXMLToken( XML_TRACE_PRECEDENTS
);
298 case SCDETOP_ADDERROR
:
299 sTypeStr
= GetXMLToken( XML_TRACE_ERRORS
);
301 case SCDETOP_DELSUCC
:
302 sTypeStr
= GetXMLToken( XML_REMOVE_DEPENDENTS
);
304 case SCDETOP_DELPRED
:
305 sTypeStr
= GetXMLToken( XML_REMOVE_PRECEDENTS
);
308 ScRangeStringConverter::AssignString( rString
, sTypeStr
, false );
311 void ScXMLConverter::ConvertCellRangeAddress(OUString
& sFormula
)
313 OUStringBuffer
sBuffer(sFormula
.getLength());
314 bool bInQuotationMarks(false);
315 sal_Unicode
chPrevious('=');
316 const sal_Unicode
* p
= sFormula
.getStr();
317 const sal_Unicode
* const pStop
= p
+ sFormula
.getLength();
318 for ( ; p
< pStop
; ++p
)
320 const sal_Unicode c
= *p
;
322 bInQuotationMarks
= !bInQuotationMarks
;
323 if (bInQuotationMarks
)
325 else if ((c
!= '.') ||
326 !((chPrevious
== ':') || (chPrevious
== ' ') || (chPrevious
== '=')))
331 sFormula
= sBuffer
.makeStringAndClear();
334 void ScXMLConverter::ConvertDateTimeToString(const DateTime
& aDateTime
, OUStringBuffer
& sDate
)
336 css::util::DateTime aAPIDateTime
= aDateTime
.GetUNODateTime();
337 ::sax::Converter::convertDateTime(sDate
, aAPIDateTime
, nullptr);
342 /** Enumerates different types of condition tokens. */
343 enum ScXMLConditionTokenType
345 XML_COND_TYPE_KEYWORD
, /// Simple keyword without parentheses, e.g. 'and'.
346 XML_COND_TYPE_COMPARISON
, /// Comparison rule, e.g. 'cell-content()<=2'.
347 XML_COND_TYPE_FUNCTION0
, /// Function without parameters, e.g. 'cell-content-is-whole-number()'.
348 XML_COND_TYPE_FUNCTION1
, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'.
349 XML_COND_TYPE_FUNCTION2
/// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'.
352 struct ScXMLConditionInfo
354 ScXMLConditionToken
const meToken
;
355 ScXMLConditionTokenType
const meType
;
356 sheet::ValidationType
const meValidation
;
357 sheet::ConditionOperator
const meOperator
;
358 const sal_Char
* mpcIdentifier
;
359 sal_Int32
const mnIdentLength
;
362 static const ScXMLConditionInfo spConditionInfos
[] =
364 { XML_COND_AND
, XML_COND_TYPE_KEYWORD
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "and" ) },
365 { XML_COND_CELLCONTENT
, XML_COND_TYPE_COMPARISON
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) },
366 { XML_COND_ISBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_ANY
, sheet::ConditionOperator_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) },
367 { XML_COND_ISNOTBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NOT_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) },
368 { XML_COND_ISWHOLENUMBER
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_WHOLE
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) },
369 { XML_COND_ISDECIMALNUMBER
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_DECIMAL
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) },
370 { XML_COND_ISDATE
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_DATE
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) },
371 { XML_COND_ISTIME
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_TIME
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) },
372 { XML_COND_ISINLIST
, XML_COND_TYPE_FUNCTION1
, sheet::ValidationType_LIST
, sheet::ConditionOperator_EQUAL
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) },
373 { XML_COND_TEXTLENGTH
, XML_COND_TYPE_COMPARISON
, sheet::ValidationType_TEXT_LEN
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) },
374 { XML_COND_TEXTLENGTH_ISBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_TEXT_LEN
, sheet::ConditionOperator_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) },
375 { 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" ) },
376 { XML_COND_ISTRUEFORMULA
, XML_COND_TYPE_FUNCTION1
, sheet::ValidationType_CUSTOM
, sheet::ConditionOperator_FORMULA
, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) }
379 void lclSkipWhitespace( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
381 while( (rpcString
< pcEnd
) && (*rpcString
<= ' ') ) ++rpcString
;
384 const ScXMLConditionInfo
* lclGetConditionInfo( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
386 lclSkipWhitespace( rpcString
, pcEnd
);
387 /* Search the end of an identifier name; assuming that valid identifiers
388 consist of [a-z-] only. */
389 const sal_Unicode
* pcIdStart
= rpcString
;
390 while( (rpcString
< pcEnd
) && (((*rpcString
>= 'a') && (*rpcString
<= 'z')) || (*rpcString
== '-')) ) ++rpcString
;
391 sal_Int32 nLength
= static_cast< sal_Int32
>( rpcString
- pcIdStart
);
393 // search the table for an entry
395 for(auto const &rInfo
: spConditionInfos
)
396 if((nLength
== rInfo
.mnIdentLength
)
397 && (::rtl_ustr_ascii_shortenedCompare_WithLength(pcIdStart
, nLength
, rInfo
.mpcIdentifier
, nLength
) == 0) )
403 sheet::ConditionOperator
lclGetConditionOperator( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
405 // check for double-char operators
406 if( (rpcString
+ 1 < pcEnd
) && (rpcString
[ 1 ] == '=') )
408 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
411 case '!': eOperator
= sheet::ConditionOperator_NOT_EQUAL
; break;
412 case '<': eOperator
= sheet::ConditionOperator_LESS_EQUAL
; break;
413 case '>': eOperator
= sheet::ConditionOperator_GREATER_EQUAL
; break;
415 if( eOperator
!= sheet::ConditionOperator_NONE
)
422 // check for single-char operators
423 if( rpcString
< pcEnd
)
425 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
428 case '=': eOperator
= sheet::ConditionOperator_EQUAL
; break;
429 case '<': eOperator
= sheet::ConditionOperator_LESS
; break;
430 case '>': eOperator
= sheet::ConditionOperator_GREATER
; break;
432 if( eOperator
!= sheet::ConditionOperator_NONE
)
439 return sheet::ConditionOperator_NONE
;
442 /** Skips a literal string in a formula expression.
445 (in-out) On call, must point to the first character of the string
446 following the leading string delimiter character. On return, points to
447 the trailing string delimiter character if existing, otherwise to
451 The end of the string to parse.
454 The string delimiter character enclosing the string.
456 void lclSkipExpressionString( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cQuoteChar
)
458 if( rpcString
< pcEnd
)
460 sal_Int32 nLength
= static_cast< sal_Int32
>( pcEnd
- rpcString
);
461 sal_Int32 nNextQuote
= ::rtl_ustr_indexOfChar_WithLength( rpcString
, nLength
, cQuoteChar
);
462 if( nNextQuote
>= 0 )
463 rpcString
+= nNextQuote
;
469 /** Skips a formula expression. Processes embedded parentheses, braces, and
473 (in-out) On call, must point to the first character of the expression.
474 On return, points to the passed end character if existing, otherwise to
478 The end of the string to parse.
481 The termination character following the expression.
483 void lclSkipExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
485 while( rpcString
< pcEnd
)
487 if( *rpcString
== cEndChar
)
491 case '(': lclSkipExpression( ++rpcString
, pcEnd
, ')' ); break;
492 case '{': lclSkipExpression( ++rpcString
, pcEnd
, '}' ); break;
493 case '"': lclSkipExpressionString( ++rpcString
, pcEnd
, '"' ); break;
494 case '\'': lclSkipExpressionString( ++rpcString
, pcEnd
, '\'' ); break;
496 if( rpcString
< pcEnd
) ++rpcString
;
500 /** Extracts a formula expression. Processes embedded parentheses, braces, and
504 (in-out) On call, must point to the first character of the expression.
505 On return, points *behind* the passed end character if existing,
509 The end of the string to parse.
512 The termination character following the expression.
514 /** Tries to skip an empty pair of parentheses (which may contain whitespace
518 True on success, rpcString points behind the closing parentheses then.
520 bool lclSkipEmptyParentheses( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
522 if( (rpcString
< pcEnd
) && (*rpcString
== '(') )
524 lclSkipWhitespace( ++rpcString
, pcEnd
);
525 if( (rpcString
< pcEnd
) && (*rpcString
== ')') )
536 void ScXMLConditionHelper::parseCondition(
537 ScXMLConditionParseResult
& rParseResult
, const OUString
& rAttribute
, sal_Int32 nStartIndex
)
539 rParseResult
.meToken
= XML_COND_INVALID
;
540 if( (nStartIndex
< 0) || (nStartIndex
>= rAttribute
.getLength()) ) return;
542 // try to find an identifier
543 const sal_Unicode
* pcBegin
= rAttribute
.getStr();
544 const sal_Unicode
* pcString
= pcBegin
+ nStartIndex
;
545 const sal_Unicode
* pcEnd
= pcBegin
+ rAttribute
.getLength();
546 if( const ScXMLConditionInfo
* pCondInfo
= lclGetConditionInfo( pcString
, pcEnd
) )
548 // insert default values into parse result (may be changed below)
549 rParseResult
.meValidation
= pCondInfo
->meValidation
;
550 rParseResult
.meOperator
= pCondInfo
->meOperator
;
551 // continue parsing dependent on token type
552 switch( pCondInfo
->meType
)
554 case XML_COND_TYPE_KEYWORD
:
555 // nothing specific has to follow, success
556 rParseResult
.meToken
= pCondInfo
->meToken
;
559 case XML_COND_TYPE_COMPARISON
:
560 // format is <condition>()<operator><expression>
561 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
563 rParseResult
.meOperator
= lclGetConditionOperator( pcString
, pcEnd
);
564 if( rParseResult
.meOperator
!= sheet::ConditionOperator_NONE
)
566 lclSkipWhitespace( pcString
, pcEnd
);
567 if( pcString
< pcEnd
)
569 rParseResult
.meToken
= pCondInfo
->meToken
;
570 // comparison must be at end of attribute, remaining text is the formula
571 rParseResult
.maOperand1
= OUString( pcString
, static_cast< sal_Int32
>( pcEnd
- pcString
) );
577 case XML_COND_TYPE_FUNCTION0
:
578 // format is <condition>()
579 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
580 rParseResult
.meToken
= pCondInfo
->meToken
;
583 case XML_COND_TYPE_FUNCTION1
:
584 // format is <condition>(<expression>)
585 if( (pcString
< pcEnd
) && (*pcString
== '(') )
587 rParseResult
.maOperand1
= getExpression( ++pcString
, pcEnd
, ')' );
588 if( !rParseResult
.maOperand1
.isEmpty() )
589 rParseResult
.meToken
= pCondInfo
->meToken
;
593 case XML_COND_TYPE_FUNCTION2
:
594 // format is <condition>(<expression1>,<expression2>)
595 if( (pcString
< pcEnd
) && (*pcString
== '(') )
597 rParseResult
.maOperand1
= getExpression( ++pcString
, pcEnd
, ',' );
598 if( !rParseResult
.maOperand1
.isEmpty() )
600 rParseResult
.maOperand2
= getExpression( pcString
, pcEnd
, ')' );
601 if( !rParseResult
.maOperand2
.isEmpty() )
602 rParseResult
.meToken
= pCondInfo
->meToken
;
607 rParseResult
.mnEndIndex
= static_cast< sal_Int32
>( pcString
- pcBegin
);
611 OUString
ScXMLConditionHelper::getExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
614 const sal_Unicode
* pcExpStart
= rpcString
;
615 lclSkipExpression( rpcString
, pcEnd
, cEndChar
);
616 if( rpcString
< pcEnd
)
618 aExp
= OUString( pcExpStart
, static_cast< sal_Int32
>( rpcString
- pcExpStart
) ).trim();
624 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */