update dev300-m58
[ooovba.git] / sc / source / filter / xml / XMLConverter.cxx
blob950fb74aaef81d6356a141b34bf614881bf3f61c
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"
41 #include "docuno.hxx"
42 #include "convuno.hxx"
43 #include "document.hxx"
44 #include "ftools.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 )
56 if (xModel.is())
58 ScModelObj* pDocObj = ScModelObj::getImplementation( xModel );
59 return pDocObj ? pDocObj->GetDocument() : NULL;
61 return 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(
126 OUString& rString,
127 const sheet::GeneralFunction eFunction,
128 sal_Bool bAppendStr )
130 OUString sFuncStr;
131 switch( eFunction )
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;
146 default:
148 // added to avoid warnings
151 ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
154 void ScXMLConverter::GetStringFromFunction(
155 OUString& rString,
156 const ScSubTotalFunc eFunction,
157 sal_Bool bAppendStr )
159 OUString sFuncStr;
160 switch( eFunction )
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(
199 OUString& rString,
200 const sheet::DataPilotFieldOrientation eOrientation,
201 sal_Bool bAppendStr )
203 OUString sOrientStr;
204 switch( eOrientation )
206 case sheet::DataPilotFieldOrientation_HIDDEN:
207 sOrientStr = GetXMLToken( XML_HIDDEN );
208 break;
209 case sheet::DataPilotFieldOrientation_COLUMN:
210 sOrientStr = GetXMLToken( XML_COLUMN );
211 break;
212 case sheet::DataPilotFieldOrientation_ROW:
213 sOrientStr = GetXMLToken( XML_ROW );
214 break;
215 case sheet::DataPilotFieldOrientation_PAGE:
216 sOrientStr = GetXMLToken( XML_PAGE );
217 break;
218 case sheet::DataPilotFieldOrientation_DATA:
219 sOrientStr = GetXMLToken( XML_DATA );
220 break;
221 default:
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;
255 else
256 return sal_False;
257 return sal_True;
261 //___________________________________________________________________
263 void ScXMLConverter::GetStringFromDetObjType(
264 OUString& rString,
265 const ScDetectiveObjType eObjType,
266 sal_Bool bAppendStr )
268 OUString sTypeStr;
269 switch( eObjType )
271 case SC_DETOBJ_ARROW:
272 sTypeStr = GetXMLToken( XML_FROM_SAME_TABLE );
273 break;
274 case SC_DETOBJ_FROMOTHERTAB:
275 sTypeStr = GetXMLToken( XML_FROM_ANOTHER_TABLE );
276 break;
277 case SC_DETOBJ_TOOTHERTAB:
278 sTypeStr = GetXMLToken( XML_TO_ANOTHER_TABLE );
279 break;
280 default:
282 // added to avoid warnings
285 ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
288 void ScXMLConverter::GetStringFromDetOpType(
289 OUString& rString,
290 const ScDetOpType eOpType,
291 sal_Bool bAppendStr )
293 OUString sTypeStr;
294 switch( eOpType )
296 case SCDETOP_ADDSUCC:
297 sTypeStr = GetXMLToken( XML_TRACE_DEPENDENTS );
298 break;
299 case SCDETOP_ADDPRED:
300 sTypeStr = GetXMLToken( XML_TRACE_PRECEDENTS );
301 break;
302 case SCDETOP_ADDERROR:
303 sTypeStr = GetXMLToken( XML_TRACE_ERRORS );
304 break;
305 case SCDETOP_DELSUCC:
306 sTypeStr = GetXMLToken( XML_REMOVE_DEPENDENTS );
307 break;
308 case SCDETOP_DELPRED:
309 sTypeStr = GetXMLToken( XML_REMOVE_PRECEDENTS );
310 break;
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 &&
328 chPrevious != '\\')
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] == '[')
335 ++nCountBraces;
336 else if (sFormula[i] == ']')
337 nCountBraces--;
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 */)
360 //UNUSED2008-05 {
361 //UNUSED2008-05 com::sun::star::util::DateTime aAPIDateTime;
362 //UNUSED2008-05 SvXMLUnitConverter::convertDateTime(aAPIDateTime, sDate);
363 //UNUSED2008-05 ConvertAPIToCoreDateTime(aAPIDateTime, aDateTime);
364 //UNUSED2008-05 }
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 // ============================================================================
387 namespace {
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
441 if( nLength > 0 )
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) )
444 return pInfo;
446 return 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;
455 switch( *rpcString )
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 )
463 rpcString += 2;
464 return eOperator;
468 // check for single-char operators
469 if( rpcString < pcEnd )
471 sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
472 switch( *rpcString )
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 )
480 ++rpcString;
481 return eOperator;
485 return sheet::ConditionOperator_NONE;
488 /** Skips a literal string in a formula expression.
490 @param rpcString
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
494 pcEnd.
496 @param pcEnd
497 The end of the string to parse.
499 @param cQuoteChar
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;
510 else
511 rpcString = pcEnd;
515 /** Skips a formula expression. Processes embedded parentheses, braces, and
516 literal strings.
518 @param rpcString
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
521 pcEnd.
523 @param pcEnd
524 The end of the string to parse.
526 @param cEndChar
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 )
534 return;
535 switch( *rpcString )
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
547 literal strings.
549 @param rpcString
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,
552 otherwise to pcEnd.
554 @param pcEnd
555 The end of the string to parse.
557 @param cEndChar
558 The termination character following the expression.
560 OUString lclGetExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
562 OUString aExp;
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();
568 ++rpcString;
570 return aExp;
573 /** Tries to skip an empty pair of parentheses (which may contain whitespace
574 characters).
576 @return
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 == ')') )
586 ++rpcString;
587 return true;
590 return false;
593 } // namespace
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;
618 break;
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 ) );
636 break;
638 case XML_COND_TYPE_FUNCTION0:
639 // format is <condition>()
640 if( lclSkipEmptyParentheses( pcString, pcEnd ) )
641 rParseResult.meToken = pCondInfo->meToken;
642 break;
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;
652 break;
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;
666 break;
668 rParseResult.mnEndIndex = static_cast< sal_Int32 >( pcString - pcBegin );
672 // ============================================================================