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::getFromUnoTunnel
<ScModelObj
>( xModel
);
39 return pDocObj
? pDocObj
->GetDocument() : nullptr;
44 sheet::GeneralFunction
ScXMLConverter::GetFunctionFromString( std::u16string_view 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( std::u16string_view 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( std::u16string_view 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 OUString
ScXMLConverter::GetStringFromFunction(
134 sal_Int16 eFunction
)
139 case sheet::GeneralFunction2::AUTO
: sFuncStr
= GetXMLToken( XML_AUTO
); break;
140 case sheet::GeneralFunction2::AVERAGE
: sFuncStr
= GetXMLToken( XML_AVERAGE
); break;
141 case sheet::GeneralFunction2::MEDIAN
: sFuncStr
= GetXMLToken( XML_MEDIAN
); break;
142 case sheet::GeneralFunction2::COUNT
: sFuncStr
= GetXMLToken( XML_COUNT
); break;
143 case sheet::GeneralFunction2::COUNTNUMS
: sFuncStr
= GetXMLToken( XML_COUNTNUMS
); break;
144 case sheet::GeneralFunction2::MAX
: sFuncStr
= GetXMLToken( XML_MAX
); break;
145 case sheet::GeneralFunction2::MIN
: sFuncStr
= GetXMLToken( XML_MIN
); break;
146 case sheet::GeneralFunction2::NONE
: sFuncStr
= GetXMLToken( XML_NONE
); break;
147 case sheet::GeneralFunction2::PRODUCT
: sFuncStr
= GetXMLToken( XML_PRODUCT
); break;
148 case sheet::GeneralFunction2::STDEV
: sFuncStr
= GetXMLToken( XML_STDEV
); break;
149 case sheet::GeneralFunction2::STDEVP
: sFuncStr
= GetXMLToken( XML_STDEVP
); break;
150 case sheet::GeneralFunction2::SUM
: sFuncStr
= GetXMLToken( XML_SUM
); break;
151 case sheet::GeneralFunction2::VAR
: sFuncStr
= GetXMLToken( XML_VAR
); break;
152 case sheet::GeneralFunction2::VARP
: sFuncStr
= GetXMLToken( XML_VARP
); break;
159 ScRangeStringConverter::AssignString( str
, sFuncStr
, false );
163 OUString
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;
187 ScRangeStringConverter::AssignString( str
, sFuncStr
, false );
191 sheet::DataPilotFieldOrientation
ScXMLConverter::GetOrientationFromString(
192 std::u16string_view rString
)
194 if( IsXMLToken(rString
, XML_COLUMN
) )
195 return sheet::DataPilotFieldOrientation_COLUMN
;
196 if( IsXMLToken(rString
, XML_ROW
) )
197 return sheet::DataPilotFieldOrientation_ROW
;
198 if( IsXMLToken(rString
, XML_PAGE
) )
199 return sheet::DataPilotFieldOrientation_PAGE
;
200 if( IsXMLToken(rString
, XML_DATA
) )
201 return sheet::DataPilotFieldOrientation_DATA
;
202 return sheet::DataPilotFieldOrientation_HIDDEN
;
205 OUString
ScXMLConverter::GetStringFromOrientation(
206 const sheet::DataPilotFieldOrientation eOrientation
)
209 switch( eOrientation
)
211 case sheet::DataPilotFieldOrientation_HIDDEN
:
212 sOrientStr
= GetXMLToken( XML_HIDDEN
);
214 case sheet::DataPilotFieldOrientation_COLUMN
:
215 sOrientStr
= GetXMLToken( XML_COLUMN
);
217 case sheet::DataPilotFieldOrientation_ROW
:
218 sOrientStr
= GetXMLToken( XML_ROW
);
220 case sheet::DataPilotFieldOrientation_PAGE
:
221 sOrientStr
= GetXMLToken( XML_PAGE
);
223 case sheet::DataPilotFieldOrientation_DATA
:
224 sOrientStr
= GetXMLToken( XML_DATA
);
228 // added to avoid warnings
232 ScRangeStringConverter::AssignString( str
, sOrientStr
, false );
236 ScDetectiveObjType
ScXMLConverter::GetDetObjTypeFromString( std::u16string_view rString
)
238 if( IsXMLToken(rString
, XML_FROM_SAME_TABLE
) )
239 return SC_DETOBJ_ARROW
;
240 if( IsXMLToken(rString
, XML_FROM_ANOTHER_TABLE
) )
241 return SC_DETOBJ_FROMOTHERTAB
;
242 if( IsXMLToken(rString
, XML_TO_ANOTHER_TABLE
) )
243 return SC_DETOBJ_TOOTHERTAB
;
244 return SC_DETOBJ_NONE
;
247 bool ScXMLConverter::GetDetOpTypeFromString( ScDetOpType
& rDetOpType
, std::u16string_view rString
)
249 if( IsXMLToken(rString
, XML_TRACE_DEPENDENTS
) )
250 rDetOpType
= SCDETOP_ADDSUCC
;
251 else if( IsXMLToken(rString
, XML_TRACE_PRECEDENTS
) )
252 rDetOpType
= SCDETOP_ADDPRED
;
253 else if( IsXMLToken(rString
, XML_TRACE_ERRORS
) )
254 rDetOpType
= SCDETOP_ADDERROR
;
255 else if( IsXMLToken(rString
, XML_REMOVE_DEPENDENTS
) )
256 rDetOpType
= SCDETOP_DELSUCC
;
257 else if( IsXMLToken(rString
, XML_REMOVE_PRECEDENTS
) )
258 rDetOpType
= SCDETOP_DELPRED
;
264 OUString
ScXMLConverter::GetStringFromDetObjType(
265 const ScDetectiveObjType eObjType
)
270 case SC_DETOBJ_ARROW
:
271 sTypeStr
= GetXMLToken( XML_FROM_SAME_TABLE
);
273 case SC_DETOBJ_FROMOTHERTAB
:
274 sTypeStr
= GetXMLToken( XML_FROM_ANOTHER_TABLE
);
276 case SC_DETOBJ_TOOTHERTAB
:
277 sTypeStr
= GetXMLToken( XML_TO_ANOTHER_TABLE
);
281 // added to avoid warnings
285 ScRangeStringConverter::AssignString( str
, sTypeStr
, false );
289 OUString
ScXMLConverter::GetStringFromDetOpType(
290 const ScDetOpType eOpType
)
295 case SCDETOP_ADDSUCC
:
296 sTypeStr
= GetXMLToken( XML_TRACE_DEPENDENTS
);
298 case SCDETOP_ADDPRED
:
299 sTypeStr
= GetXMLToken( XML_TRACE_PRECEDENTS
);
301 case SCDETOP_ADDERROR
:
302 sTypeStr
= GetXMLToken( XML_TRACE_ERRORS
);
304 case SCDETOP_DELSUCC
:
305 sTypeStr
= GetXMLToken( XML_REMOVE_DEPENDENTS
);
307 case SCDETOP_DELPRED
:
308 sTypeStr
= GetXMLToken( XML_REMOVE_PRECEDENTS
);
312 ScRangeStringConverter::AssignString( str
, sTypeStr
, false );
316 void ScXMLConverter::ConvertCellRangeAddress(OUString
& sFormula
)
318 OUStringBuffer
sBuffer(sFormula
.getLength());
319 bool bInQuotationMarks(false);
320 sal_Unicode
chPrevious('=');
321 const sal_Unicode
* p
= sFormula
.getStr();
322 const sal_Unicode
* const pStop
= p
+ sFormula
.getLength();
323 for ( ; p
< pStop
; ++p
)
325 const sal_Unicode c
= *p
;
327 bInQuotationMarks
= !bInQuotationMarks
;
328 if (bInQuotationMarks
)
330 else if ((c
!= '.') ||
331 !((chPrevious
== ':') || (chPrevious
== ' ') || (chPrevious
== '=')))
336 sFormula
= sBuffer
.makeStringAndClear();
339 void ScXMLConverter::ConvertDateTimeToString(const DateTime
& aDateTime
, OUStringBuffer
& sDate
)
341 css::util::DateTime aAPIDateTime
= aDateTime
.GetUNODateTime();
342 ::sax::Converter::convertDateTime(sDate
, aAPIDateTime
, nullptr);
347 /** Enumerates different types of condition tokens. */
348 enum ScXMLConditionTokenType
350 XML_COND_TYPE_KEYWORD
, /// Simple keyword without parentheses, e.g. 'and'.
351 XML_COND_TYPE_COMPARISON
, /// Comparison rule, e.g. 'cell-content()<=2'.
352 XML_COND_TYPE_FUNCTION0
, /// Function without parameters, e.g. 'cell-content-is-whole-number()'.
353 XML_COND_TYPE_FUNCTION1
, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'.
354 XML_COND_TYPE_FUNCTION2
/// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'.
357 struct ScXMLConditionInfo
359 ScXMLConditionToken meToken
;
360 ScXMLConditionTokenType meType
;
361 sheet::ValidationType meValidation
;
362 sheet::ConditionOperator meOperator
;
363 const char* mpcIdentifier
;
364 sal_Int32 mnIdentLength
;
367 const ScXMLConditionInfo spConditionInfos
[] =
369 { XML_COND_AND
, XML_COND_TYPE_KEYWORD
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "and" ) },
370 { XML_COND_CELLCONTENT
, XML_COND_TYPE_COMPARISON
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) },
371 { XML_COND_ISBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_ANY
, sheet::ConditionOperator_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) },
372 { XML_COND_ISNOTBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NOT_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) },
373 { XML_COND_ISWHOLENUMBER
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_WHOLE
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) },
374 { XML_COND_ISDECIMALNUMBER
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_DECIMAL
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) },
375 { XML_COND_ISDATE
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_DATE
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) },
376 { XML_COND_ISTIME
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_TIME
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) },
377 { XML_COND_ISINLIST
, XML_COND_TYPE_FUNCTION1
, sheet::ValidationType_LIST
, sheet::ConditionOperator_EQUAL
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) },
378 { XML_COND_TEXTLENGTH
, XML_COND_TYPE_COMPARISON
, sheet::ValidationType_TEXT_LEN
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) },
379 { XML_COND_TEXTLENGTH_ISBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_TEXT_LEN
, sheet::ConditionOperator_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) },
380 { 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" ) },
381 { XML_COND_ISTRUEFORMULA
, XML_COND_TYPE_FUNCTION1
, sheet::ValidationType_CUSTOM
, sheet::ConditionOperator_FORMULA
, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) }
384 void lclSkipWhitespace( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
386 while( (rpcString
< pcEnd
) && (*rpcString
<= ' ') ) ++rpcString
;
389 const ScXMLConditionInfo
* lclGetConditionInfo( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
391 lclSkipWhitespace( rpcString
, pcEnd
);
392 /* Search the end of an identifier name; assuming that valid identifiers
393 consist of [a-z-] only. */
394 const sal_Unicode
* pcIdStart
= rpcString
;
395 while( (rpcString
< pcEnd
) && (((*rpcString
>= 'a') && (*rpcString
<= 'z')) || (*rpcString
== '-')) ) ++rpcString
;
396 sal_Int32 nLength
= static_cast< sal_Int32
>( rpcString
- pcIdStart
);
398 // search the table for an entry
400 for(auto const &rInfo
: spConditionInfos
)
401 if((nLength
== rInfo
.mnIdentLength
)
402 && (::rtl_ustr_ascii_shortenedCompare_WithLength(pcIdStart
, nLength
, rInfo
.mpcIdentifier
, nLength
) == 0) )
408 sheet::ConditionOperator
lclGetConditionOperator( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
410 // check for double-char operators
411 if( (rpcString
+ 1 < pcEnd
) && (rpcString
[ 1 ] == '=') )
413 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
416 case '!': eOperator
= sheet::ConditionOperator_NOT_EQUAL
; break;
417 case '<': eOperator
= sheet::ConditionOperator_LESS_EQUAL
; break;
418 case '>': eOperator
= sheet::ConditionOperator_GREATER_EQUAL
; break;
420 if( eOperator
!= sheet::ConditionOperator_NONE
)
427 // check for single-char operators
428 if( rpcString
< pcEnd
)
430 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
433 case '=': eOperator
= sheet::ConditionOperator_EQUAL
; break;
434 case '<': eOperator
= sheet::ConditionOperator_LESS
; break;
435 case '>': eOperator
= sheet::ConditionOperator_GREATER
; break;
437 if( eOperator
!= sheet::ConditionOperator_NONE
)
444 return sheet::ConditionOperator_NONE
;
447 /** Skips a literal string in a formula expression.
450 (in-out) On call, must point to the first character of the string
451 following the leading string delimiter character. On return, points to
452 the trailing string delimiter character if existing, otherwise to
456 The end of the string to parse.
459 The string delimiter character enclosing the string.
461 void lclSkipExpressionString( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cQuoteChar
)
463 if( rpcString
< pcEnd
)
465 sal_Int32 nLength
= static_cast< sal_Int32
>( pcEnd
- rpcString
);
466 sal_Int32 nNextQuote
= ::rtl_ustr_indexOfChar_WithLength( rpcString
, nLength
, cQuoteChar
);
467 if( nNextQuote
>= 0 )
468 rpcString
+= nNextQuote
;
474 /** Skips a formula expression. Processes embedded parentheses, braces, and
478 (in-out) On call, must point to the first character of the expression.
479 On return, points to the passed end character if existing, otherwise to
483 The end of the string to parse.
486 The termination character following the expression.
488 void lclSkipExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
490 while( rpcString
< pcEnd
)
492 if( *rpcString
== cEndChar
)
496 case '(': lclSkipExpression( ++rpcString
, pcEnd
, ')' ); break;
497 case '{': lclSkipExpression( ++rpcString
, pcEnd
, '}' ); break;
498 case '"': lclSkipExpressionString( ++rpcString
, pcEnd
, '"' ); break;
499 case '\'': lclSkipExpressionString( ++rpcString
, pcEnd
, '\'' ); break;
501 if( rpcString
< pcEnd
) ++rpcString
;
505 /** Extracts a formula expression. Processes embedded parentheses, braces, and
509 (in-out) On call, must point to the first character of the expression.
510 On return, points *behind* the passed end character if existing,
514 The end of the string to parse.
517 The termination character following the expression.
519 /** Tries to skip an empty pair of parentheses (which may contain whitespace
523 True on success, rpcString points behind the closing parentheses then.
525 bool lclSkipEmptyParentheses( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
527 if( (rpcString
< pcEnd
) && (*rpcString
== '(') )
529 lclSkipWhitespace( ++rpcString
, pcEnd
);
530 if( (rpcString
< pcEnd
) && (*rpcString
== ')') )
541 void ScXMLConditionHelper::parseCondition(
542 ScXMLConditionParseResult
& rParseResult
, const OUString
& rAttribute
, sal_Int32 nStartIndex
)
544 rParseResult
.meToken
= XML_COND_INVALID
;
545 if( (nStartIndex
< 0) || (nStartIndex
>= rAttribute
.getLength()) ) return;
547 // try to find an identifier
548 const sal_Unicode
* pcBegin
= rAttribute
.getStr();
549 const sal_Unicode
* pcString
= pcBegin
+ nStartIndex
;
550 const sal_Unicode
* pcEnd
= pcBegin
+ rAttribute
.getLength();
551 const ScXMLConditionInfo
* pCondInfo
= lclGetConditionInfo( pcString
, pcEnd
);
555 // insert default values into parse result (may be changed below)
556 rParseResult
.meValidation
= pCondInfo
->meValidation
;
557 rParseResult
.meOperator
= pCondInfo
->meOperator
;
558 // continue parsing dependent on token type
559 switch( pCondInfo
->meType
)
561 case XML_COND_TYPE_KEYWORD
:
562 // nothing specific has to follow, success
563 rParseResult
.meToken
= pCondInfo
->meToken
;
566 case XML_COND_TYPE_COMPARISON
:
567 // format is <condition>()<operator><expression>
568 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
570 rParseResult
.meOperator
= lclGetConditionOperator( pcString
, pcEnd
);
571 if( rParseResult
.meOperator
!= sheet::ConditionOperator_NONE
)
573 lclSkipWhitespace( pcString
, pcEnd
);
574 if( pcString
< pcEnd
)
576 rParseResult
.meToken
= pCondInfo
->meToken
;
577 // comparison must be at end of attribute, remaining text is the formula
578 rParseResult
.maOperand1
= OUString( pcString
, static_cast< sal_Int32
>( pcEnd
- pcString
) );
584 case XML_COND_TYPE_FUNCTION0
:
585 // format is <condition>()
586 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
587 rParseResult
.meToken
= pCondInfo
->meToken
;
590 case XML_COND_TYPE_FUNCTION1
:
591 // format is <condition>(<expression>)
592 if( (pcString
< pcEnd
) && (*pcString
== '(') )
594 rParseResult
.maOperand1
= getExpression( ++pcString
, pcEnd
, ')' );
595 if( !rParseResult
.maOperand1
.isEmpty() )
596 rParseResult
.meToken
= pCondInfo
->meToken
;
600 case XML_COND_TYPE_FUNCTION2
:
601 // format is <condition>(<expression1>,<expression2>)
602 if( (pcString
< pcEnd
) && (*pcString
== '(') )
604 rParseResult
.maOperand1
= getExpression( ++pcString
, pcEnd
, ',' );
605 if( !rParseResult
.maOperand1
.isEmpty() )
607 rParseResult
.maOperand2
= getExpression( pcString
, pcEnd
, ')' );
608 if( !rParseResult
.maOperand2
.isEmpty() )
609 rParseResult
.meToken
= pCondInfo
->meToken
;
614 rParseResult
.mnEndIndex
= static_cast< sal_Int32
>( pcString
- pcBegin
);
617 OUString
ScXMLConditionHelper::getExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
620 const sal_Unicode
* pcExpStart
= rpcString
;
621 lclSkipExpression( rpcString
, pcEnd
, cEndChar
);
622 if( rpcString
< pcEnd
)
624 aExp
= OUString( pcExpStart
, static_cast< sal_Int32
>( rpcString
- pcExpStart
) ).trim();
630 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */