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 <tools/datetime.hxx>
23 #include <sax/tools/converter.hxx>
24 #include <xmloff/xmltoken.hxx>
25 #include "rangelst.hxx"
26 #include "rangeutl.hxx"
28 #include "convuno.hxx"
29 #include "document.hxx"
32 using namespace ::com::sun::star
;
33 using namespace xmloff::token
;
35 ScDocument
* ScXMLConverter::GetScDocument( uno::Reference
< frame::XModel
> xModel
)
39 ScModelObj
* pDocObj
= ScModelObj::getImplementation( xModel
);
40 return pDocObj
? pDocObj
->GetDocument() : 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(
103 const sheet::GeneralFunction 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;
124 // added to avoid warnings
127 ScRangeStringConverter::AssignString( rString
, sFuncStr
, bAppendStr
);
130 void ScXMLConverter::GetStringFromFunction(
132 const ScSubTotalFunc 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(
173 const sheet::DataPilotFieldOrientation eOrientation
,
177 switch( eOrientation
)
179 case sheet::DataPilotFieldOrientation_HIDDEN
:
180 sOrientStr
= GetXMLToken( XML_HIDDEN
);
182 case sheet::DataPilotFieldOrientation_COLUMN
:
183 sOrientStr
= GetXMLToken( XML_COLUMN
);
185 case sheet::DataPilotFieldOrientation_ROW
:
186 sOrientStr
= GetXMLToken( XML_ROW
);
188 case sheet::DataPilotFieldOrientation_PAGE
:
189 sOrientStr
= GetXMLToken( XML_PAGE
);
191 case sheet::DataPilotFieldOrientation_DATA
:
192 sOrientStr
= GetXMLToken( XML_DATA
);
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
;
230 void ScXMLConverter::GetStringFromDetObjType(
232 const ScDetectiveObjType eObjType
,
238 case SC_DETOBJ_ARROW
:
239 sTypeStr
= GetXMLToken( XML_FROM_SAME_TABLE
);
241 case SC_DETOBJ_FROMOTHERTAB
:
242 sTypeStr
= GetXMLToken( XML_FROM_ANOTHER_TABLE
);
244 case SC_DETOBJ_TOOTHERTAB
:
245 sTypeStr
= GetXMLToken( XML_TO_ANOTHER_TABLE
);
249 // added to avoid warnings
252 ScRangeStringConverter::AssignString( rString
, sTypeStr
, bAppendStr
);
255 void ScXMLConverter::GetStringFromDetOpType(
257 const ScDetOpType eOpType
,
263 case SCDETOP_ADDSUCC
:
264 sTypeStr
= GetXMLToken( XML_TRACE_DEPENDENTS
);
266 case SCDETOP_ADDPRED
:
267 sTypeStr
= GetXMLToken( XML_TRACE_PRECEDENTS
);
269 case SCDETOP_ADDERROR
:
270 sTypeStr
= GetXMLToken( XML_TRACE_ERRORS
);
272 case SCDETOP_DELSUCC
:
273 sTypeStr
= GetXMLToken( XML_REMOVE_DEPENDENTS
);
275 case SCDETOP_DELPRED
:
276 sTypeStr
= GetXMLToken( XML_REMOVE_PRECEDENTS
);
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
&&
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
] == '[')
300 else if (sFormula
[i
] == ']')
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);
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
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) )
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
;
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
)
400 // check for single-char operators
401 if( rpcString
< pcEnd
)
403 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
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
)
417 return sheet::ConditionOperator_NONE
;
420 /** Skips a literal string in a formula expression.
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
429 The end of the string to parse.
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
;
447 /** Skips a formula expression. Processes embedded parentheses, braces, and
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
456 The end of the string to parse.
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
)
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
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,
487 The end of the string to parse.
490 The termination character following the expression.
492 /** Tries to skip an empty pair of parentheses (which may contain whitespace
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
== ')') )
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
;
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
) );
555 case XML_COND_TYPE_FUNCTION0
:
556 // format is <condition>()
557 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
558 rParseResult
.meToken
= pCondInfo
->meToken
;
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
;
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
;
585 rParseResult
.mnEndIndex
= static_cast< sal_Int32
>( pcString
- pcBegin
);
589 OUString
ScXMLConditionHelper::getExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
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();
602 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */