1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: XMLConverter.cxx,v $
10 * $Revision: 1.29.32.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 #include "XMLConverter.hxx"
35 #include <com/sun/star/util/DateTime.hpp>
36 #include <tools/datetime.hxx>
37 #include <xmloff/xmltoken.hxx>
38 #include <xmloff/xmluconv.hxx>
39 #include "rangelst.hxx"
40 #include "rangeutl.hxx"
42 #include "convuno.hxx"
43 #include "document.hxx"
46 using ::rtl::OUString
;
47 using ::rtl::OUStringBuffer
;
48 using namespace ::com::sun::star
;
49 using namespace xmloff::token
;
52 //___________________________________________________________________
54 ScDocument
* ScXMLConverter::GetScDocument( uno::Reference
< frame::XModel
> xModel
)
58 ScModelObj
* pDocObj
= ScModelObj::getImplementation( xModel
);
59 return pDocObj
? pDocObj
->GetDocument() : NULL
;
65 //___________________________________________________________________
66 sheet::GeneralFunction
ScXMLConverter::GetFunctionFromString( const OUString
& sFunction
)
68 if( IsXMLToken(sFunction
, XML_SUM
) )
69 return sheet::GeneralFunction_SUM
;
70 if( IsXMLToken(sFunction
, XML_AUTO
) )
71 return sheet::GeneralFunction_AUTO
;
72 if( IsXMLToken(sFunction
, XML_COUNT
) )
73 return sheet::GeneralFunction_COUNT
;
74 if( IsXMLToken(sFunction
, XML_COUNTNUMS
) )
75 return sheet::GeneralFunction_COUNTNUMS
;
76 if( IsXMLToken(sFunction
, XML_PRODUCT
) )
77 return sheet::GeneralFunction_PRODUCT
;
78 if( IsXMLToken(sFunction
, XML_AVERAGE
) )
79 return sheet::GeneralFunction_AVERAGE
;
80 if( IsXMLToken(sFunction
, XML_MAX
) )
81 return sheet::GeneralFunction_MAX
;
82 if( IsXMLToken(sFunction
, XML_MIN
) )
83 return sheet::GeneralFunction_MIN
;
84 if( IsXMLToken(sFunction
, XML_STDEV
) )
85 return sheet::GeneralFunction_STDEV
;
86 if( IsXMLToken(sFunction
, XML_STDEVP
) )
87 return sheet::GeneralFunction_STDEVP
;
88 if( IsXMLToken(sFunction
, XML_VAR
) )
89 return sheet::GeneralFunction_VAR
;
90 if( IsXMLToken(sFunction
, XML_VARP
) )
91 return sheet::GeneralFunction_VARP
;
92 return sheet::GeneralFunction_NONE
;
95 ScSubTotalFunc
ScXMLConverter::GetSubTotalFuncFromString( const OUString
& sFunction
)
97 if( IsXMLToken(sFunction
, XML_SUM
) )
98 return SUBTOTAL_FUNC_SUM
;
99 if( IsXMLToken(sFunction
, XML_COUNT
) )
100 return SUBTOTAL_FUNC_CNT
;
101 if( IsXMLToken(sFunction
, XML_COUNTNUMS
) )
102 return SUBTOTAL_FUNC_CNT2
;
103 if( IsXMLToken(sFunction
, XML_PRODUCT
) )
104 return SUBTOTAL_FUNC_PROD
;
105 if( IsXMLToken(sFunction
, XML_AVERAGE
) )
106 return SUBTOTAL_FUNC_AVE
;
107 if( IsXMLToken(sFunction
, XML_MAX
) )
108 return SUBTOTAL_FUNC_MAX
;
109 if( IsXMLToken(sFunction
, XML_MIN
) )
110 return SUBTOTAL_FUNC_MIN
;
111 if( IsXMLToken(sFunction
, XML_STDEV
) )
112 return SUBTOTAL_FUNC_STD
;
113 if( IsXMLToken(sFunction
, XML_STDEVP
) )
114 return SUBTOTAL_FUNC_STDP
;
115 if( IsXMLToken(sFunction
, XML_VAR
) )
116 return SUBTOTAL_FUNC_VAR
;
117 if( IsXMLToken(sFunction
, XML_VARP
) )
118 return SUBTOTAL_FUNC_VARP
;
119 return SUBTOTAL_FUNC_NONE
;
123 //___________________________________________________________________
125 void ScXMLConverter::GetStringFromFunction(
127 const sheet::GeneralFunction eFunction
,
128 sal_Bool bAppendStr
)
133 case sheet::GeneralFunction_AUTO
: sFuncStr
= GetXMLToken( XML_AUTO
); break;
134 case sheet::GeneralFunction_AVERAGE
: sFuncStr
= GetXMLToken( XML_AVERAGE
); break;
135 case sheet::GeneralFunction_COUNT
: sFuncStr
= GetXMLToken( XML_COUNT
); break;
136 case sheet::GeneralFunction_COUNTNUMS
: sFuncStr
= GetXMLToken( XML_COUNTNUMS
); break;
137 case sheet::GeneralFunction_MAX
: sFuncStr
= GetXMLToken( XML_MAX
); break;
138 case sheet::GeneralFunction_MIN
: sFuncStr
= GetXMLToken( XML_MIN
); break;
139 case sheet::GeneralFunction_NONE
: sFuncStr
= GetXMLToken( XML_NONE
); break;
140 case sheet::GeneralFunction_PRODUCT
: sFuncStr
= GetXMLToken( XML_PRODUCT
); break;
141 case sheet::GeneralFunction_STDEV
: sFuncStr
= GetXMLToken( XML_STDEV
); break;
142 case sheet::GeneralFunction_STDEVP
: sFuncStr
= GetXMLToken( XML_STDEVP
); break;
143 case sheet::GeneralFunction_SUM
: sFuncStr
= GetXMLToken( XML_SUM
); break;
144 case sheet::GeneralFunction_VAR
: sFuncStr
= GetXMLToken( XML_VAR
); break;
145 case sheet::GeneralFunction_VARP
: sFuncStr
= GetXMLToken( XML_VARP
); break;
148 // added to avoid warnings
151 ScRangeStringConverter::AssignString( rString
, sFuncStr
, bAppendStr
);
154 void ScXMLConverter::GetStringFromFunction(
156 const ScSubTotalFunc eFunction
,
157 sal_Bool bAppendStr
)
162 case SUBTOTAL_FUNC_AVE
: sFuncStr
= GetXMLToken( XML_AVERAGE
); break;
163 case SUBTOTAL_FUNC_CNT
: sFuncStr
= GetXMLToken( XML_COUNT
); break;
164 case SUBTOTAL_FUNC_CNT2
: sFuncStr
= GetXMLToken( XML_COUNTNUMS
); break;
165 case SUBTOTAL_FUNC_MAX
: sFuncStr
= GetXMLToken( XML_MAX
); break;
166 case SUBTOTAL_FUNC_MIN
: sFuncStr
= GetXMLToken( XML_MIN
); break;
167 case SUBTOTAL_FUNC_NONE
: sFuncStr
= GetXMLToken( XML_NONE
); break;
168 case SUBTOTAL_FUNC_PROD
: sFuncStr
= GetXMLToken( XML_PRODUCT
); break;
169 case SUBTOTAL_FUNC_STD
: sFuncStr
= GetXMLToken( XML_STDEV
); break;
170 case SUBTOTAL_FUNC_STDP
: sFuncStr
= GetXMLToken( XML_STDEVP
); break;
171 case SUBTOTAL_FUNC_SUM
: sFuncStr
= GetXMLToken( XML_SUM
); break;
172 case SUBTOTAL_FUNC_VAR
: sFuncStr
= GetXMLToken( XML_VAR
); break;
173 case SUBTOTAL_FUNC_VARP
: sFuncStr
= GetXMLToken( XML_VARP
); break;
175 ScRangeStringConverter::AssignString( rString
, sFuncStr
, bAppendStr
);
179 //___________________________________________________________________
181 sheet::DataPilotFieldOrientation
ScXMLConverter::GetOrientationFromString(
182 const OUString
& rString
)
184 if( IsXMLToken(rString
, XML_COLUMN
) )
185 return sheet::DataPilotFieldOrientation_COLUMN
;
186 if( IsXMLToken(rString
, XML_ROW
) )
187 return sheet::DataPilotFieldOrientation_ROW
;
188 if( IsXMLToken(rString
, XML_PAGE
) )
189 return sheet::DataPilotFieldOrientation_PAGE
;
190 if( IsXMLToken(rString
, XML_DATA
) )
191 return sheet::DataPilotFieldOrientation_DATA
;
192 return sheet::DataPilotFieldOrientation_HIDDEN
;
196 //___________________________________________________________________
198 void ScXMLConverter::GetStringFromOrientation(
200 const sheet::DataPilotFieldOrientation eOrientation
,
201 sal_Bool bAppendStr
)
204 switch( eOrientation
)
206 case sheet::DataPilotFieldOrientation_HIDDEN
:
207 sOrientStr
= GetXMLToken( XML_HIDDEN
);
209 case sheet::DataPilotFieldOrientation_COLUMN
:
210 sOrientStr
= GetXMLToken( XML_COLUMN
);
212 case sheet::DataPilotFieldOrientation_ROW
:
213 sOrientStr
= GetXMLToken( XML_ROW
);
215 case sheet::DataPilotFieldOrientation_PAGE
:
216 sOrientStr
= GetXMLToken( XML_PAGE
);
218 case sheet::DataPilotFieldOrientation_DATA
:
219 sOrientStr
= GetXMLToken( XML_DATA
);
223 // added to avoid warnings
226 ScRangeStringConverter::AssignString( rString
, sOrientStr
, bAppendStr
);
230 //___________________________________________________________________
232 ScDetectiveObjType
ScXMLConverter::GetDetObjTypeFromString( const OUString
& rString
)
234 if( IsXMLToken(rString
, XML_FROM_SAME_TABLE
) )
235 return SC_DETOBJ_ARROW
;
236 if( IsXMLToken(rString
, XML_FROM_ANOTHER_TABLE
) )
237 return SC_DETOBJ_FROMOTHERTAB
;
238 if( IsXMLToken(rString
, XML_TO_ANOTHER_TABLE
) )
239 return SC_DETOBJ_TOOTHERTAB
;
240 return SC_DETOBJ_NONE
;
243 sal_Bool
ScXMLConverter::GetDetOpTypeFromString( ScDetOpType
& rDetOpType
, const OUString
& rString
)
245 if( IsXMLToken(rString
, XML_TRACE_DEPENDENTS
) )
246 rDetOpType
= SCDETOP_ADDSUCC
;
247 else if( IsXMLToken(rString
, XML_TRACE_PRECEDENTS
) )
248 rDetOpType
= SCDETOP_ADDPRED
;
249 else if( IsXMLToken(rString
, XML_TRACE_ERRORS
) )
250 rDetOpType
= SCDETOP_ADDERROR
;
251 else if( IsXMLToken(rString
, XML_REMOVE_DEPENDENTS
) )
252 rDetOpType
= SCDETOP_DELSUCC
;
253 else if( IsXMLToken(rString
, XML_REMOVE_PRECEDENTS
) )
254 rDetOpType
= SCDETOP_DELPRED
;
261 //___________________________________________________________________
263 void ScXMLConverter::GetStringFromDetObjType(
265 const ScDetectiveObjType eObjType
,
266 sal_Bool bAppendStr
)
271 case SC_DETOBJ_ARROW
:
272 sTypeStr
= GetXMLToken( XML_FROM_SAME_TABLE
);
274 case SC_DETOBJ_FROMOTHERTAB
:
275 sTypeStr
= GetXMLToken( XML_FROM_ANOTHER_TABLE
);
277 case SC_DETOBJ_TOOTHERTAB
:
278 sTypeStr
= GetXMLToken( XML_TO_ANOTHER_TABLE
);
282 // added to avoid warnings
285 ScRangeStringConverter::AssignString( rString
, sTypeStr
, bAppendStr
);
288 void ScXMLConverter::GetStringFromDetOpType(
290 const ScDetOpType eOpType
,
291 sal_Bool bAppendStr
)
296 case SCDETOP_ADDSUCC
:
297 sTypeStr
= GetXMLToken( XML_TRACE_DEPENDENTS
);
299 case SCDETOP_ADDPRED
:
300 sTypeStr
= GetXMLToken( XML_TRACE_PRECEDENTS
);
302 case SCDETOP_ADDERROR
:
303 sTypeStr
= GetXMLToken( XML_TRACE_ERRORS
);
305 case SCDETOP_DELSUCC
:
306 sTypeStr
= GetXMLToken( XML_REMOVE_DEPENDENTS
);
308 case SCDETOP_DELPRED
:
309 sTypeStr
= GetXMLToken( XML_REMOVE_PRECEDENTS
);
312 ScRangeStringConverter::AssignString( rString
, sTypeStr
, bAppendStr
);
316 //___________________________________________________________________
318 void ScXMLConverter::ParseFormula(OUString
& sFormula
, const sal_Bool bIsFormula
)
320 OUStringBuffer
sBuffer(sFormula
.getLength());
321 sal_Bool
bInQuotationMarks(sal_False
);
322 sal_Bool
bInDoubleQuotationMarks(sal_False
);
323 sal_Int16
nCountBraces(0);
324 sal_Unicode
chPrevious('=');
325 for (sal_Int32 i
= 0; i
< sFormula
.getLength(); ++i
)
327 if (sFormula
[i
] == '\'' && !bInDoubleQuotationMarks
&&
329 bInQuotationMarks
= !bInQuotationMarks
;
330 else if (sFormula
[i
] == '"' && !bInQuotationMarks
)
331 bInDoubleQuotationMarks
= !bInDoubleQuotationMarks
;
332 if (bInQuotationMarks
|| bInDoubleQuotationMarks
)
333 sBuffer
.append(sFormula
[i
]);
334 else if (sFormula
[i
] == '[')
336 else if (sFormula
[i
] == ']')
338 else if ((sFormula
[i
] != '.') ||
339 ((nCountBraces
== 0) && bIsFormula
) ||
340 !((chPrevious
== '[') || (chPrevious
== ':') || (chPrevious
== ' ') || (chPrevious
== '=')))
341 sBuffer
.append(sFormula
[i
]);
342 chPrevious
= sFormula
[i
];
345 DBG_ASSERT(nCountBraces
== 0, "there are some braces still open");
346 sFormula
= sBuffer
.makeStringAndClear();
350 //_____________________________________________________________________
352 void ScXMLConverter::ConvertDateTimeToString(const DateTime
& aDateTime
, rtl::OUStringBuffer
& sDate
)
354 util::DateTime aAPIDateTime
;
355 ConvertCoreToAPIDateTime(aDateTime
, aAPIDateTime
);
356 SvXMLUnitConverter::convertDateTime(sDate
, aAPIDateTime
);
359 //UNUSED2008-05 void ScXMLConverter::ConvertStringToDateTime(const rtl::OUString& sDate, DateTime& aDateTime, SvXMLUnitConverter* /* pUnitConverter */)
361 //UNUSED2008-05 com::sun::star::util::DateTime aAPIDateTime;
362 //UNUSED2008-05 SvXMLUnitConverter::convertDateTime(aAPIDateTime, sDate);
363 //UNUSED2008-05 ConvertAPIToCoreDateTime(aAPIDateTime, aDateTime);
366 void ScXMLConverter::ConvertCoreToAPIDateTime(const DateTime
& aDateTime
, util::DateTime
& rDateTime
)
368 rDateTime
.Year
= aDateTime
.GetYear();
369 rDateTime
.Month
= aDateTime
.GetMonth();
370 rDateTime
.Day
= aDateTime
.GetDay();
371 rDateTime
.Hours
= aDateTime
.GetHour();
372 rDateTime
.Minutes
= aDateTime
.GetMin();
373 rDateTime
.Seconds
= aDateTime
.GetSec();
374 rDateTime
.HundredthSeconds
= aDateTime
.Get100Sec();
377 void ScXMLConverter::ConvertAPIToCoreDateTime(const util::DateTime
& aDateTime
, DateTime
& rDateTime
)
379 Date
aDate(aDateTime
.Day
, aDateTime
.Month
, aDateTime
.Year
);
380 Time
aTime(aDateTime
.Hours
, aDateTime
.Minutes
, aDateTime
.Seconds
, aDateTime
.HundredthSeconds
);
381 DateTime
aTempDateTime (aDate
, aTime
);
382 rDateTime
= aTempDateTime
;
385 // ============================================================================
389 /** Enumerates different types of condition tokens. */
390 enum ScXMLConditionTokenType
392 XML_COND_TYPE_KEYWORD
, /// Simple keyword without parentheses, e.g. 'and'.
393 XML_COND_TYPE_COMPARISON
, /// Comparison rule, e.g. 'cell-content()<=2'.
394 XML_COND_TYPE_FUNCTION0
, /// Function without parameters, e.g. 'cell-content-is-whole-number()'.
395 XML_COND_TYPE_FUNCTION1
, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'.
396 XML_COND_TYPE_FUNCTION2
/// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'.
399 struct ScXMLConditionInfo
401 ScXMLConditionToken meToken
;
402 ScXMLConditionTokenType meType
;
403 sheet::ValidationType meValidation
;
404 sheet::ConditionOperator meOperator
;
405 const sal_Char
* mpcIdentifier
;
406 sal_Int32 mnIdentLength
;
409 static const ScXMLConditionInfo spConditionInfos
[] =
411 { XML_COND_AND
, XML_COND_TYPE_KEYWORD
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "and" ) },
412 { XML_COND_CELLCONTENT
, XML_COND_TYPE_COMPARISON
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) },
413 { XML_COND_ISBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_ANY
, sheet::ConditionOperator_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) },
414 { XML_COND_ISNOTBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_ANY
, sheet::ConditionOperator_NOT_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) },
415 { XML_COND_ISWHOLENUMBER
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_WHOLE
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) },
416 { XML_COND_ISDECIMALNUMBER
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_DECIMAL
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) },
417 { XML_COND_ISDATE
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_DATE
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) },
418 { XML_COND_ISTIME
, XML_COND_TYPE_FUNCTION0
, sheet::ValidationType_TIME
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) },
419 { XML_COND_ISINLIST
, XML_COND_TYPE_FUNCTION1
, sheet::ValidationType_LIST
, sheet::ConditionOperator_EQUAL
, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) },
420 { XML_COND_TEXTLENGTH
, XML_COND_TYPE_COMPARISON
, sheet::ValidationType_TEXT_LEN
, sheet::ConditionOperator_NONE
, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) },
421 { XML_COND_TEXTLENGTH_ISBETWEEN
, XML_COND_TYPE_FUNCTION2
, sheet::ValidationType_TEXT_LEN
, sheet::ConditionOperator_BETWEEN
, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) },
422 { 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" ) },
423 { XML_COND_ISTRUEFORMULA
, XML_COND_TYPE_FUNCTION1
, sheet::ValidationType_CUSTOM
, sheet::ConditionOperator_FORMULA
, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) }
426 void lclSkipWhitespace( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
428 while( (rpcString
< pcEnd
) && (*rpcString
<= ' ') ) ++rpcString
;
431 const ScXMLConditionInfo
* lclGetConditionInfo( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
433 lclSkipWhitespace( rpcString
, pcEnd
);
434 /* Search the end of an identifier name; assuming that valid identifiers
435 consist of [a-z-] only. */
436 const sal_Unicode
* pcIdStart
= rpcString
;
437 while( (rpcString
< pcEnd
) && (((*rpcString
>= 'a') && (*rpcString
<= 'z')) || (*rpcString
== '-')) ) ++rpcString
;
438 sal_Int32 nLength
= static_cast< sal_Int32
>( rpcString
- pcIdStart
);
440 // search the table for an entry
442 for( const ScXMLConditionInfo
* pInfo
= spConditionInfos
; pInfo
< STATIC_TABLE_END( spConditionInfos
); ++pInfo
)
443 if( (nLength
== pInfo
->mnIdentLength
) && (::rtl_ustr_ascii_shortenedCompare_WithLength( pcIdStart
, nLength
, pInfo
->mpcIdentifier
, nLength
) == 0) )
449 sheet::ConditionOperator
lclGetConditionOperator( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
451 // check for double-char operators
452 if( (rpcString
+ 1 < pcEnd
) && (rpcString
[ 1 ] == '=') )
454 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
457 case '!': eOperator
= sheet::ConditionOperator_NOT_EQUAL
; break;
458 case '<': eOperator
= sheet::ConditionOperator_LESS_EQUAL
; break;
459 case '>': eOperator
= sheet::ConditionOperator_GREATER_EQUAL
; break;
461 if( eOperator
!= sheet::ConditionOperator_NONE
)
468 // check for single-char operators
469 if( rpcString
< pcEnd
)
471 sheet::ConditionOperator eOperator
= sheet::ConditionOperator_NONE
;
474 case '=': eOperator
= sheet::ConditionOperator_EQUAL
; break;
475 case '<': eOperator
= sheet::ConditionOperator_LESS
; break;
476 case '>': eOperator
= sheet::ConditionOperator_GREATER
; break;
478 if( eOperator
!= sheet::ConditionOperator_NONE
)
485 return sheet::ConditionOperator_NONE
;
488 /** Skips a literal string in a formula expression.
491 (in-out) On call, must point to the first character of the string
492 following the leading string delimiter character. On return, points to
493 the trailing string delimiter character if existing, otherwise to
497 The end of the string to parse.
500 The string delimiter character enclosing the string.
502 void lclSkipExpressionString( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cQuoteChar
)
504 if( rpcString
< pcEnd
)
506 sal_Int32 nLength
= static_cast< sal_Int32
>( pcEnd
- rpcString
);
507 sal_Int32 nNextQuote
= ::rtl_ustr_indexOfChar_WithLength( rpcString
, nLength
, cQuoteChar
);
508 if( nNextQuote
>= 0 )
509 rpcString
+= nNextQuote
;
515 /** Skips a formula expression. Processes embedded parentheses, braces, and
519 (in-out) On call, must point to the first character of the expression.
520 On return, points to the passed end character if existing, otherwise to
524 The end of the string to parse.
527 The termination character following the expression.
529 void lclSkipExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
531 while( rpcString
< pcEnd
)
533 if( *rpcString
== cEndChar
)
537 case '(': lclSkipExpression( ++rpcString
, pcEnd
, ')' ); break;
538 case '{': lclSkipExpression( ++rpcString
, pcEnd
, '}' ); break;
539 case '"': lclSkipExpressionString( ++rpcString
, pcEnd
, '"' ); break;
540 case '\'': lclSkipExpressionString( ++rpcString
, pcEnd
, '\'' ); break;
542 if( rpcString
< pcEnd
) ++rpcString
;
546 /** Extracts a formula expression. Processes embedded parentheses, braces, and
550 (in-out) On call, must point to the first character of the expression.
551 On return, points *behind* the passed end character if existing,
555 The end of the string to parse.
558 The termination character following the expression.
560 OUString
lclGetExpression( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
, sal_Unicode cEndChar
)
563 const sal_Unicode
* pcExpStart
= rpcString
;
564 lclSkipExpression( rpcString
, pcEnd
, cEndChar
);
565 if( rpcString
< pcEnd
)
567 aExp
= OUString( pcExpStart
, static_cast< sal_Int32
>( rpcString
- pcExpStart
) ).trim();
573 /** Tries to skip an empty pair of parentheses (which may contain whitespace
577 True on success, rpcString points behind the closing parentheses then.
579 bool lclSkipEmptyParentheses( const sal_Unicode
*& rpcString
, const sal_Unicode
* pcEnd
)
581 if( (rpcString
< pcEnd
) && (*rpcString
== '(') )
583 lclSkipWhitespace( ++rpcString
, pcEnd
);
584 if( (rpcString
< pcEnd
) && (*rpcString
== ')') )
595 // ----------------------------------------------------------------------------
597 /*static*/ void ScXMLConditionHelper::parseCondition(
598 ScXMLConditionParseResult
& rParseResult
, const OUString
& rAttribute
, sal_Int32 nStartIndex
)
600 rParseResult
.meToken
= XML_COND_INVALID
;
601 if( (nStartIndex
< 0) || (nStartIndex
>= rAttribute
.getLength()) ) return;
603 // try to find an identifier
604 const sal_Unicode
* pcBegin
= rAttribute
.getStr();
605 const sal_Unicode
* pcString
= pcBegin
+ nStartIndex
;
606 const sal_Unicode
* pcEnd
= pcBegin
+ rAttribute
.getLength();
607 if( const ScXMLConditionInfo
* pCondInfo
= lclGetConditionInfo( pcString
, pcEnd
) )
609 // insert default values into parse result (may be changed below)
610 rParseResult
.meValidation
= pCondInfo
->meValidation
;
611 rParseResult
.meOperator
= pCondInfo
->meOperator
;
612 // continue parsing dependent on token type
613 switch( pCondInfo
->meType
)
615 case XML_COND_TYPE_KEYWORD
:
616 // nothing specific has to follow, success
617 rParseResult
.meToken
= pCondInfo
->meToken
;
620 case XML_COND_TYPE_COMPARISON
:
621 // format is <condition>()<operator><expression>
622 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
624 rParseResult
.meOperator
= lclGetConditionOperator( pcString
, pcEnd
);
625 if( rParseResult
.meOperator
!= sheet::ConditionOperator_NONE
)
627 lclSkipWhitespace( pcString
, pcEnd
);
628 if( pcString
< pcEnd
)
630 rParseResult
.meToken
= pCondInfo
->meToken
;
631 // comparison must be at end of attribute, remaining text is the formula
632 rParseResult
.maOperand1
= OUString( pcString
, static_cast< sal_Int32
>( pcEnd
- pcString
) );
638 case XML_COND_TYPE_FUNCTION0
:
639 // format is <condition>()
640 if( lclSkipEmptyParentheses( pcString
, pcEnd
) )
641 rParseResult
.meToken
= pCondInfo
->meToken
;
644 case XML_COND_TYPE_FUNCTION1
:
645 // format is <condition>(<expression>)
646 if( (pcString
< pcEnd
) && (*pcString
== '(') )
648 rParseResult
.maOperand1
= lclGetExpression( ++pcString
, pcEnd
, ')' );
649 if( rParseResult
.maOperand1
.getLength() > 0 )
650 rParseResult
.meToken
= pCondInfo
->meToken
;
654 case XML_COND_TYPE_FUNCTION2
:
655 // format is <condition>(<expression1>,<expression2>)
656 if( (pcString
< pcEnd
) && (*pcString
== '(') )
658 rParseResult
.maOperand1
= lclGetExpression( ++pcString
, pcEnd
, ',' );
659 if( rParseResult
.maOperand1
.getLength() > 0 )
661 rParseResult
.maOperand2
= lclGetExpression( pcString
, pcEnd
, ')' );
662 if( rParseResult
.maOperand2
.getLength() > 0 )
663 rParseResult
.meToken
= pCondInfo
->meToken
;
668 rParseResult
.mnEndIndex
= static_cast< sal_Int32
>( pcString
- pcBegin
);
672 // ============================================================================