1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 #include "XMLConverter.hxx"
28 #include <com/sun/star/util/DateTime.hpp>
29 #include <tools/datetime.hxx>
30 #include <xmloff/xmltoken.hxx>
31 #include <xmloff/xmluconv.hxx>
32 #include "rangelst.hxx"
33 #include "rangeutl.hxx"
34 #include "docuno.hxx"
35 #include "convuno.hxx"
36 #include "document.hxx"
37 #include "ftools.hxx"
38
39 using ::rtl::OUString;
40 using ::rtl::OUStringBuffer;
41 using namespace ::com::sun::star;
42 using namespace xmloff::token;
43
44
45 //___________________________________________________________________
46
GetScDocument(uno::Reference<frame::XModel> xModel)47 ScDocument* ScXMLConverter::GetScDocument( uno::Reference< frame::XModel > xModel )
48 {
49 if (xModel.is())
50 {
51 ScModelObj* pDocObj = ScModelObj::getImplementation( xModel );
52 return pDocObj ? pDocObj->GetDocument() : NULL;
53 }
54 return NULL;
55 }
56
57
58 //___________________________________________________________________
GetFunctionFromString(const OUString & sFunction)59 sheet::GeneralFunction ScXMLConverter::GetFunctionFromString( const OUString& sFunction )
60 {
61 if( IsXMLToken(sFunction, XML_SUM ) )
62 return sheet::GeneralFunction_SUM;
63 if( IsXMLToken(sFunction, XML_AUTO ) )
64 return sheet::GeneralFunction_AUTO;
65 if( IsXMLToken(sFunction, XML_COUNT ) )
66 return sheet::GeneralFunction_COUNT;
67 if( IsXMLToken(sFunction, XML_COUNTNUMS ) )
68 return sheet::GeneralFunction_COUNTNUMS;
69 if( IsXMLToken(sFunction, XML_PRODUCT ) )
70 return sheet::GeneralFunction_PRODUCT;
71 if( IsXMLToken(sFunction, XML_AVERAGE ) )
72 return sheet::GeneralFunction_AVERAGE;
73 if( IsXMLToken(sFunction, XML_MAX ) )
74 return sheet::GeneralFunction_MAX;
75 if( IsXMLToken(sFunction, XML_MIN ) )
76 return sheet::GeneralFunction_MIN;
77 if( IsXMLToken(sFunction, XML_STDEV ) )
78 return sheet::GeneralFunction_STDEV;
79 if( IsXMLToken(sFunction, XML_STDEVP ) )
80 return sheet::GeneralFunction_STDEVP;
81 if( IsXMLToken(sFunction, XML_VAR ) )
82 return sheet::GeneralFunction_VAR;
83 if( IsXMLToken(sFunction, XML_VARP ) )
84 return sheet::GeneralFunction_VARP;
85 return sheet::GeneralFunction_NONE;
86 }
87
GetSubTotalFuncFromString(const OUString & sFunction)88 ScSubTotalFunc ScXMLConverter::GetSubTotalFuncFromString( const OUString& sFunction )
89 {
90 if( IsXMLToken(sFunction, XML_SUM ) )
91 return SUBTOTAL_FUNC_SUM;
92 if( IsXMLToken(sFunction, XML_COUNT ) )
93 return SUBTOTAL_FUNC_CNT;
94 if( IsXMLToken(sFunction, XML_COUNTNUMS ) )
95 return SUBTOTAL_FUNC_CNT2;
96 if( IsXMLToken(sFunction, XML_PRODUCT ) )
97 return SUBTOTAL_FUNC_PROD;
98 if( IsXMLToken(sFunction, XML_AVERAGE ) )
99 return SUBTOTAL_FUNC_AVE;
100 if( IsXMLToken(sFunction, XML_MAX ) )
101 return SUBTOTAL_FUNC_MAX;
102 if( IsXMLToken(sFunction, XML_MIN ) )
103 return SUBTOTAL_FUNC_MIN;
104 if( IsXMLToken(sFunction, XML_STDEV ) )
105 return SUBTOTAL_FUNC_STD;
106 if( IsXMLToken(sFunction, XML_STDEVP ) )
107 return SUBTOTAL_FUNC_STDP;
108 if( IsXMLToken(sFunction, XML_VAR ) )
109 return SUBTOTAL_FUNC_VAR;
110 if( IsXMLToken(sFunction, XML_VARP ) )
111 return SUBTOTAL_FUNC_VARP;
112 return SUBTOTAL_FUNC_NONE;
113 }
114
115
116 //___________________________________________________________________
117
GetStringFromFunction(OUString & rString,const sheet::GeneralFunction eFunction,sal_Bool bAppendStr)118 void ScXMLConverter::GetStringFromFunction(
119 OUString& rString,
120 const sheet::GeneralFunction eFunction,
121 sal_Bool bAppendStr )
122 {
123 OUString sFuncStr;
124 switch( eFunction )
125 {
126 case sheet::GeneralFunction_AUTO: sFuncStr = GetXMLToken( XML_AUTO ); break;
127 case sheet::GeneralFunction_AVERAGE: sFuncStr = GetXMLToken( XML_AVERAGE ); break;
128 case sheet::GeneralFunction_COUNT: sFuncStr = GetXMLToken( XML_COUNT ); break;
129 case sheet::GeneralFunction_COUNTNUMS: sFuncStr = GetXMLToken( XML_COUNTNUMS ); break;
130 case sheet::GeneralFunction_MAX: sFuncStr = GetXMLToken( XML_MAX ); break;
131 case sheet::GeneralFunction_MIN: sFuncStr = GetXMLToken( XML_MIN ); break;
132 case sheet::GeneralFunction_NONE: sFuncStr = GetXMLToken( XML_NONE ); break;
133 case sheet::GeneralFunction_PRODUCT: sFuncStr = GetXMLToken( XML_PRODUCT ); break;
134 case sheet::GeneralFunction_STDEV: sFuncStr = GetXMLToken( XML_STDEV ); break;
135 case sheet::GeneralFunction_STDEVP: sFuncStr = GetXMLToken( XML_STDEVP ); break;
136 case sheet::GeneralFunction_SUM: sFuncStr = GetXMLToken( XML_SUM ); break;
137 case sheet::GeneralFunction_VAR: sFuncStr = GetXMLToken( XML_VAR ); break;
138 case sheet::GeneralFunction_VARP: sFuncStr = GetXMLToken( XML_VARP ); break;
139 default:
140 {
141 // added to avoid warnings
142 }
143 }
144 ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
145 }
146
GetStringFromFunction(OUString & rString,const ScSubTotalFunc eFunction,sal_Bool bAppendStr)147 void ScXMLConverter::GetStringFromFunction(
148 OUString& rString,
149 const ScSubTotalFunc eFunction,
150 sal_Bool bAppendStr )
151 {
152 OUString sFuncStr;
153 switch( eFunction )
154 {
155 case SUBTOTAL_FUNC_AVE: sFuncStr = GetXMLToken( XML_AVERAGE ); break;
156 case SUBTOTAL_FUNC_CNT: sFuncStr = GetXMLToken( XML_COUNT ); break;
157 case SUBTOTAL_FUNC_CNT2: sFuncStr = GetXMLToken( XML_COUNTNUMS ); break;
158 case SUBTOTAL_FUNC_MAX: sFuncStr = GetXMLToken( XML_MAX ); break;
159 case SUBTOTAL_FUNC_MIN: sFuncStr = GetXMLToken( XML_MIN ); break;
160 case SUBTOTAL_FUNC_NONE: sFuncStr = GetXMLToken( XML_NONE ); break;
161 case SUBTOTAL_FUNC_PROD: sFuncStr = GetXMLToken( XML_PRODUCT ); break;
162 case SUBTOTAL_FUNC_STD: sFuncStr = GetXMLToken( XML_STDEV ); break;
163 case SUBTOTAL_FUNC_STDP: sFuncStr = GetXMLToken( XML_STDEVP ); break;
164 case SUBTOTAL_FUNC_SUM: sFuncStr = GetXMLToken( XML_SUM ); break;
165 case SUBTOTAL_FUNC_VAR: sFuncStr = GetXMLToken( XML_VAR ); break;
166 case SUBTOTAL_FUNC_VARP: sFuncStr = GetXMLToken( XML_VARP ); break;
167 }
168 ScRangeStringConverter::AssignString( rString, sFuncStr, bAppendStr );
169 }
170
171
172 //___________________________________________________________________
173
GetOrientationFromString(const OUString & rString)174 sheet::DataPilotFieldOrientation ScXMLConverter::GetOrientationFromString(
175 const OUString& rString )
176 {
177 if( IsXMLToken(rString, XML_COLUMN ) )
178 return sheet::DataPilotFieldOrientation_COLUMN;
179 if( IsXMLToken(rString, XML_ROW ) )
180 return sheet::DataPilotFieldOrientation_ROW;
181 if( IsXMLToken(rString, XML_PAGE ) )
182 return sheet::DataPilotFieldOrientation_PAGE;
183 if( IsXMLToken(rString, XML_DATA ) )
184 return sheet::DataPilotFieldOrientation_DATA;
185 return sheet::DataPilotFieldOrientation_HIDDEN;
186 }
187
188
189 //___________________________________________________________________
190
GetStringFromOrientation(OUString & rString,const sheet::DataPilotFieldOrientation eOrientation,sal_Bool bAppendStr)191 void ScXMLConverter::GetStringFromOrientation(
192 OUString& rString,
193 const sheet::DataPilotFieldOrientation eOrientation,
194 sal_Bool bAppendStr )
195 {
196 OUString sOrientStr;
197 switch( eOrientation )
198 {
199 case sheet::DataPilotFieldOrientation_HIDDEN:
200 sOrientStr = GetXMLToken( XML_HIDDEN );
201 break;
202 case sheet::DataPilotFieldOrientation_COLUMN:
203 sOrientStr = GetXMLToken( XML_COLUMN );
204 break;
205 case sheet::DataPilotFieldOrientation_ROW:
206 sOrientStr = GetXMLToken( XML_ROW );
207 break;
208 case sheet::DataPilotFieldOrientation_PAGE:
209 sOrientStr = GetXMLToken( XML_PAGE );
210 break;
211 case sheet::DataPilotFieldOrientation_DATA:
212 sOrientStr = GetXMLToken( XML_DATA );
213 break;
214 default:
215 {
216 // added to avoid warnings
217 }
218 }
219 ScRangeStringConverter::AssignString( rString, sOrientStr, bAppendStr );
220 }
221
222
223 //___________________________________________________________________
224
GetDetObjTypeFromString(const OUString & rString)225 ScDetectiveObjType ScXMLConverter::GetDetObjTypeFromString( const OUString& rString )
226 {
227 if( IsXMLToken(rString, XML_FROM_SAME_TABLE ) )
228 return SC_DETOBJ_ARROW;
229 if( IsXMLToken(rString, XML_FROM_ANOTHER_TABLE ) )
230 return SC_DETOBJ_FROMOTHERTAB;
231 if( IsXMLToken(rString, XML_TO_ANOTHER_TABLE ) )
232 return SC_DETOBJ_TOOTHERTAB;
233 return SC_DETOBJ_NONE;
234 }
235
GetDetOpTypeFromString(ScDetOpType & rDetOpType,const OUString & rString)236 sal_Bool ScXMLConverter::GetDetOpTypeFromString( ScDetOpType& rDetOpType, const OUString& rString )
237 {
238 if( IsXMLToken(rString, XML_TRACE_DEPENDENTS ) )
239 rDetOpType = SCDETOP_ADDSUCC;
240 else if( IsXMLToken(rString, XML_TRACE_PRECEDENTS ) )
241 rDetOpType = SCDETOP_ADDPRED;
242 else if( IsXMLToken(rString, XML_TRACE_ERRORS ) )
243 rDetOpType = SCDETOP_ADDERROR;
244 else if( IsXMLToken(rString, XML_REMOVE_DEPENDENTS ) )
245 rDetOpType = SCDETOP_DELSUCC;
246 else if( IsXMLToken(rString, XML_REMOVE_PRECEDENTS ) )
247 rDetOpType = SCDETOP_DELPRED;
248 else
249 return sal_False;
250 return sal_True;
251 }
252
253
254 //___________________________________________________________________
255
GetStringFromDetObjType(OUString & rString,const ScDetectiveObjType eObjType,sal_Bool bAppendStr)256 void ScXMLConverter::GetStringFromDetObjType(
257 OUString& rString,
258 const ScDetectiveObjType eObjType,
259 sal_Bool bAppendStr )
260 {
261 OUString sTypeStr;
262 switch( eObjType )
263 {
264 case SC_DETOBJ_ARROW:
265 sTypeStr = GetXMLToken( XML_FROM_SAME_TABLE );
266 break;
267 case SC_DETOBJ_FROMOTHERTAB:
268 sTypeStr = GetXMLToken( XML_FROM_ANOTHER_TABLE );
269 break;
270 case SC_DETOBJ_TOOTHERTAB:
271 sTypeStr = GetXMLToken( XML_TO_ANOTHER_TABLE );
272 break;
273 default:
274 {
275 // added to avoid warnings
276 }
277 }
278 ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
279 }
280
GetStringFromDetOpType(OUString & rString,const ScDetOpType eOpType,sal_Bool bAppendStr)281 void ScXMLConverter::GetStringFromDetOpType(
282 OUString& rString,
283 const ScDetOpType eOpType,
284 sal_Bool bAppendStr )
285 {
286 OUString sTypeStr;
287 switch( eOpType )
288 {
289 case SCDETOP_ADDSUCC:
290 sTypeStr = GetXMLToken( XML_TRACE_DEPENDENTS );
291 break;
292 case SCDETOP_ADDPRED:
293 sTypeStr = GetXMLToken( XML_TRACE_PRECEDENTS );
294 break;
295 case SCDETOP_ADDERROR:
296 sTypeStr = GetXMLToken( XML_TRACE_ERRORS );
297 break;
298 case SCDETOP_DELSUCC:
299 sTypeStr = GetXMLToken( XML_REMOVE_DEPENDENTS );
300 break;
301 case SCDETOP_DELPRED:
302 sTypeStr = GetXMLToken( XML_REMOVE_PRECEDENTS );
303 break;
304 }
305 ScRangeStringConverter::AssignString( rString, sTypeStr, bAppendStr );
306 }
307
308
309 //___________________________________________________________________
310
ParseFormula(OUString & sFormula,const sal_Bool bIsFormula)311 void ScXMLConverter::ParseFormula(OUString& sFormula, const sal_Bool bIsFormula)
312 {
313 OUStringBuffer sBuffer(sFormula.getLength());
314 sal_Bool bInQuotationMarks(sal_False);
315 sal_Bool bInDoubleQuotationMarks(sal_False);
316 sal_Int16 nCountBraces(0);
317 sal_Unicode chPrevious('=');
318 for (sal_Int32 i = 0; i < sFormula.getLength(); ++i)
319 {
320 if (sFormula[i] == '\'' && !bInDoubleQuotationMarks &&
321 chPrevious != '\\')
322 bInQuotationMarks = !bInQuotationMarks;
323 else if (sFormula[i] == '"' && !bInQuotationMarks)
324 bInDoubleQuotationMarks = !bInDoubleQuotationMarks;
325 if (bInQuotationMarks || bInDoubleQuotationMarks)
326 sBuffer.append(sFormula[i]);
327 else if (sFormula[i] == '[')
328 ++nCountBraces;
329 else if (sFormula[i] == ']')
330 nCountBraces--;
331 else if ((sFormula[i] != '.') ||
332 ((nCountBraces == 0) && bIsFormula) ||
333 !((chPrevious == '[') || (chPrevious == ':') || (chPrevious == ' ') || (chPrevious == '=')))
334 sBuffer.append(sFormula[i]);
335 chPrevious = sFormula[i];
336 }
337
338 DBG_ASSERT(nCountBraces == 0, "there are some braces still open");
339 sFormula = sBuffer.makeStringAndClear();
340 }
341
342
343 //_____________________________________________________________________
344
ConvertDateTimeToString(const DateTime & aDateTime,rtl::OUStringBuffer & sDate)345 void ScXMLConverter::ConvertDateTimeToString(const DateTime& aDateTime, rtl::OUStringBuffer& sDate)
346 {
347 util::DateTime aAPIDateTime;
348 ConvertCoreToAPIDateTime(aDateTime, aAPIDateTime);
349 SvXMLUnitConverter::convertDateTime(sDate, aAPIDateTime);
350 }
351
352 //UNUSED2008-05 void ScXMLConverter::ConvertStringToDateTime(const rtl::OUString& sDate, DateTime& aDateTime, SvXMLUnitConverter* /* pUnitConverter */)
353 //UNUSED2008-05 {
354 //UNUSED2008-05 com::sun::star::util::DateTime aAPIDateTime;
355 //UNUSED2008-05 SvXMLUnitConverter::convertDateTime(aAPIDateTime, sDate);
356 //UNUSED2008-05 ConvertAPIToCoreDateTime(aAPIDateTime, aDateTime);
357 //UNUSED2008-05 }
358
ConvertCoreToAPIDateTime(const DateTime & aDateTime,util::DateTime & rDateTime)359 void ScXMLConverter::ConvertCoreToAPIDateTime(const DateTime& aDateTime, util::DateTime& rDateTime)
360 {
361 rDateTime.Year = aDateTime.GetYear();
362 rDateTime.Month = aDateTime.GetMonth();
363 rDateTime.Day = aDateTime.GetDay();
364 rDateTime.Hours = aDateTime.GetHour();
365 rDateTime.Minutes = aDateTime.GetMin();
366 rDateTime.Seconds = aDateTime.GetSec();
367 rDateTime.HundredthSeconds = aDateTime.Get100Sec();
368 }
369
ConvertAPIToCoreDateTime(const util::DateTime & aDateTime,DateTime & rDateTime)370 void ScXMLConverter::ConvertAPIToCoreDateTime(const util::DateTime& aDateTime, DateTime& rDateTime)
371 {
372 Date aDate(aDateTime.Day, aDateTime.Month, aDateTime.Year);
373 Time aTime(aDateTime.Hours, aDateTime.Minutes, aDateTime.Seconds, aDateTime.HundredthSeconds);
374 DateTime aTempDateTime (aDate, aTime);
375 rDateTime = aTempDateTime;
376 }
377
378 // ============================================================================
379
380 namespace {
381
382 /** Enumerates different types of condition tokens. */
383 enum ScXMLConditionTokenType
384 {
385 XML_COND_TYPE_KEYWORD, /// Simple keyword without parentheses, e.g. 'and'.
386 XML_COND_TYPE_COMPARISON, /// Comparison rule, e.g. 'cell-content()<=2'.
387 XML_COND_TYPE_FUNCTION0, /// Function without parameters, e.g. 'cell-content-is-whole-number()'.
388 XML_COND_TYPE_FUNCTION1, /// Function with 1 parameter, e.g. 'is-true-formula(1+1=2)'.
389 XML_COND_TYPE_FUNCTION2 /// Function with 2 parameters, e.g. 'cell-content-is-between(1,2)'.
390 };
391
392 struct ScXMLConditionInfo
393 {
394 ScXMLConditionToken meToken;
395 ScXMLConditionTokenType meType;
396 sheet::ValidationType meValidation;
397 sheet::ConditionOperator meOperator;
398 const sal_Char* mpcIdentifier;
399 sal_Int32 mnIdentLength;
400 };
401
402 static const ScXMLConditionInfo spConditionInfos[] =
403 {
404 { XML_COND_AND, XML_COND_TYPE_KEYWORD, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "and" ) },
405 { XML_COND_CELLCONTENT, XML_COND_TYPE_COMPARISON, sheet::ValidationType_ANY, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content" ) },
406 { XML_COND_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-between" ) },
407 { XML_COND_ISNOTBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_ANY, sheet::ConditionOperator_NOT_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-not-between" ) },
408 { XML_COND_ISWHOLENUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_WHOLE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-whole-number" ) },
409 { XML_COND_ISDECIMALNUMBER, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DECIMAL, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-decimal-number" ) },
410 { XML_COND_ISDATE, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_DATE, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-date" ) },
411 { XML_COND_ISTIME, XML_COND_TYPE_FUNCTION0, sheet::ValidationType_TIME, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-time" ) },
412 { XML_COND_ISINLIST, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_LIST, sheet::ConditionOperator_EQUAL, RTL_CONSTASCII_STRINGPARAM( "cell-content-is-in-list" ) },
413 { XML_COND_TEXTLENGTH, XML_COND_TYPE_COMPARISON, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_NONE, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length" ) },
414 { XML_COND_TEXTLENGTH_ISBETWEEN, XML_COND_TYPE_FUNCTION2, sheet::ValidationType_TEXT_LEN, sheet::ConditionOperator_BETWEEN, RTL_CONSTASCII_STRINGPARAM( "cell-content-text-length-is-between" ) },
415 { 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" ) },
416 { XML_COND_ISTRUEFORMULA, XML_COND_TYPE_FUNCTION1, sheet::ValidationType_CUSTOM, sheet::ConditionOperator_FORMULA, RTL_CONSTASCII_STRINGPARAM( "is-true-formula" ) }
417 };
418
lclSkipWhitespace(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd)419 void lclSkipWhitespace( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
420 {
421 while( (rpcString < pcEnd) && (*rpcString <= ' ') ) ++rpcString;
422 }
423
lclGetConditionInfo(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd)424 const ScXMLConditionInfo* lclGetConditionInfo( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
425 {
426 lclSkipWhitespace( rpcString, pcEnd );
427 /* Search the end of an identifier name; assuming that valid identifiers
428 consist of [a-z-] only. */
429 const sal_Unicode* pcIdStart = rpcString;
430 while( (rpcString < pcEnd) && (((*rpcString >= 'a') && (*rpcString <= 'z')) || (*rpcString == '-')) ) ++rpcString;
431 sal_Int32 nLength = static_cast< sal_Int32 >( rpcString - pcIdStart );
432
433 // search the table for an entry
434 if( nLength > 0 )
435 for( const ScXMLConditionInfo* pInfo = spConditionInfos; pInfo < STATIC_ARRAY_END( spConditionInfos ); ++pInfo )
436 if( (nLength == pInfo->mnIdentLength) && (::rtl_ustr_ascii_shortenedCompare_WithLength( pcIdStart, nLength, pInfo->mpcIdentifier, nLength ) == 0) )
437 return pInfo;
438
439 return 0;
440 }
441
lclGetConditionOperator(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd)442 sheet::ConditionOperator lclGetConditionOperator( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
443 {
444 // check for double-char operators
445 if( (rpcString + 1 < pcEnd) && (rpcString[ 1 ] == '=') )
446 {
447 sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
448 switch( *rpcString )
449 {
450 case '!': eOperator = sheet::ConditionOperator_NOT_EQUAL; break;
451 case '<': eOperator = sheet::ConditionOperator_LESS_EQUAL; break;
452 case '>': eOperator = sheet::ConditionOperator_GREATER_EQUAL; break;
453 }
454 if( eOperator != sheet::ConditionOperator_NONE )
455 {
456 rpcString += 2;
457 return eOperator;
458 }
459 }
460
461 // check for single-char operators
462 if( rpcString < pcEnd )
463 {
464 sheet::ConditionOperator eOperator = sheet::ConditionOperator_NONE;
465 switch( *rpcString )
466 {
467 case '=': eOperator = sheet::ConditionOperator_EQUAL; break;
468 case '<': eOperator = sheet::ConditionOperator_LESS; break;
469 case '>': eOperator = sheet::ConditionOperator_GREATER; break;
470 }
471 if( eOperator != sheet::ConditionOperator_NONE )
472 {
473 ++rpcString;
474 return eOperator;
475 }
476 }
477
478 return sheet::ConditionOperator_NONE;
479 }
480
481 /** Skips a literal string in a formula expression.
482
483 @param rpcString
484 (in-out) On call, must point to the first character of the string
485 following the leading string delimiter character. On return, points to
486 the trailing string delimiter character if existing, otherwise to
487 pcEnd.
488
489 @param pcEnd
490 The end of the string to parse.
491
492 @param cQuoteChar
493 The string delimiter character enclosing the string.
494 */
lclSkipExpressionString(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd,sal_Unicode cQuoteChar)495 void lclSkipExpressionString( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cQuoteChar )
496 {
497 if( rpcString < pcEnd )
498 {
499 sal_Int32 nLength = static_cast< sal_Int32 >( pcEnd - rpcString );
500 sal_Int32 nNextQuote = ::rtl_ustr_indexOfChar_WithLength( rpcString, nLength, cQuoteChar );
501 if( nNextQuote >= 0 )
502 rpcString += nNextQuote;
503 else
504 rpcString = pcEnd;
505 }
506 }
507
508 /** Skips a formula expression. Processes embedded parentheses, braces, and
509 literal strings.
510
511 @param rpcString
512 (in-out) On call, must point to the first character of the expression.
513 On return, points to the passed end character if existing, otherwise to
514 pcEnd.
515
516 @param pcEnd
517 The end of the string to parse.
518
519 @param cEndChar
520 The termination character following the expression.
521 */
lclSkipExpression(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd,sal_Unicode cEndChar)522 void lclSkipExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
523 {
524 while( rpcString < pcEnd )
525 {
526 if( *rpcString == cEndChar )
527 return;
528 switch( *rpcString )
529 {
530 case '(': lclSkipExpression( ++rpcString, pcEnd, ')' ); break;
531 case '{': lclSkipExpression( ++rpcString, pcEnd, '}' ); break;
532 case '"': lclSkipExpressionString( ++rpcString, pcEnd, '"' ); break;
533 case '\'': lclSkipExpressionString( ++rpcString, pcEnd, '\'' ); break;
534 }
535 if( rpcString < pcEnd ) ++rpcString;
536 }
537 }
538
539 /** Extracts a formula expression. Processes embedded parentheses, braces, and
540 literal strings.
541
542 @param rpcString
543 (in-out) On call, must point to the first character of the expression.
544 On return, points *behind* the passed end character if existing,
545 otherwise to pcEnd.
546
547 @param pcEnd
548 The end of the string to parse.
549
550 @param cEndChar
551 The termination character following the expression.
552 */
lclGetExpression(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd,sal_Unicode cEndChar)553 OUString lclGetExpression( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd, sal_Unicode cEndChar )
554 {
555 OUString aExp;
556 const sal_Unicode* pcExpStart = rpcString;
557 lclSkipExpression( rpcString, pcEnd, cEndChar );
558 if( rpcString < pcEnd )
559 {
560 aExp = OUString( pcExpStart, static_cast< sal_Int32 >( rpcString - pcExpStart ) ).trim();
561 ++rpcString;
562 }
563 return aExp;
564 }
565
566 /** Tries to skip an empty pair of parentheses (which may contain whitespace
567 characters).
568
569 @return
570 True on success, rpcString points behind the closing parentheses then.
571 */
lclSkipEmptyParentheses(const sal_Unicode * & rpcString,const sal_Unicode * pcEnd)572 bool lclSkipEmptyParentheses( const sal_Unicode*& rpcString, const sal_Unicode* pcEnd )
573 {
574 if( (rpcString < pcEnd) && (*rpcString == '(') )
575 {
576 lclSkipWhitespace( ++rpcString, pcEnd );
577 if( (rpcString < pcEnd) && (*rpcString == ')') )
578 {
579 ++rpcString;
580 return true;
581 }
582 }
583 return false;
584 }
585
586 } // namespace
587
588 // ----------------------------------------------------------------------------
589
parseCondition(ScXMLConditionParseResult & rParseResult,const OUString & rAttribute,sal_Int32 nStartIndex)590 /*static*/ void ScXMLConditionHelper::parseCondition(
591 ScXMLConditionParseResult& rParseResult, const OUString& rAttribute, sal_Int32 nStartIndex )
592 {
593 rParseResult.meToken = XML_COND_INVALID;
594 if( (nStartIndex < 0) || (nStartIndex >= rAttribute.getLength()) ) return;
595
596 // try to find an identifier
597 const sal_Unicode* pcBegin = rAttribute.getStr();
598 const sal_Unicode* pcString = pcBegin + nStartIndex;
599 const sal_Unicode* pcEnd = pcBegin + rAttribute.getLength();
600 if( const ScXMLConditionInfo* pCondInfo = lclGetConditionInfo( pcString, pcEnd ) )
601 {
602 // insert default values into parse result (may be changed below)
603 rParseResult.meValidation = pCondInfo->meValidation;
604 rParseResult.meOperator = pCondInfo->meOperator;
605 // continue parsing dependent on token type
606 switch( pCondInfo->meType )
607 {
608 case XML_COND_TYPE_KEYWORD:
609 // nothing specific has to follow, success
610 rParseResult.meToken = pCondInfo->meToken;
611 break;
612
613 case XML_COND_TYPE_COMPARISON:
614 // format is <condition>()<operator><expression>
615 if( lclSkipEmptyParentheses( pcString, pcEnd ) )
616 {
617 rParseResult.meOperator = lclGetConditionOperator( pcString, pcEnd );
618 if( rParseResult.meOperator != sheet::ConditionOperator_NONE )
619 {
620 lclSkipWhitespace( pcString, pcEnd );
621 if( pcString < pcEnd )
622 {
623 rParseResult.meToken = pCondInfo->meToken;
624 // comparison must be at end of attribute, remaining text is the formula
625 rParseResult.maOperand1 = OUString( pcString, static_cast< sal_Int32 >( pcEnd - pcString ) );
626 }
627 }
628 }
629 break;
630
631 case XML_COND_TYPE_FUNCTION0:
632 // format is <condition>()
633 if( lclSkipEmptyParentheses( pcString, pcEnd ) )
634 rParseResult.meToken = pCondInfo->meToken;
635 break;
636
637 case XML_COND_TYPE_FUNCTION1:
638 // format is <condition>(<expression>)
639 if( (pcString < pcEnd) && (*pcString == '(') )
640 {
641 rParseResult.maOperand1 = lclGetExpression( ++pcString, pcEnd, ')' );
642 if( rParseResult.maOperand1.getLength() > 0 )
643 rParseResult.meToken = pCondInfo->meToken;
644 }
645 break;
646
647 case XML_COND_TYPE_FUNCTION2:
648 // format is <condition>(<expression1>,<expression2>)
649 if( (pcString < pcEnd) && (*pcString == '(') )
650 {
651 rParseResult.maOperand1 = lclGetExpression( ++pcString, pcEnd, ',' );
652 if( rParseResult.maOperand1.getLength() > 0 )
653 {
654 rParseResult.maOperand2 = lclGetExpression( pcString, pcEnd, ')' );
655 if( rParseResult.maOperand2.getLength() > 0 )
656 rParseResult.meToken = pCondInfo->meToken;
657 }
658 }
659 break;
660 }
661 rParseResult.mnEndIndex = static_cast< sal_Int32 >( pcString - pcBegin );
662 }
663 }
664
665 // ============================================================================
666
667