Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include <ctype.h>
21 : #include <cstdlib>
22 : #include <float.h>
23 : #include <errno.h>
24 : #include <comphelper/string.hxx>
25 : #include <sal/log.hxx>
26 : #include <tools/date.hxx>
27 : #include <rtl/math.hxx>
28 : #include <unotools/charclass.hxx>
29 : #include <unotools/calendarwrapper.hxx>
30 : #include <unotools/localedatawrapper.hxx>
31 : #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
32 : #include <com/sun/star/i18n/LocaleCalendar2.hpp>
33 : #include <unotools/digitgroupingiterator.hxx>
34 :
35 : #include <svl/zforlist.hxx>
36 : #include "zforscan.hxx"
37 : #include <svl/zformat.hxx>
38 :
39 : #include "zforfind.hxx"
40 :
41 : #ifndef DBG_UTIL
42 : #define NF_TEST_CALENDAR 0
43 : #else
44 : #define NF_TEST_CALENDAR 0
45 : #endif
46 : #if NF_TEST_CALENDAR
47 : #include <comphelper/processfactory.hxx>
48 : #include <com/sun/star/i18n/XCalendar4.hpp>
49 : #endif
50 :
51 :
52 : const sal_uInt8 ImpSvNumberInputScan::nMatchedEndString = 0x01;
53 : const sal_uInt8 ImpSvNumberInputScan::nMatchedMidString = 0x02;
54 : const sal_uInt8 ImpSvNumberInputScan::nMatchedStartString = 0x04;
55 : const sal_uInt8 ImpSvNumberInputScan::nMatchedVirgin = 0x08;
56 : const sal_uInt8 ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10;
57 :
58 : /* It is not clear how we want timezones to be handled. Convert them to local
59 : * time isn't wanted, as it isn't done in any other place and timezone
60 : * information isn't stored anywhere. Ignoring them and pretending local time
61 : * may be wrong too and might not be what the user expects. Keep the input as
62 : * string so that no information is lost.
63 : * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it
64 : * would work, together with the nTimezonePos handling in GetTimeRef(). */
65 : #define NF_RECOGNIZE_ISO8601_TIMEZONES 0
66 :
67 : static const sal_Unicode cNoBreakSpace = 0xA0;
68 : static const sal_Unicode cNarrowNoBreakSpace = 0x202F;
69 :
70 4232 : ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP )
71 : :
72 : pUpperMonthText( NULL ),
73 : pUpperAbbrevMonthText( NULL ),
74 : pUpperGenitiveMonthText( NULL ),
75 : pUpperGenitiveAbbrevMonthText( NULL ),
76 : pUpperPartitiveMonthText( NULL ),
77 : pUpperPartitiveAbbrevMonthText( NULL ),
78 : pUpperDayText( NULL ),
79 : pUpperAbbrevDayText( NULL ),
80 : bTextInitialized( false ),
81 : bScanGenitiveMonths( false ),
82 : bScanPartitiveMonths( false ),
83 : eScannedType( css::util::NumberFormat::UNDEFINED ),
84 4232 : eSetType( css::util::NumberFormat::UNDEFINED )
85 : {
86 4232 : pFormatter = pFormatterP;
87 4232 : pNullDate = new Date(30,12,1899);
88 4232 : nYear2000 = SvNumberFormatter::GetYear2000Default();
89 4232 : Reset();
90 4232 : ChangeIntl();
91 4232 : }
92 :
93 :
94 8392 : ImpSvNumberInputScan::~ImpSvNumberInputScan()
95 : {
96 4196 : Reset();
97 4196 : delete pNullDate;
98 4196 : delete [] pUpperMonthText;
99 4196 : delete [] pUpperAbbrevMonthText;
100 4196 : delete [] pUpperGenitiveMonthText;
101 4196 : delete [] pUpperGenitiveAbbrevMonthText;
102 4196 : delete [] pUpperPartitiveMonthText;
103 4196 : delete [] pUpperPartitiveAbbrevMonthText;
104 4196 : delete [] pUpperDayText;
105 4196 : delete [] pUpperAbbrevDayText;
106 4196 : }
107 :
108 :
109 19767 : void ImpSvNumberInputScan::Reset()
110 : {
111 19767 : nMonth = 0;
112 19767 : nMonthPos = 0;
113 19767 : nTimePos = 0;
114 19767 : nSign = 0;
115 19767 : nESign = 0;
116 19767 : nDecPos = 0;
117 19767 : nNegCheck = 0;
118 19767 : nAnzStrings = 0;
119 19767 : nAnzNums = 0;
120 19767 : nThousand = 0;
121 19767 : eScannedType = css::util::NumberFormat::UNDEFINED;
122 19767 : nAmPm = 0;
123 19767 : nPosThousandString = 0;
124 19767 : nLogical = 0;
125 19767 : nStringScanNumFor = 0;
126 19767 : nStringScanSign = 0;
127 19767 : nMatchedAllStrings = nMatchedVirgin;
128 19767 : nMayBeIso8601 = 0;
129 19767 : nTimezonePos = 0;
130 19767 : nMayBeMonthDate = 0;
131 19767 : nAcceptedDatePattern = -2;
132 19767 : nDatePatternStart = 0;
133 19767 : nDatePatternNumbers = 0;
134 19767 : nCanForceToIso8601 = 0;
135 :
136 415107 : for (sal_uInt32 i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++)
137 : {
138 395340 : IsNum[i] = false;
139 395340 : nNums[i] = 0;
140 : }
141 19767 : }
142 :
143 :
144 : // static
145 78558 : inline bool ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
146 : {
147 78558 : return c < 128 && isdigit( (unsigned char) c );
148 : }
149 :
150 : // native number transliteration if necessary
151 11339 : void TransformInput( SvNumberFormatter* pFormatter, OUString& rStr )
152 : {
153 : sal_Int32 nPos, nLen;
154 82090 : for ( nPos = 0, nLen = rStr.getLength(); nPos < nLen; ++nPos )
155 : {
156 71088 : if ( 256 <= rStr[ nPos ] &&
157 337 : pFormatter->GetCharClass()->isDigit( rStr, nPos ) )
158 : {
159 0 : break;
160 : }
161 : }
162 11339 : if ( nPos < nLen )
163 : {
164 0 : rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr,
165 0 : pFormatter->GetLanguageTag().getLocale(), 0 );
166 : }
167 11339 : }
168 :
169 :
170 : /**
171 : * Only simple unsigned floating point values without any error detection,
172 : * decimal separator has to be '.'
173 : */
174 4560 : double ImpSvNumberInputScan::StringToDouble( const OUString& rStr, bool bForceFraction )
175 : {
176 4560 : double fNum = 0.0;
177 4560 : double fFrac = 0.0;
178 4560 : int nExp = 0;
179 4560 : sal_Int32 nPos = 0;
180 4560 : sal_Int32 nLen = rStr.getLength();
181 4560 : bool bPreSep = !bForceFraction;
182 :
183 17700 : while (nPos < nLen)
184 : {
185 8580 : if (rStr[nPos] == '.')
186 : {
187 557 : bPreSep = false;
188 : }
189 8023 : else if (bPreSep)
190 : {
191 6884 : fNum = fNum * 10.0 + (double) (rStr[nPos] - '0');
192 : }
193 : else
194 : {
195 1139 : fFrac = fFrac * 10.0 + (double) (rStr[nPos] - '0');
196 1139 : --nExp;
197 : }
198 8580 : nPos++;
199 : }
200 4560 : if ( fFrac )
201 : {
202 481 : return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
203 : }
204 4079 : return fNum;
205 : }
206 :
207 :
208 : /**
209 : * Splits up the input into numbers and strings for further processing
210 : * (by the Turing machine).
211 : *
212 : * Starting state = GetChar
213 : * ---------------+-------------------+-----------------------------+---------------
214 : * Old State | Character read | Event | New state
215 : * ---------------+-------------------+-----------------------------+---------------
216 : * GetChar | Number | Symbol = Character | GetValue
217 : * | Else | Symbol = Character | GetString
218 : * ---------------|-------------------+-----------------------------+---------------
219 : * GetValue | Number | Symbol = Symbol + Character | GetValue
220 : * | Else | Dec(CharPos) | Stop
221 : * ---------------+-------------------+-----------------------------+---------------
222 : * GetString | Number | Dec(CharPos) | Stop
223 : * | Else | Symbol = Symbol + Character | GetString
224 : * ---------------+-------------------+-----------------------------+---------------
225 : */
226 : enum ScanState // States of the Turing machine
227 : {
228 : SsStop = 0,
229 : SsStart = 1,
230 : SsGetValue = 2,
231 : SsGetString = 3
232 : };
233 :
234 19146 : bool ImpSvNumberInputScan::NextNumberStringSymbol( const sal_Unicode*& pStr,
235 : OUString& rSymbol )
236 : {
237 19146 : bool isNumber = false;
238 : sal_Unicode cToken;
239 19146 : ScanState eState = SsStart;
240 19146 : const sal_Unicode* pHere = pStr;
241 19146 : sal_Int32 nChars = 0;
242 :
243 116850 : while ( ((cToken = *pHere) != 0) && eState != SsStop)
244 : {
245 78558 : pHere++;
246 78558 : switch (eState)
247 : {
248 : case SsStart:
249 19146 : if ( MyIsdigit( cToken ) )
250 : {
251 10057 : eState = SsGetValue;
252 10057 : isNumber = true;
253 : }
254 : else
255 : {
256 9089 : eState = SsGetString;
257 : }
258 19146 : nChars++;
259 19146 : break;
260 : case SsGetValue:
261 12120 : if ( MyIsdigit( cToken ) )
262 : {
263 8644 : nChars++;
264 : }
265 : else
266 : {
267 3476 : eState = SsStop;
268 3476 : pHere--;
269 : }
270 12120 : break;
271 : case SsGetString:
272 47292 : if ( !MyIsdigit( cToken ) )
273 : {
274 42961 : nChars++;
275 : }
276 : else
277 : {
278 4331 : eState = SsStop;
279 4331 : pHere--;
280 : }
281 47292 : break;
282 : default:
283 0 : break;
284 : } // switch
285 : } // while
286 :
287 19146 : if ( nChars )
288 : {
289 19146 : rSymbol = OUString( pStr, nChars );
290 : }
291 : else
292 : {
293 0 : rSymbol.clear();
294 : }
295 :
296 19146 : pStr = pHere;
297 :
298 19146 : return isNumber;
299 : }
300 :
301 :
302 : // FIXME: should be grouping; it is only used though in case nAnzStrings is
303 : // near SV_MAX_ANZ_INPUT_STRINGS, in NumberStringDivision().
304 :
305 3 : bool ImpSvNumberInputScan::SkipThousands( const sal_Unicode*& pStr,
306 : OUString& rSymbol )
307 : {
308 3 : bool res = false;
309 3 : OUStringBuffer sBuff(rSymbol);
310 : sal_Unicode cToken;
311 3 : const OUString& rThSep = pFormatter->GetNumThousandSep();
312 3 : const sal_Unicode* pHere = pStr;
313 3 : ScanState eState = SsStart;
314 3 : sal_Int32 nCounter = 0; // counts 3 digits
315 :
316 6 : while ( ((cToken = *pHere) != 0) && eState != SsStop)
317 : {
318 0 : pHere++;
319 0 : switch (eState)
320 : {
321 : case SsStart:
322 0 : if ( StringPtrContains( rThSep, pHere-1, 0 ) )
323 : {
324 0 : nCounter = 0;
325 0 : eState = SsGetValue;
326 0 : pHere += rThSep.getLength() - 1;
327 : }
328 : else
329 : {
330 0 : eState = SsStop;
331 0 : pHere--;
332 : }
333 0 : break;
334 : case SsGetValue:
335 0 : if ( MyIsdigit( cToken ) )
336 : {
337 0 : sBuff.append(cToken);
338 0 : nCounter++;
339 0 : if (nCounter == 3)
340 : {
341 0 : eState = SsStart;
342 0 : res = true; // .000 combination found
343 : }
344 : }
345 : else
346 : {
347 0 : eState = SsStop;
348 0 : pHere--;
349 : }
350 0 : break;
351 : default:
352 0 : break;
353 : } // switch
354 : } // while
355 :
356 3 : if (eState == SsGetValue) // break witth less than 3 digits
357 : {
358 0 : if ( nCounter )
359 : {
360 0 : sBuff.remove( sBuff.getLength() - nCounter, nCounter );
361 : }
362 0 : pHere -= nCounter + rThSep.getLength(); // put back ThSep also
363 : }
364 3 : rSymbol = sBuff.makeStringAndClear();
365 3 : pStr = pHere;
366 :
367 3 : return res;
368 : }
369 :
370 :
371 11339 : void ImpSvNumberInputScan::NumberStringDivision( const OUString& rString )
372 : {
373 11339 : const sal_Unicode* pStr = rString.getStr();
374 11339 : const sal_Unicode* const pEnd = pStr + rString.getLength();
375 41824 : while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS )
376 : {
377 19146 : if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) )
378 : { // Number
379 10057 : IsNum[nAnzStrings] = true;
380 10057 : nNums[nAnzNums] = nAnzStrings;
381 10057 : nAnzNums++;
382 10060 : if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 &&
383 3 : nPosThousandString == 0) // Only once
384 : {
385 3 : if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) )
386 : {
387 0 : nPosThousandString = nAnzStrings;
388 : }
389 : }
390 : }
391 : else
392 : {
393 9089 : IsNum[nAnzStrings] = false;
394 : }
395 19146 : nAnzStrings++;
396 : }
397 11339 : }
398 :
399 :
400 : /**
401 : * Whether rString contains rWhat at nPos
402 : */
403 617 : bool ImpSvNumberInputScan::StringContainsImpl( const OUString& rWhat,
404 : const OUString& rString, sal_Int32 nPos )
405 : {
406 617 : if ( nPos + rWhat.getLength() <= rString.getLength() )
407 : {
408 613 : return StringPtrContainsImpl( rWhat, rString.getStr(), nPos );
409 : }
410 4 : return false;
411 : }
412 :
413 :
414 : /**
415 : * Whether pString contains rWhat at nPos
416 : */
417 30079 : bool ImpSvNumberInputScan::StringPtrContainsImpl( const OUString& rWhat,
418 : const sal_Unicode* pString, sal_Int32 nPos )
419 : {
420 30079 : if ( rWhat.isEmpty() )
421 : {
422 0 : return false;
423 : }
424 30079 : const sal_Unicode* pWhat = rWhat.getStr();
425 30079 : const sal_Unicode* const pEnd = pWhat + rWhat.getLength();
426 30079 : const sal_Unicode* pStr = pString + nPos;
427 63356 : while ( pWhat < pEnd )
428 : {
429 32214 : if ( *pWhat != *pStr )
430 : {
431 29016 : return false;
432 : }
433 3198 : pWhat++;
434 3198 : pStr++;
435 : }
436 1063 : return true;
437 : }
438 :
439 :
440 : /**
441 : * Whether rString contains word rWhat at nPos
442 : */
443 82950 : bool ImpSvNumberInputScan::StringContainsWord( const OUString& rWhat,
444 : const OUString& rString, sal_Int32 nPos )
445 : {
446 82950 : if (rWhat.isEmpty() || rString.getLength() < nPos + rWhat.getLength())
447 53484 : return false;
448 :
449 29466 : if (StringPtrContainsImpl( rWhat, rString.getStr(), nPos))
450 : {
451 451 : nPos += rWhat.getLength();
452 451 : if (nPos == rString.getLength())
453 2 : return true; // word at end of string
454 :
455 : /* TODO: we COULD invoke bells and whistles word break iterator to find
456 : * the next boundary, but really ... this is called for date input, so
457 : * how many languages do not separate the day and month names in some
458 : * form? */
459 :
460 : // Check simple ASCII first before invoking i18n or anything else.
461 449 : const sal_Unicode c = rString[nPos];
462 :
463 : // Common separating ASCII characters in date context.
464 449 : switch (c)
465 : {
466 : case ' ':
467 : case '-':
468 : case '.':
469 : case '/':
470 449 : return true;
471 : default:
472 : ; // nothing
473 : }
474 :
475 0 : if (rtl::isAsciiAlphanumeric( c ))
476 0 : return false; // Alpha or numeric is not word gap.
477 :
478 0 : sal_Int32 nIndex = nPos;
479 0 : const sal_uInt32 uc = rString.iterateCodePoints( &nIndex);
480 0 : if (nPos+1 < nIndex)
481 0 : return true; // Surrogate, assume these to be new words.
482 : (void)uc;
483 :
484 0 : const sal_Int32 nType = pFormatter->GetCharClass()->getCharacterType( rString, nPos);
485 : using namespace ::com::sun::star::i18n;
486 :
487 0 : if ((nType & (KCharacterType::UPPER | KCharacterType::LOWER | KCharacterType::DIGIT)) != 0)
488 0 : return false; // Alpha or numeric is not word gap.
489 :
490 0 : if ((nType & (KCharacterType::LETTER)) != 0)
491 0 : return true; // Letter other than alpha is new word. (Is it?)
492 :
493 0 : return true; // Catch all remaining as gap until we know better.
494 : }
495 :
496 29015 : return false;
497 : }
498 :
499 :
500 : /**
501 : * Skips the supplied char
502 : */
503 12471 : inline bool ImpSvNumberInputScan::SkipChar( sal_Unicode c, const OUString& rString,
504 : sal_Int32& nPos )
505 : {
506 12471 : if ((nPos < rString.getLength()) && (rString[nPos] == c))
507 : {
508 1304 : nPos++;
509 1304 : return true;
510 : }
511 11167 : return false;
512 : }
513 :
514 :
515 : /**
516 : * Skips blanks
517 : */
518 10020 : inline void ImpSvNumberInputScan::SkipBlanks( const OUString& rString,
519 : sal_Int32& nPos )
520 : {
521 10020 : if ( nPos < rString.getLength() )
522 : {
523 7013 : const sal_Unicode* p = rString.getStr() + nPos;
524 15037 : while ( *p == ' ' || *p == cNoBreakSpace || *p == cNarrowNoBreakSpace )
525 : {
526 1011 : nPos++;
527 1011 : p++;
528 : }
529 : }
530 10020 : }
531 :
532 :
533 : /**
534 : * jump over rWhat in rString at nPos
535 : */
536 6266 : inline bool ImpSvNumberInputScan::SkipString( const OUString& rWhat,
537 : const OUString& rString, sal_Int32& nPos )
538 : {
539 6266 : if ( StringContains( rWhat, rString, nPos ) )
540 : {
541 508 : nPos = nPos + rWhat.getLength();
542 508 : return true;
543 : }
544 5758 : return false;
545 : }
546 :
547 :
548 : /**
549 : * Recognizes exactly ,111 in {3} and {3,2} or ,11 in {3,2} grouping
550 : */
551 2418 : inline bool ImpSvNumberInputScan::GetThousandSep( const OUString& rString,
552 : sal_Int32& nPos,
553 : sal_uInt16 nStringPos )
554 : {
555 2418 : const OUString& rSep = pFormatter->GetNumThousandSep();
556 : // Is it an ordinary space instead of a no-break space?
557 4836 : bool bSpaceBreak = (rSep[0] == cNoBreakSpace || rSep[0] == cNarrowNoBreakSpace) &&
558 0 : rString[0] == (sal_Unicode)0x20 &&
559 2418 : rSep.getLength() == 1 && rString.getLength() == 1;
560 7254 : if (!((rString == rSep || bSpaceBreak) && // nothing else
561 3 : nStringPos < nAnzStrings - 1 && // safety first!
562 2421 : IsNum[ nStringPos + 1 ] )) // number follows
563 : {
564 2415 : return false; // no? => out
565 : }
566 :
567 3 : utl::DigitGroupingIterator aGrouping( pFormatter->GetLocaleData()->getDigitGrouping());
568 : // Match ,### in {3} or ,## in {3,2}
569 : /* FIXME: this could be refined to match ,## in {3,2} only if ,##,## or
570 : * ,##,### and to match ,### in {3,2} only if it's the last. However,
571 : * currently there is no track kept where group separators occur. In {3,2}
572 : * #,###,### and #,##,## would be valid input, which maybe isn't even bad
573 : * for #,###,###. Other combinations such as #,###,## maybe not. */
574 3 : sal_Int32 nLen = sStrArray[ nStringPos + 1 ].getLength();
575 6 : if (nLen == aGrouping.get() || // with 3 (or so) digits
576 3 : nLen == aGrouping.advance().get() || // or with 2 (or 3 or so) digits
577 0 : nPosThousandString == nStringPos + 1 ) // or concatenated
578 : {
579 3 : nPos = nPos + rSep.getLength();
580 3 : return true;
581 : }
582 0 : return false;
583 : }
584 :
585 :
586 : /**
587 : * Conversion of text to logical value
588 : * "true" => 1:
589 : * "false"=> -1:
590 : * else => 0:
591 : */
592 4000 : short ImpSvNumberInputScan::GetLogical( const OUString& rString )
593 : {
594 : short res;
595 :
596 4000 : const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner();
597 4000 : if ( rString == pFS->GetTrueString() )
598 : {
599 0 : res = 1;
600 : }
601 4000 : else if ( rString == pFS->GetFalseString() )
602 : {
603 0 : res = -1;
604 : }
605 : else
606 : {
607 4000 : res = 0;
608 : }
609 4000 : return res;
610 : }
611 :
612 :
613 : /**
614 : * Converts a string containing a month name (JAN, January) at nPos into the
615 : * month number (negative if abbreviated), returns 0 if nothing found
616 : */
617 5770 : short ImpSvNumberInputScan::GetMonth( const OUString& rString, sal_Int32& nPos )
618 : {
619 : // #102136# The correct English form of month September abbreviated is
620 : // SEPT, but almost every data contains SEP instead.
621 : static const char aSeptCorrect[] = "SEPT";
622 : static const char aSepShortened[] = "SEP";
623 :
624 5770 : short res = 0; // no month found
625 :
626 5770 : if (rString.getLength() > nPos) // only if needed
627 : {
628 2584 : if ( !bTextInitialized )
629 : {
630 561 : InitText();
631 : }
632 2584 : sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
633 29873 : for ( sal_Int16 i = 0; i < nMonths; i++ )
634 : {
635 27740 : if ( bScanGenitiveMonths && StringContainsWord( pUpperGenitiveMonthText[i], rString, nPos ) )
636 : { // genitive full names first
637 0 : nPos = nPos + pUpperGenitiveMonthText[i].getLength();
638 0 : res = i + 1;
639 0 : break; // for
640 : }
641 27740 : else if ( bScanGenitiveMonths && StringContainsWord( pUpperGenitiveAbbrevMonthText[i], rString, nPos ) )
642 : { // genitive abbreviated
643 0 : nPos = nPos + pUpperGenitiveAbbrevMonthText[i].getLength();
644 0 : res = sal::static_int_cast< short >(-(i+1)); // negative
645 0 : break; // for
646 : }
647 27740 : else if ( bScanPartitiveMonths && StringContainsWord( pUpperPartitiveMonthText[i], rString, nPos ) )
648 : { // partitive full names
649 0 : nPos = nPos + pUpperPartitiveMonthText[i].getLength();
650 0 : res = i+1;
651 0 : break; // for
652 : }
653 27740 : else if ( bScanPartitiveMonths && StringContainsWord( pUpperPartitiveAbbrevMonthText[i], rString, nPos ) )
654 : { // partitive abbreviated
655 0 : nPos = nPos + pUpperPartitiveAbbrevMonthText[i].getLength();
656 0 : res = sal::static_int_cast< short >(-(i+1)); // negative
657 0 : break; // for
658 : }
659 27740 : else if ( StringContainsWord( pUpperMonthText[i], rString, nPos ) )
660 : { // noun full names
661 222 : nPos = nPos + pUpperMonthText[i].getLength();
662 222 : res = i+1;
663 222 : break; // for
664 : }
665 27518 : else if ( StringContainsWord( pUpperAbbrevMonthText[i], rString, nPos ) )
666 : { // noun abbreviated
667 229 : nPos = nPos + pUpperAbbrevMonthText[i].getLength();
668 229 : res = sal::static_int_cast< short >(-(i+1)); // negative
669 229 : break; // for
670 : }
671 81867 : else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect &&
672 27289 : StringContainsWord( aSepShortened, rString, nPos ) )
673 : { // #102136# SEPT/SEP
674 0 : nPos = nPos + strlen(aSepShortened);
675 0 : res = sal::static_int_cast< short >(-(i+1)); // negative
676 0 : break; // for
677 : }
678 : }
679 : }
680 :
681 5770 : return res;
682 : }
683 :
684 :
685 : /**
686 : * Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the
687 : * DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found
688 : */
689 1988 : int ImpSvNumberInputScan::GetDayOfWeek( const OUString& rString, sal_Int32& nPos )
690 : {
691 1988 : int res = 0; // no day found
692 :
693 1988 : if (rString.getLength() > nPos) // only if needed
694 : {
695 1978 : if ( !bTextInitialized )
696 : {
697 0 : InitText();
698 : }
699 1978 : sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek();
700 15824 : for ( sal_Int16 i = 0; i < nDays; i++ )
701 : {
702 13846 : if ( StringContainsWord( pUpperDayText[i], rString, nPos ) )
703 : { // full names first
704 0 : nPos = nPos + pUpperDayText[i].getLength();
705 0 : res = i + 1;
706 0 : break; // for
707 : }
708 13846 : if ( StringContainsWord( pUpperAbbrevDayText[i], rString, nPos ) )
709 : { // abbreviated
710 0 : nPos = nPos + pUpperAbbrevDayText[i].getLength();
711 0 : res = -(i + 1); // negative
712 0 : break; // for
713 : }
714 : }
715 : }
716 :
717 1988 : return res;
718 : }
719 :
720 :
721 : /**
722 : * Reading a currency symbol
723 : * '$' => true
724 : * else => false
725 : */
726 2112 : bool ImpSvNumberInputScan::GetCurrency( const OUString& rString, sal_Int32& nPos,
727 : const SvNumberformat* pFormat )
728 : {
729 2112 : if ( rString.getLength() > nPos )
730 : {
731 2100 : if ( !aUpperCurrSymbol.getLength() )
732 : { // if no format specified the currency of the initialized formatter
733 593 : LanguageType eLang = (pFormat ? pFormat->GetLanguage() : pFormatter->GetLanguage());
734 1186 : aUpperCurrSymbol = pFormatter->GetCharClass()->uppercase(
735 1186 : SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() );
736 : }
737 2100 : if ( StringContains( aUpperCurrSymbol, rString, nPos ) )
738 : {
739 58 : nPos = nPos + aUpperCurrSymbol.getLength();
740 58 : return true;
741 : }
742 2042 : if ( pFormat )
743 : {
744 4084 : OUString aSymbol, aExtension;
745 2042 : if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
746 : {
747 0 : if ( aSymbol.getLength() <= rString.getLength() - nPos )
748 : {
749 0 : aSymbol = pFormatter->GetCharClass()->uppercase(aSymbol);
750 0 : if ( StringContains( aSymbol, rString, nPos ) )
751 : {
752 0 : nPos = nPos + aSymbol.getLength();
753 0 : return true;
754 : }
755 : }
756 2042 : }
757 : }
758 : }
759 :
760 2054 : return false;
761 : }
762 :
763 :
764 : /**
765 : * Reading the time period specifier (AM/PM) for the 12 hour clock
766 : *
767 : * Returns:
768 : * "AM" or "PM" => true
769 : * else => false
770 : *
771 : * nAmPos:
772 : * "AM" => 1
773 : * "PM" => -1
774 : * else => 0
775 : */
776 499 : bool ImpSvNumberInputScan::GetTimeAmPm( const OUString& rString, sal_Int32& nPos )
777 : {
778 :
779 499 : if ( rString.getLength() > nPos )
780 : {
781 497 : const CharClass* pChr = pFormatter->GetCharClass();
782 497 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
783 497 : if ( StringContains( pChr->uppercase( pLoc->getTimeAM() ), rString, nPos ) )
784 : {
785 20 : nAmPm = 1;
786 20 : nPos = nPos + pLoc->getTimeAM().getLength();
787 20 : return true;
788 : }
789 477 : else if ( StringContains( pChr->uppercase( pLoc->getTimePM() ), rString, nPos ) )
790 : {
791 26 : nAmPm = -1;
792 26 : nPos = nPos + pLoc->getTimePM().getLength();
793 26 : return true;
794 : }
795 : }
796 :
797 453 : return false;
798 : }
799 :
800 :
801 : /**
802 : * Read a decimal separator (',')
803 : * ',' => true
804 : * else => false
805 : */
806 4595 : inline bool ImpSvNumberInputScan::GetDecSep( const OUString& rString, sal_Int32& nPos )
807 : {
808 4595 : if ( rString.getLength() > nPos )
809 : {
810 4562 : const OUString& rSep = pFormatter->GetNumDecimalSep();
811 4562 : if ( rString.match( rSep, nPos) )
812 : {
813 571 : nPos = nPos + rSep.getLength();
814 571 : return true;
815 : }
816 : }
817 4024 : return false;
818 : }
819 :
820 :
821 : /**
822 : * Reading a hundredth seconds separator
823 : */
824 8 : inline bool ImpSvNumberInputScan::GetTime100SecSep( const OUString& rString, sal_Int32& nPos )
825 : {
826 8 : if ( rString.getLength() > nPos )
827 : {
828 8 : const OUString& rSep = pFormatter->GetLocaleData()->getTime100SecSep();
829 8 : if ( rString.match( rSep, nPos ))
830 : {
831 0 : nPos = nPos + rSep.getLength();
832 0 : return true;
833 : }
834 : }
835 8 : return false;
836 : }
837 :
838 :
839 : /**
840 : * Read a sign including brackets
841 : * '+' => 1
842 : * '-' => -1
843 : * '(' => -1, nNegCheck = 1
844 : * else => 0
845 : */
846 1728 : int ImpSvNumberInputScan::GetSign( const OUString& rString, sal_Int32& nPos )
847 : {
848 1728 : if (rString.getLength() > nPos)
849 1716 : switch (rString[ nPos ])
850 : {
851 : case '+':
852 0 : nPos++;
853 0 : return 1;
854 : case '(': // '(' similar to '-' ?!?
855 88 : nNegCheck = 1;
856 : //! fallthru
857 : case '-':
858 98 : nPos++;
859 98 : return -1;
860 : default:
861 1618 : break;
862 : }
863 :
864 1630 : return 0;
865 : }
866 :
867 :
868 : /**
869 : * Read a sign with an exponent
870 : * '+' => 1
871 : * '-' => -1
872 : * else => 0
873 : */
874 0 : short ImpSvNumberInputScan::GetESign( const OUString& rString, sal_Int32& nPos )
875 : {
876 0 : if (rString.getLength() > nPos)
877 : {
878 0 : switch (rString[nPos])
879 : {
880 : case '+':
881 0 : nPos++;
882 0 : return 1;
883 : case '-':
884 0 : nPos++;
885 0 : return -1;
886 : default:
887 0 : break;
888 : }
889 : }
890 0 : return 0;
891 : }
892 :
893 :
894 : /**
895 : * i counts string portions, j counts numbers thereof.
896 : * It should had been called SkipNumber instead.
897 : */
898 15477 : inline bool ImpSvNumberInputScan::GetNextNumber( sal_uInt16& i, sal_uInt16& j )
899 : {
900 15477 : if ( i < nAnzStrings && IsNum[i] )
901 : {
902 8138 : j++;
903 8138 : i++;
904 8138 : return true;
905 : }
906 7339 : return false;
907 : }
908 :
909 :
910 54 : bool ImpSvNumberInputScan::GetTimeRef( double& fOutNumber,
911 : sal_uInt16 nIndex, // j-value of the first numeric time part of input, default 0
912 : sal_uInt16 nAnz ) // count of numeric time parts
913 : {
914 54 : bool bRet = true;
915 : sal_uInt16 nHour;
916 54 : sal_uInt16 nMinute = 0;
917 54 : sal_uInt16 nSecond = 0;
918 54 : double fSecond100 = 0.0;
919 54 : sal_uInt16 nStartIndex = nIndex;
920 :
921 54 : if (nTimezonePos)
922 : {
923 : // find first timezone number index and adjust count
924 0 : for (sal_uInt16 j=0; j<nAnzNums; ++j)
925 : {
926 0 : if (nNums[j] == nTimezonePos)
927 : {
928 : // nAnz is not total count, but count of time relevant strings.
929 0 : if (nStartIndex < j && j - nStartIndex < nAnz)
930 : {
931 0 : nAnz = j - nStartIndex;
932 : }
933 0 : break; // for
934 : }
935 : }
936 : }
937 :
938 54 : if (nDecPos == 2 && (nAnz == 3 || nAnz == 2)) // 20:45.5 or 45.5
939 : {
940 0 : nHour = 0;
941 : }
942 54 : else if (nIndex - nStartIndex < nAnz)
943 : {
944 54 : nHour = (sal_uInt16) sStrArray[nNums[nIndex++]].toInt32();
945 : }
946 : else
947 : {
948 0 : nHour = 0;
949 0 : bRet = false;
950 : SAL_WARN( "svl.numbers", "ImpSvNumberInputScan::GetTimeRef: bad number index");
951 : }
952 54 : if (nDecPos == 2 && nAnz == 2) // 45.5
953 : {
954 0 : nMinute = 0;
955 : }
956 54 : else if (nIndex - nStartIndex < nAnz)
957 : {
958 54 : nMinute = (sal_uInt16) sStrArray[nNums[nIndex++]].toInt32();
959 : }
960 54 : if (nIndex - nStartIndex < nAnz)
961 : {
962 8 : nSecond = (sal_uInt16) sStrArray[nNums[nIndex++]].toInt32();
963 : }
964 54 : if (nIndex - nStartIndex < nAnz)
965 : {
966 0 : fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], true );
967 : }
968 54 : if (nAmPm && nHour > 12) // not a valid AM/PM clock time
969 : {
970 0 : bRet = false;
971 : }
972 54 : else if (nAmPm == -1 && nHour != 12) // PM
973 : {
974 21 : nHour += 12;
975 : }
976 33 : else if (nAmPm == 1 && nHour == 12) // 12 AM
977 : {
978 0 : nHour = 0;
979 : }
980 108 : fOutNumber = ((double)nHour*3600 +
981 108 : (double)nMinute*60 +
982 54 : (double)nSecond +
983 54 : fSecond100)/86400.0;
984 54 : return bRet;
985 : }
986 :
987 :
988 657 : sal_uInt16 ImpSvNumberInputScan::ImplGetDay( sal_uInt16 nIndex )
989 : {
990 657 : sal_uInt16 nRes = 0;
991 :
992 657 : if (sStrArray[nNums[nIndex]].getLength() <= 2)
993 : {
994 657 : sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].toInt32();
995 657 : if (nNum <= 31)
996 : {
997 657 : nRes = nNum;
998 : }
999 : }
1000 :
1001 657 : return nRes;
1002 : }
1003 :
1004 :
1005 649 : sal_uInt16 ImpSvNumberInputScan::ImplGetMonth( sal_uInt16 nIndex )
1006 : {
1007 : // Preset invalid month number
1008 649 : sal_uInt16 nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
1009 :
1010 649 : if (sStrArray[nNums[nIndex]].getLength() <= 2)
1011 : {
1012 649 : sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].toInt32();
1013 649 : if ( 0 < nNum && nNum <= nRes )
1014 : {
1015 649 : nRes = nNum - 1; // zero based for CalendarFieldIndex::MONTH
1016 : }
1017 : }
1018 :
1019 649 : return nRes;
1020 : }
1021 :
1022 :
1023 : /**
1024 : * 30 -> 1930, 29 -> 2029, or 56 -> 1756, 55 -> 1855, ...
1025 : */
1026 656 : sal_uInt16 ImpSvNumberInputScan::ImplGetYear( sal_uInt16 nIndex )
1027 : {
1028 656 : sal_uInt16 nYear = 0;
1029 :
1030 656 : sal_Int32 nLen = sStrArray[nNums[nIndex]].getLength();
1031 656 : if (nLen <= 4)
1032 : {
1033 656 : nYear = (sal_uInt16) sStrArray[nNums[nIndex]].toInt32();
1034 : // A year < 100 entered with at least 3 digits with leading 0 is taken
1035 : // as is without expansion.
1036 656 : if (nYear < 100 && nLen < 3)
1037 : {
1038 4 : nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 );
1039 : }
1040 : }
1041 :
1042 656 : return nYear;
1043 : }
1044 :
1045 :
1046 4198 : bool ImpSvNumberInputScan::MayBeIso8601()
1047 : {
1048 4198 : if (nMayBeIso8601 == 0)
1049 : {
1050 1753 : nMayBeIso8601 = 1;
1051 1753 : sal_Int32 nLen = ((nAnzNums >= 1 && nNums[0] < nAnzStrings) ? sStrArray[nNums[0]].getLength() : 0);
1052 1753 : if (nLen)
1053 : {
1054 : sal_Int32 n;
1055 4882 : if (nAnzNums >= 3 && nNums[2] < nAnzStrings &&
1056 1339 : comphelper::string::equals(sStrArray[nNums[0]+1], '-') && // separator year-month
1057 1935 : (n = sStrArray[nNums[1]].toInt32()) >= 1 && n <= 12 && // month
1058 1284 : comphelper::string::equals(sStrArray[nNums[1]+1], '-') && // separator month-day
1059 3037 : (n = sStrArray[nNums[2]].toInt32()) >= 1 && n <= 31) // day
1060 : {
1061 : // Year (nNums[0]) value not checked, may be anything, but
1062 : // length (number of digits) is checked.
1063 642 : nMayBeIso8601 = (nLen >= 4 ? 4 : (nLen == 3 ? 3 : (nLen > 0 ? 2 : 1)));
1064 : }
1065 : }
1066 : }
1067 4198 : return nMayBeIso8601 > 1;
1068 : }
1069 :
1070 :
1071 1289 : bool ImpSvNumberInputScan::CanForceToIso8601( DateFormat eDateFormat )
1072 : {
1073 1289 : if (nCanForceToIso8601 == 0)
1074 : {
1075 :
1076 653 : if (!MayBeIso8601())
1077 : {
1078 11 : nCanForceToIso8601 = 1;
1079 : }
1080 642 : else if (nMayBeIso8601 >= 3)
1081 : {
1082 642 : nCanForceToIso8601 = 2; // at least 3 digits in year
1083 : }
1084 : else
1085 : {
1086 0 : nCanForceToIso8601 = 1;
1087 : }
1088 :
1089 : sal_Int32 n;
1090 653 : switch (eDateFormat)
1091 : {
1092 : case DMY: // "day" value out of range => ISO 8601 year
1093 5 : if ((n = sStrArray[nNums[0]].toInt32()) < 1 || n > 31)
1094 : {
1095 0 : nCanForceToIso8601 = 2;
1096 : }
1097 5 : break;
1098 : case MDY: // "month" value out of range => ISO 8601 year
1099 648 : if ((n = sStrArray[nNums[0]].toInt32()) < 1 || n > 12)
1100 : {
1101 642 : nCanForceToIso8601 = 2;
1102 : }
1103 648 : break;
1104 : case YMD: // always possible
1105 0 : nCanForceToIso8601 = 2;
1106 0 : break;
1107 : }
1108 : }
1109 1289 : return nCanForceToIso8601 > 1;
1110 : }
1111 :
1112 :
1113 1595 : bool ImpSvNumberInputScan::MayBeMonthDate()
1114 : {
1115 1595 : if (nMayBeMonthDate == 0)
1116 : {
1117 1103 : nMayBeMonthDate = 1;
1118 1103 : if (nAnzNums >= 2 && nNums[1] < nAnzStrings)
1119 : {
1120 : // "-Jan-"
1121 1092 : const OUString& rM = sStrArray[ nNums[ 0 ] + 1 ];
1122 1092 : if (rM.getLength() >= 3 && rM[0] == (sal_Unicode)'-' && rM[ rM.getLength() - 1] == (sal_Unicode)'-')
1123 : {
1124 : // Check year length assuming at least 3 digits (including
1125 : // leading zero). Two digit years 1..31 are out of luck here
1126 : // and may be taken as day of month.
1127 0 : bool bYear1 = (sStrArray[nNums[0]].getLength() >= 3);
1128 0 : bool bYear2 = (sStrArray[nNums[1]].getLength() >= 3);
1129 : sal_Int32 n;
1130 0 : bool bDay1 = (!bYear1 && (n = sStrArray[nNums[0]].toInt32()) >= 1 && n <= 31);
1131 0 : bool bDay2 = (!bYear2 && (n = sStrArray[nNums[1]].toInt32()) >= 1 && n <= 31);
1132 :
1133 0 : if (bDay1 && !bDay2)
1134 : {
1135 0 : nMayBeMonthDate = 2; // dd-month-yy
1136 : }
1137 0 : else if (!bDay1 && bDay2)
1138 : {
1139 0 : nMayBeMonthDate = 3; // yy-month-dd
1140 : }
1141 0 : else if (bDay1 && bDay2)
1142 : {
1143 : // Ambiguous ##-MMM-## date, but some big vendor's database
1144 : // reports write this crap, assume this always to be
1145 0 : nMayBeMonthDate = 2; // dd-month-yy
1146 : }
1147 : }
1148 : }
1149 : }
1150 1595 : return nMayBeMonthDate > 1;
1151 : }
1152 :
1153 :
1154 4223 : bool ImpSvNumberInputScan::IsAcceptedDatePattern( sal_uInt16 nStartPatternAt )
1155 : {
1156 4223 : if (nAcceptedDatePattern >= -1)
1157 : {
1158 2470 : return (nAcceptedDatePattern >= 0);
1159 : }
1160 1753 : if (!nAnzNums)
1161 : {
1162 0 : nAcceptedDatePattern = -1;
1163 : }
1164 1753 : else if (!sDateAcceptancePatterns.getLength())
1165 : {
1166 76 : sDateAcceptancePatterns = pFormatter->GetLocaleData()->getDateAcceptancePatterns();
1167 : SAL_WARN_IF( !sDateAcceptancePatterns.getLength(), "svl.numbers", "ImpSvNumberInputScan::IsAcceptedDatePattern: no date acceptance patterns");
1168 76 : nAcceptedDatePattern = (sDateAcceptancePatterns.getLength() ? -2 : -1);
1169 : }
1170 :
1171 1753 : if (nAcceptedDatePattern == -1)
1172 : {
1173 0 : return false;
1174 : }
1175 1753 : nDatePatternStart = nStartPatternAt; // remember start particle
1176 :
1177 1753 : const sal_Int32 nMonthsInYear = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
1178 :
1179 5262 : for (sal_Int32 nPattern=0; nPattern < sDateAcceptancePatterns.getLength(); ++nPattern)
1180 : {
1181 3516 : sal_uInt16 nNext = nDatePatternStart;
1182 3516 : nDatePatternNumbers = 0;
1183 3516 : bool bOk = true;
1184 3516 : const OUString& rPat = sDateAcceptancePatterns[nPattern];
1185 3516 : sal_Int32 nPat = 0;
1186 7886 : for ( ; nPat < rPat.getLength() && bOk && nNext < nAnzStrings; ++nPat, ++nNext)
1187 : {
1188 4370 : const sal_Unicode c = rPat[nPat];
1189 4370 : switch (c)
1190 : {
1191 : case 'Y':
1192 : case 'M':
1193 : case 'D':
1194 3530 : bOk = IsNum[nNext];
1195 3530 : if (bOk && (c == 'M' || c == 'D'))
1196 : {
1197 : // Check the D and M cases for plausibility. This also
1198 : // prevents recognition of date instead of number with a
1199 : // numeric group input if date separator is identical to
1200 : // group separator, for example with D.M as a pattern and
1201 : // #.### as a group.
1202 : sal_Int32 nMaxLen, nMaxVal;
1203 3523 : switch (c)
1204 : {
1205 : case 'M':
1206 3465 : nMaxLen = 2;
1207 3465 : nMaxVal = nMonthsInYear;
1208 3465 : break;
1209 : case 'D':
1210 58 : nMaxLen = 2;
1211 58 : nMaxVal = 31;
1212 58 : break;
1213 : default:
1214 : // This merely exists against
1215 : // -Werror=maybe-uninitialized, which is nonsense
1216 : // after the (c == 'M' || c == 'D') check above,
1217 : // but ...
1218 0 : nMaxLen = 2;
1219 0 : nMaxVal = 31;
1220 : }
1221 3523 : bOk = (sStrArray[nNext].getLength() <= nMaxLen);
1222 3523 : if (bOk)
1223 : {
1224 2135 : sal_Int32 nNum = sStrArray[nNext].toInt32();
1225 2135 : bOk = (1 <= nNum && nNum <= nMaxVal);
1226 : }
1227 : }
1228 3530 : if (bOk)
1229 849 : ++nDatePatternNumbers;
1230 3530 : break;
1231 : default:
1232 840 : bOk = !IsNum[nNext];
1233 840 : if (bOk)
1234 : {
1235 840 : const sal_Int32 nLen = sStrArray[nNext].getLength();
1236 840 : bOk = (rPat.indexOf( sStrArray[nNext], nPat) == nPat);
1237 840 : if (bOk)
1238 : {
1239 14 : nPat += nLen - 1;
1240 : }
1241 826 : else if (nPat + nLen > rPat.getLength() && sStrArray[nNext][ nLen - 1 ] == ' ')
1242 : {
1243 : using namespace comphelper::string;
1244 : // Trailing blanks in input.
1245 220 : OUStringBuffer aBuf(sStrArray[nNext]);
1246 220 : aBuf.stripEnd((sal_Unicode)' ');
1247 : // Expand again in case of pattern "M. D. " and
1248 : // input "M. D. ", maybe fetched far, but..
1249 220 : padToLength(aBuf, rPat.getLength() - nPat, ' ');
1250 440 : OUString aStr = aBuf.makeStringAndClear();
1251 220 : bOk = (rPat.indexOf( aStr, nPat) == nPat);
1252 220 : if (bOk)
1253 : {
1254 0 : nPat += aStr.getLength() - 1;
1255 220 : }
1256 : }
1257 : }
1258 840 : break;
1259 : }
1260 : }
1261 3516 : if (bOk)
1262 : {
1263 : // Check for trailing characters mismatch.
1264 9 : if (nNext < nAnzStrings)
1265 : {
1266 : // Pattern end but not input end.
1267 : // A trailing blank may be part of the current pattern input,
1268 : // if pattern is "D.M." and input is "D.M. hh:mm" last was
1269 : // ". ", or may be following the current pattern input, if
1270 : // pattern is "D.M" and input is "D.M hh:mm" last was "M".
1271 0 : sal_Int32 nPos = 0;
1272 : sal_uInt16 nCheck;
1273 0 : if (nPat > 0 && nNext > 0)
1274 : {
1275 : // nPat is one behind after the for loop.
1276 0 : sal_Int32 nPatCheck = nPat - 1;
1277 0 : switch (rPat[nPatCheck])
1278 : {
1279 : case 'Y':
1280 : case 'M':
1281 : case 'D':
1282 0 : nCheck = nNext;
1283 0 : break;
1284 : default:
1285 : {
1286 0 : nCheck = nNext - 1;
1287 : // Advance position in input to match length of
1288 : // non-YMD (separator) characters in pattern.
1289 : sal_Unicode c;
1290 0 : do
1291 : {
1292 0 : ++nPos;
1293 0 : } while ((c = rPat[--nPatCheck]) != 'Y' && c != 'M' && c != 'D');
1294 : }
1295 0 : }
1296 : }
1297 : else
1298 : {
1299 0 : nCheck = nNext;
1300 : }
1301 0 : if (!IsNum[nCheck])
1302 : {
1303 : // Trailing (or separating if time follows) blanks are ok.
1304 0 : SkipBlanks( sStrArray[nCheck], nPos);
1305 0 : if (nPos == sStrArray[nCheck].getLength())
1306 : {
1307 0 : nAcceptedDatePattern = nPattern;
1308 0 : return true;
1309 : }
1310 : }
1311 : }
1312 9 : else if (nPat == rPat.getLength())
1313 : {
1314 : // Input end and pattern end => match.
1315 7 : nAcceptedDatePattern = nPattern;
1316 7 : return true;
1317 : }
1318 : // else Input end but not pattern end, no match.
1319 : }
1320 : }
1321 1746 : nAcceptedDatePattern = -1;
1322 1746 : return false;
1323 : }
1324 :
1325 :
1326 2924 : bool ImpSvNumberInputScan::SkipDatePatternSeparator( sal_uInt16 nParticle, sal_Int32 & rPos )
1327 : {
1328 : // If not initialized yet start with first number, if any.
1329 2924 : if (!IsAcceptedDatePattern( (nAnzNums ? nNums[0] : 0)))
1330 : {
1331 2910 : return false;
1332 : }
1333 14 : if (nParticle < nDatePatternStart || nParticle >= nAnzStrings || IsNum[nParticle])
1334 : {
1335 0 : return false;
1336 : }
1337 14 : sal_uInt16 nNext = nDatePatternStart;
1338 14 : const OUString& rPat = sDateAcceptancePatterns[nAcceptedDatePattern];
1339 42 : for (sal_Int32 nPat = 0; nPat < rPat.getLength() && nNext < nAnzStrings; ++nPat, ++nNext)
1340 : {
1341 42 : switch (rPat[nPat])
1342 : {
1343 : case 'Y':
1344 : case 'M':
1345 : case 'D':
1346 21 : break;
1347 : default:
1348 21 : if (nNext == nParticle)
1349 : {
1350 14 : const sal_Int32 nLen = sStrArray[nNext].getLength();
1351 14 : bool bOk = (rPat.indexOf( sStrArray[nNext], nPat) == nPat);
1352 14 : if (!bOk && (nPat + nLen > rPat.getLength() && sStrArray[nNext][ nLen - 1 ] == (sal_Unicode)' '))
1353 : {
1354 : // The same ugly trailing blanks check as in
1355 : // IsAcceptedDatePattern().
1356 : using namespace comphelper::string;
1357 0 : OUStringBuffer aBuf(sStrArray[nNext]);
1358 0 : aBuf.stripEnd((sal_Unicode)' ');
1359 0 : padToLength(aBuf, rPat.getLength() - nPat, ' ');
1360 0 : bOk = (rPat.indexOf( aBuf.makeStringAndClear(), nPat) == nPat);
1361 : }
1362 14 : if (bOk)
1363 : {
1364 14 : rPos = nLen; // yes, set, not add!
1365 14 : return true;
1366 : }
1367 : else
1368 0 : return false;
1369 : }
1370 7 : nPat += sStrArray[nNext].getLength() - 1;
1371 7 : break;
1372 : }
1373 : }
1374 0 : return false;
1375 : }
1376 :
1377 :
1378 641 : sal_uInt16 ImpSvNumberInputScan::GetDatePatternNumbers()
1379 : {
1380 : // If not initialized yet start with first number, if any.
1381 641 : if (!IsAcceptedDatePattern( (nAnzNums ? nNums[0] : 0)))
1382 : {
1383 634 : return 0;
1384 : }
1385 7 : return nDatePatternNumbers;
1386 : }
1387 :
1388 :
1389 650 : sal_uInt32 ImpSvNumberInputScan::GetDatePatternOrder()
1390 : {
1391 : // If not initialized yet start with first number, if any.
1392 650 : if (!IsAcceptedDatePattern( (nAnzNums ? nNums[0] : 0)))
1393 : {
1394 646 : return 0;
1395 : }
1396 4 : sal_uInt32 nOrder = 0;
1397 4 : const OUString& rPat = sDateAcceptancePatterns[nAcceptedDatePattern];
1398 24 : for (sal_Int32 nPat = 0; nPat < rPat.getLength() && !(nOrder & 0xff0000); ++nPat)
1399 : {
1400 20 : switch (rPat[nPat])
1401 : {
1402 : case 'Y':
1403 : case 'M':
1404 : case 'D':
1405 12 : nOrder = (nOrder << 8) | rPat[nPat];
1406 12 : break;
1407 : }
1408 : }
1409 4 : return nOrder;
1410 : }
1411 :
1412 :
1413 650 : DateFormat ImpSvNumberInputScan::GetDateOrder()
1414 : {
1415 650 : sal_uInt32 nOrder = GetDatePatternOrder();
1416 650 : if (!nOrder)
1417 : {
1418 646 : return pFormatter->GetLocaleData()->getDateFormat();
1419 : }
1420 4 : switch ((nOrder & 0xff0000) >> 16)
1421 : {
1422 : case 'Y':
1423 0 : if ((((nOrder & 0xff00) >> 8) == 'M') && ((nOrder & 0xff) == 'D'))
1424 : {
1425 0 : return YMD;
1426 : }
1427 0 : break;
1428 : case 'M':
1429 3 : if ((((nOrder & 0xff00) >> 8) == 'D') && ((nOrder & 0xff) == 'Y'))
1430 : {
1431 3 : return MDY;
1432 : }
1433 0 : break;
1434 : case 'D':
1435 1 : if ((((nOrder & 0xff00) >> 8) == 'M') && ((nOrder & 0xff) == 'Y'))
1436 : {
1437 1 : return DMY;
1438 : }
1439 0 : break;
1440 : default:
1441 : case 0:
1442 0 : switch ((nOrder & 0xff00) >> 8)
1443 : {
1444 : case 'Y':
1445 0 : switch ((nOrder & 0xff))
1446 : {
1447 : case 'M':
1448 0 : return YMD;
1449 : }
1450 0 : break;
1451 : case 'M':
1452 0 : switch ((nOrder & 0xff))
1453 : {
1454 : case 'Y':
1455 0 : return DMY;
1456 : case 'D':
1457 0 : return MDY;
1458 : }
1459 0 : break;
1460 : case 'D':
1461 0 : switch ((nOrder & 0xff))
1462 : {
1463 : case 'Y':
1464 0 : return MDY;
1465 : case 'M':
1466 0 : return DMY;
1467 : }
1468 0 : break;
1469 : default:
1470 : case 0:
1471 0 : switch ((nOrder & 0xff))
1472 : {
1473 : case 'Y':
1474 0 : return YMD;
1475 : case 'M':
1476 0 : return MDY;
1477 : case 'D':
1478 0 : return DMY;
1479 : }
1480 0 : break;
1481 : }
1482 : }
1483 : SAL_WARN( "svl.numbers", "ImpSvNumberInputScan::GetDateOrder: undefined, falling back to locale's default");
1484 0 : return pFormatter->GetLocaleData()->getDateFormat();
1485 : }
1486 :
1487 656 : bool ImpSvNumberInputScan::GetDateRef( double& fDays, sal_uInt16& nCounter,
1488 : const SvNumberformat* pFormat )
1489 : {
1490 : using namespace ::com::sun::star::i18n;
1491 : NfEvalDateFormat eEDF;
1492 : int nFormatOrder;
1493 656 : if ( pFormat && (pFormat->GetType() & css::util::NumberFormat::DATE) )
1494 : {
1495 8 : eEDF = pFormatter->GetEvalDateFormat();
1496 8 : switch ( eEDF )
1497 : {
1498 : case NF_EVALDATEFORMAT_INTL :
1499 : case NF_EVALDATEFORMAT_FORMAT :
1500 0 : nFormatOrder = 1; // only one loop
1501 0 : break;
1502 : default:
1503 8 : nFormatOrder = 2;
1504 8 : if ( nMatchedAllStrings )
1505 : {
1506 3 : eEDF = NF_EVALDATEFORMAT_FORMAT_INTL;
1507 : // we have a complete match, use it
1508 : }
1509 : }
1510 : }
1511 : else
1512 : {
1513 648 : eEDF = NF_EVALDATEFORMAT_INTL;
1514 648 : nFormatOrder = 1;
1515 : }
1516 656 : bool res = true;
1517 :
1518 656 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1519 656 : CalendarWrapper* pCal = pFormatter->GetCalendar();
1520 1312 : for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ )
1521 : {
1522 656 : pCal->setGregorianDateTime( Date( Date::SYSTEM ) ); // today
1523 656 : OUString aOrgCalendar; // empty => not changed yet
1524 : DateFormat DateFmt;
1525 : bool bFormatTurn;
1526 656 : switch ( eEDF )
1527 : {
1528 : case NF_EVALDATEFORMAT_INTL :
1529 648 : bFormatTurn = false;
1530 648 : DateFmt = GetDateOrder();
1531 648 : break;
1532 : case NF_EVALDATEFORMAT_FORMAT :
1533 0 : bFormatTurn = true;
1534 0 : DateFmt = pFormat->GetDateOrder();
1535 0 : break;
1536 : case NF_EVALDATEFORMAT_INTL_FORMAT :
1537 2 : if ( nTryOrder == 1 )
1538 : {
1539 2 : bFormatTurn = false;
1540 2 : DateFmt = GetDateOrder();
1541 : }
1542 : else
1543 : {
1544 0 : bFormatTurn = true;
1545 0 : DateFmt = pFormat->GetDateOrder();
1546 : }
1547 2 : break;
1548 : case NF_EVALDATEFORMAT_FORMAT_INTL :
1549 6 : if ( nTryOrder == 2 )
1550 : {
1551 0 : bFormatTurn = false;
1552 0 : DateFmt = GetDateOrder();
1553 : }
1554 : else
1555 : {
1556 6 : bFormatTurn = true;
1557 6 : DateFmt = pFormat->GetDateOrder();
1558 : }
1559 6 : break;
1560 : default:
1561 : SAL_WARN( "svl.numbers", "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" );
1562 0 : DateFmt = YMD;
1563 0 : bFormatTurn = false;
1564 : }
1565 : if ( bFormatTurn )
1566 : {
1567 : /* TODO:
1568 : We are currently not able to fully support a switch to another calendar during
1569 : input for the following reasons:
1570 : 1. We do have a problem if both (locale's default and format's) calendars
1571 : define the same YMD order and use the same date separator, there is no way
1572 : to distinguish between them if the input results in valid calendar input for
1573 : both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should
1574 : it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's
1575 : calendar be preferred? This could be confusing if a Calc cell was formatted
1576 : different to the locale's default and has no content yet, then the user has
1577 : no clue about the format or calendar being set.
1578 : 2. In Calc cell edit mode a date is always displayed and edited using the
1579 : default edit format of the default calendar (normally being Gregorian). If
1580 : input was ambiguous due to issue #1 we'd need a mechanism to tell that a
1581 : date was edited and not newly entered. Not feasible. Otherwise we'd need a
1582 : mechanism to use a specific edit format with a specific calendar according
1583 : to the format set.
1584 : 3. For some calendars like Japanese Gengou we'd need era input, which isn't
1585 : implemented at all. Though this is a rare and special case, forcing a
1586 : calendar dependent edit format as suggested in item #2 might require era
1587 : input, if it shouldn't result in a fallback to Gregorian calendar.
1588 : 4. Last and least: the GetMonth() method currently only matches month names of
1589 : the default calendar. Alternating month names of the actual format's
1590 : calendar would have to be implemented. No problem.
1591 :
1592 : */
1593 : #ifdef THE_FUTURE
1594 : if ( pFormat->IsOtherCalendar( nStringScanNumFor ) )
1595 : {
1596 : pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
1597 : }
1598 : else
1599 : {
1600 : pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime,
1601 : nStringScanNumFor );
1602 : }
1603 : #endif
1604 : }
1605 :
1606 656 : res = true;
1607 656 : nCounter = 0;
1608 : // For incomplete dates, always assume first day of month if not specified.
1609 656 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1610 :
1611 656 : switch (nAnzNums) // count of numbers in string
1612 : {
1613 : case 0: // none
1614 0 : if (nMonthPos) // only month (Jan)
1615 : {
1616 0 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1617 : }
1618 : else
1619 : {
1620 0 : res = false;
1621 : }
1622 0 : break;
1623 :
1624 : case 1: // only one number
1625 1 : nCounter = 1;
1626 1 : switch (nMonthPos) // where is the month
1627 : {
1628 : case 0: // not found
1629 : {
1630 : // If input matched a date pattern, use the pattern
1631 : // to determine if it is a day, month or year. The
1632 : // pattern should have only one single value then,
1633 : // 'D-', 'M-' or 'Y-'. If input did not match a
1634 : // pattern assume the usual day of current month.
1635 : sal_uInt32 nDateOrder = (bFormatTurn ?
1636 : pFormat->GetExactDateOrder() :
1637 0 : GetDatePatternOrder());
1638 0 : switch (nDateOrder)
1639 : {
1640 : case 'Y':
1641 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1642 0 : break;
1643 : case 'M':
1644 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1645 0 : break;
1646 : case 'D':
1647 : default:
1648 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1649 0 : break;
1650 : }
1651 0 : break;
1652 : }
1653 : case 1: // month at the beginning (Jan 01)
1654 1 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1655 1 : switch (DateFmt)
1656 : {
1657 : case MDY:
1658 : case YMD:
1659 : {
1660 1 : sal_uInt16 nDay = ImplGetDay(0);
1661 1 : sal_uInt16 nYear = ImplGetYear(0);
1662 1 : if (nDay == 0 || nDay > 32)
1663 : {
1664 0 : pCal->setValue( CalendarFieldIndex::YEAR, nYear);
1665 : }
1666 : else
1667 : {
1668 1 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1669 : }
1670 1 : break;
1671 : }
1672 : case DMY:
1673 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1674 0 : break;
1675 : default:
1676 0 : res = false;
1677 0 : break;
1678 : }
1679 1 : break;
1680 : case 3: // month at the end (10 Jan)
1681 0 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1682 0 : switch (DateFmt)
1683 : {
1684 : case DMY:
1685 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1686 0 : break;
1687 : case YMD:
1688 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1689 0 : break;
1690 : default:
1691 0 : res = false;
1692 0 : break;
1693 : }
1694 0 : break;
1695 : default:
1696 0 : res = false;
1697 0 : break;
1698 : } // switch (nMonthPos)
1699 1 : break;
1700 :
1701 : case 2: // 2 numbers
1702 6 : nCounter = 2;
1703 6 : switch (nMonthPos) // where is the month
1704 : {
1705 : case 0: // not found
1706 : {
1707 : sal_uInt32 nExactDateOrder = (bFormatTurn ?
1708 : pFormat->GetExactDateOrder() :
1709 0 : GetDatePatternOrder());
1710 0 : bool bIsExact = (0xff < nExactDateOrder && nExactDateOrder <= 0xffff);
1711 0 : if (!bIsExact && bFormatTurn && IsAcceptedDatePattern( nNums[0]))
1712 : {
1713 : // If input does not match format but pattern, use pattern
1714 : // instead, even if eEDF==NF_EVALDATEFORMAT_FORMAT_INTL.
1715 : // For example, format has "Y-M-D" and pattern is "D.M.",
1716 : // input with 2 numbers can't match format and 31.12. would
1717 : // lead to 1931-12-01 (fdo#54344)
1718 0 : nExactDateOrder = GetDatePatternOrder();
1719 0 : bIsExact = (0xff < nExactDateOrder && nExactDateOrder <= 0xffff);
1720 : }
1721 : bool bHadExact;
1722 0 : if (bIsExact)
1723 : {
1724 : // formatted as date and exactly 2 parts
1725 0 : bHadExact = true;
1726 0 : switch ( (nExactDateOrder >> 8) & 0xff )
1727 : {
1728 : case 'Y':
1729 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1730 0 : break;
1731 : case 'M':
1732 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1733 0 : break;
1734 : case 'D':
1735 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1736 0 : break;
1737 : default:
1738 0 : bHadExact = false;
1739 : }
1740 0 : switch ( nExactDateOrder & 0xff )
1741 : {
1742 : case 'Y':
1743 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1744 0 : break;
1745 : case 'M':
1746 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1747 0 : break;
1748 : case 'D':
1749 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1750 0 : break;
1751 : default:
1752 0 : bHadExact = false;
1753 : }
1754 : SAL_WARN_IF( !bHadExact, "svl.numbers", "ImpSvNumberInputScan::GetDateRef: error in exact date order");
1755 : }
1756 : else
1757 : {
1758 0 : bHadExact = false;
1759 : }
1760 : // If input matched against a date acceptance pattern
1761 : // do not attempt to mess around with guessing the
1762 : // order, either it matches or it doesn't.
1763 0 : if ((bFormatTurn || !bIsExact) && (!bHadExact || !pCal->isValid()))
1764 : {
1765 0 : if ( !bHadExact && nExactDateOrder )
1766 : {
1767 0 : pCal->setGregorianDateTime( Date( Date::SYSTEM ) ); // reset today
1768 : }
1769 0 : switch (DateFmt)
1770 : {
1771 : case MDY:
1772 : // M D
1773 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1774 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1775 0 : if ( !pCal->isValid() ) // 2nd try
1776 : { // M Y
1777 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1778 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1779 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1780 : }
1781 0 : break;
1782 : case DMY:
1783 : // D M
1784 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1785 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1786 0 : if ( !pCal->isValid() ) // 2nd try
1787 : { // M Y
1788 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1789 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1790 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1791 : }
1792 0 : break;
1793 : case YMD:
1794 : // M D
1795 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1796 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1797 0 : if ( !pCal->isValid() ) // 2nd try
1798 : { // Y M
1799 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1800 0 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1801 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1802 : }
1803 0 : break;
1804 : default:
1805 0 : res = false;
1806 0 : break;
1807 : }
1808 : }
1809 : }
1810 0 : break;
1811 : case 1: // month at the beginning (Jan 01 01)
1812 : {
1813 : // The input is valid as MDY in almost any
1814 : // constellation, there is no date order (M)YD except if
1815 : // set in a format applied.
1816 6 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1817 6 : sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1818 6 : if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D'))
1819 : {
1820 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1821 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1822 : }
1823 : else
1824 : {
1825 6 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1826 6 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1827 : }
1828 6 : break;
1829 : }
1830 : case 2: // month in the middle (10 Jan 94)
1831 : {
1832 0 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1833 0 : DateFormat eDF = (MayBeMonthDate() ? (nMayBeMonthDate == 2 ? DMY : YMD) : DateFmt);
1834 0 : switch (eDF)
1835 : {
1836 : case DMY:
1837 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1838 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1839 0 : break;
1840 : case YMD:
1841 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1842 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1843 0 : break;
1844 : default:
1845 0 : res = false;
1846 0 : break;
1847 : }
1848 0 : break;
1849 : }
1850 : default: // else, e.g. month at the end (94 10 Jan)
1851 0 : res = false;
1852 0 : break;
1853 : } // switch (nMonthPos)
1854 6 : break;
1855 :
1856 : default: // more than two numbers (31.12.94 8:23) (31.12. 8:23)
1857 649 : switch (nMonthPos) // where is the month
1858 : {
1859 : case 0: // not found
1860 : {
1861 649 : nCounter = 3;
1862 649 : if ( nTimePos > 1 )
1863 : { // find first time number index (should only be 3 or 2 anyway)
1864 32 : for ( sal_uInt16 j = 0; j < nAnzNums; j++ )
1865 : {
1866 32 : if ( nNums[j] == nTimePos - 2 )
1867 : {
1868 8 : nCounter = j;
1869 8 : break; // for
1870 : }
1871 : }
1872 : }
1873 : // ISO 8601 yyyy-mm-dd forced recognition
1874 649 : DateFormat eDF = (CanForceToIso8601( DateFmt) ? YMD : DateFmt);
1875 649 : switch (eDF)
1876 : {
1877 : case MDY:
1878 6 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1879 6 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1880 6 : if ( nCounter > 2 )
1881 6 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1882 6 : break;
1883 : case DMY:
1884 1 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1885 1 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1886 1 : if ( nCounter > 2 )
1887 1 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1888 1 : break;
1889 : case YMD:
1890 642 : if ( nCounter > 2 )
1891 642 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) );
1892 642 : pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1893 642 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1894 642 : break;
1895 : default:
1896 0 : res = false;
1897 0 : break;
1898 : }
1899 649 : break;
1900 : }
1901 : case 1: // month at the beginning (Jan 01 01 8:23)
1902 0 : nCounter = 2;
1903 0 : switch (DateFmt)
1904 : {
1905 : case MDY:
1906 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1907 0 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1908 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1909 0 : break;
1910 : default:
1911 0 : res = false;
1912 0 : break;
1913 : }
1914 0 : break;
1915 : case 2: // month in the middle (10 Jan 94 8:23)
1916 0 : nCounter = 2;
1917 0 : pCal->setValue( CalendarFieldIndex::MONTH, std::abs(nMonth)-1 );
1918 0 : switch (DateFmt)
1919 : {
1920 : case DMY:
1921 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1922 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1923 0 : break;
1924 : case YMD:
1925 0 : pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1926 0 : pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1927 0 : break;
1928 : default:
1929 0 : res = false;
1930 0 : break;
1931 : }
1932 0 : break;
1933 : default: // else, e.g. month at the end (94 10 Jan 8:23)
1934 0 : nCounter = 2;
1935 0 : res = false;
1936 0 : break;
1937 : } // switch (nMonthPos)
1938 649 : break;
1939 : } // switch (nAnzNums)
1940 :
1941 656 : if ( res && pCal->isValid() )
1942 : {
1943 656 : double fDiff = DateTime(*pNullDate) - pCal->getEpochStart();
1944 656 : fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() );
1945 656 : fDays -= fDiff;
1946 656 : nTryOrder = nFormatOrder; // break for
1947 : }
1948 : else
1949 : {
1950 0 : res = false;
1951 : }
1952 656 : if ( aOrgCalendar.getLength() )
1953 : {
1954 0 : pCal->loadCalendar( aOrgCalendar, pLoc->getLanguageTag().getLocale() ); // restore calendar
1955 : }
1956 : #if NF_TEST_CALENDAR
1957 : {
1958 : using namespace ::com::sun::star;
1959 : struct entry { const char* lan; const char* cou; const char* cal; };
1960 : const entry cals[] = {
1961 : { "en", "US", "gregorian" },
1962 : { "ar", "TN", "hijri" },
1963 : { "he", "IL", "jewish" },
1964 : { "ja", "JP", "gengou" },
1965 : { "ko", "KR", "hanja_yoil" },
1966 : { "th", "TH", "buddhist" },
1967 : { "zh", "TW", "ROC" },
1968 : {0,0,0}
1969 : };
1970 : lang::Locale aLocale;
1971 : bool bValid;
1972 : sal_Int16 nDay, nMyMonth, nYear, nHour, nMinute, nSecond;
1973 : sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet;
1974 : sal_Int16 nZO, nDST1, nDST2, nDST, nZOmillis, nDST1millis, nDST2millis, nDSTmillis;
1975 : sal_Int32 nZoneInMillis, nDST1InMillis, nDST2InMillis;
1976 : uno::Reference< uno::XComponentContext > xContext =
1977 : ::comphelper::getProcessComponentContext();
1978 : uno::Reference< i18n::XCalendar4 > xCal = i18n::LocaleCalendar2::create(xContext);
1979 : for ( const entry* p = cals; p->lan; ++p )
1980 : {
1981 : aLocale.Language = OUString::createFromAscii( p->lan );
1982 : aLocale.Country = OUString::createFromAscii( p->cou );
1983 : xCal->loadCalendar( OUString::createFromAscii( p->cal ),
1984 : aLocale );
1985 : double nDateTime = 0.0; // 1-Jan-1970 00:00:00
1986 : nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1987 : nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1988 : nZoneInMillis = static_cast<sal_Int32>(nZO) * 60000 +
1989 : (nZO < 0 ? -1 : 1) * static_cast<sal_uInt16>(nZOmillis);
1990 : nDST1 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1991 : nDST1millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1992 : nDST1InMillis = static_cast<sal_Int32>(nDST1) * 60000 +
1993 : (nDST1 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST1millis);
1994 : nDateTime -= (double)(nZoneInMillis + nDST1InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1995 : xCal->setDateTime( nDateTime );
1996 : nDST2 = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1997 : nDST2millis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1998 : nDST2InMillis = static_cast<sal_Int32>(nDST2) * 60000 +
1999 : (nDST2 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST2millis);
2000 : if ( nDST1InMillis != nDST2InMillis )
2001 : {
2002 : nDateTime = 0.0 - (double)(nZoneInMillis + nDST2InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
2003 : xCal->setDateTime( nDateTime );
2004 : }
2005 : nDaySet = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
2006 : nMonthSet = xCal->getValue( i18n::CalendarFieldIndex::MONTH );
2007 : nYearSet = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
2008 : nHourSet = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
2009 : nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
2010 : nSecondSet = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
2011 : nZO = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
2012 : nZOmillis = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
2013 : nDST = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
2014 : nDSTmillis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
2015 : xCal->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDaySet );
2016 : xCal->setValue( i18n::CalendarFieldIndex::MONTH, nMonthSet );
2017 : xCal->setValue( i18n::CalendarFieldIndex::YEAR, nYearSet );
2018 : xCal->setValue( i18n::CalendarFieldIndex::HOUR, nHourSet );
2019 : xCal->setValue( i18n::CalendarFieldIndex::MINUTE, nMinuteSet );
2020 : xCal->setValue( i18n::CalendarFieldIndex::SECOND, nSecondSet );
2021 : bValid = xCal->isValid();
2022 : nDay = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
2023 : nMyMonth= xCal->getValue( i18n::CalendarFieldIndex::MONTH );
2024 : nYear = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
2025 : nHour = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
2026 : nMinute = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
2027 : nSecond = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
2028 : bValid = bValid && nDay == nDaySet && nMyMonth == nMonthSet && nYear ==
2029 : nYearSet && nHour == nHourSet && nMinute == nMinuteSet && nSecond
2030 : == nSecondSet;
2031 : }
2032 : }
2033 : #endif // NF_TEST_CALENDAR
2034 :
2035 656 : }
2036 :
2037 656 : return res;
2038 : }
2039 :
2040 :
2041 : /**
2042 : * Analyze first string
2043 : * All gone => true
2044 : * else => false
2045 : */
2046 1613 : bool ImpSvNumberInputScan::ScanStartString( const OUString& rString,
2047 : const SvNumberformat* pFormat )
2048 : {
2049 1613 : sal_Int32 nPos = 0;
2050 :
2051 : // First of all, eat leading blanks
2052 1613 : SkipBlanks(rString, nPos);
2053 :
2054 : // Yes, nMatchedAllStrings should know about the sign position
2055 1613 : nSign = GetSign(rString, nPos);
2056 1613 : if ( nSign ) // sign?
2057 : {
2058 96 : SkipBlanks(rString, nPos);
2059 : }
2060 : // #102371# match against format string only if start string is not a sign character
2061 1613 : if ( nMatchedAllStrings && !(nSign && rString.getLength() == 1) )
2062 : {
2063 : // Match against format in any case, so later on for a "x1-2-3" input
2064 : // we may distinguish between a xy-m-d (or similar) date and a x0-0-0
2065 : // format. No sign detection here!
2066 1605 : if ( ScanStringNumFor( rString, nPos, pFormat, 0, true ) )
2067 : {
2068 0 : nMatchedAllStrings |= nMatchedStartString;
2069 : }
2070 : else
2071 : {
2072 1605 : nMatchedAllStrings = 0;
2073 : }
2074 : }
2075 :
2076 1613 : if ( GetDecSep(rString, nPos) ) // decimal separator in start string
2077 : {
2078 0 : nDecPos = 1;
2079 0 : SkipBlanks(rString, nPos);
2080 : }
2081 1613 : else if ( GetCurrency(rString, nPos, pFormat) ) // currency (DM 1)?
2082 : {
2083 58 : eScannedType = css::util::NumberFormat::CURRENCY; // !!! it IS currency !!!
2084 58 : SkipBlanks(rString, nPos);
2085 58 : if (nSign == 0) // no sign yet
2086 : {
2087 58 : nSign = GetSign(rString, nPos);
2088 58 : if ( nSign ) // DM -1
2089 : {
2090 2 : SkipBlanks(rString, nPos);
2091 : }
2092 : }
2093 58 : if ( GetDecSep(rString, nPos) ) // decimal separator follows currency
2094 : {
2095 0 : nDecPos = 1;
2096 0 : SkipBlanks(rString, nPos);
2097 : }
2098 : }
2099 : else
2100 : {
2101 1555 : const sal_Int32 nMonthStart = nPos;
2102 1555 : short nTempMonth = GetMonth(rString, nPos);
2103 1555 : if ( nTempMonth ) // month (Jan 1)?
2104 : {
2105 : // Jan1 without separator is not a date, unless it is followed by a
2106 : // separator and a (year) number.
2107 9 : if (nPos < rString.getLength() || (nAnzStrings >= 4 && nAnzNums >= 2))
2108 : {
2109 8 : eScannedType = css::util::NumberFormat::DATE; // !!! it IS a date !!!
2110 8 : nMonth = nTempMonth;
2111 8 : nMonthPos = 1; // month at the beginning
2112 8 : if ( nMonth < 0 )
2113 : {
2114 6 : SkipChar( '.', rString, nPos ); // abbreviated
2115 : }
2116 8 : SkipBlanks(rString, nPos);
2117 : }
2118 : else
2119 : {
2120 1 : nPos = nMonthStart; // rewind month
2121 : }
2122 : }
2123 : else
2124 : {
2125 1546 : int nDayOfWeek = GetDayOfWeek( rString, nPos );
2126 1546 : if ( nDayOfWeek )
2127 : {
2128 : // day of week is just parsed away
2129 0 : eScannedType = css::util::NumberFormat::DATE; // !!! it IS a date !!!
2130 0 : if ( nPos < rString.getLength() )
2131 : {
2132 0 : if ( nDayOfWeek < 0 )
2133 : {
2134 : // abbreviated
2135 0 : if ( rString[ nPos ] == (sal_Unicode)'.' )
2136 : {
2137 0 : ++nPos;
2138 : }
2139 : }
2140 : else
2141 : {
2142 : // full long name
2143 0 : SkipBlanks(rString, nPos);
2144 0 : SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos );
2145 : }
2146 0 : SkipBlanks(rString, nPos);
2147 0 : nTempMonth = GetMonth(rString, nPos);
2148 0 : if ( nTempMonth ) // month (Jan 1)?
2149 : {
2150 : // Jan1 without separator is not a date, unless it is followed by a
2151 : // separator and a (year) number.
2152 0 : if (nPos < rString.getLength() || (nAnzStrings >= 4 && nAnzNums >= 2))
2153 : {
2154 0 : nMonth = nTempMonth;
2155 0 : nMonthPos = 1; // month a the beginning
2156 0 : if ( nMonth < 0 )
2157 : {
2158 0 : SkipChar( '.', rString, nPos ); // abbreviated
2159 : }
2160 0 : SkipBlanks(rString, nPos);
2161 : }
2162 : else
2163 : {
2164 0 : nPos = nMonthStart; // rewind month
2165 : }
2166 : }
2167 : }
2168 0 : if (!nMonth)
2169 : {
2170 : // Determine and remember following date pattern, if any.
2171 0 : IsAcceptedDatePattern( 1);
2172 : }
2173 : }
2174 : }
2175 : }
2176 :
2177 : // skip any trailing '-' or '/' chars
2178 1613 : if (nPos < rString.getLength())
2179 : {
2180 1585 : while (SkipChar ('-', rString, nPos) || SkipChar ('/', rString, nPos))
2181 : ; // do nothing
2182 : }
2183 1613 : if (nPos < rString.getLength()) // not everything consumed
2184 : {
2185 : // Does input StartString equal StartString of format?
2186 : // This time with sign detection!
2187 1585 : if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) )
2188 : {
2189 1585 : return MatchedReturn();
2190 : }
2191 : }
2192 :
2193 28 : return true;
2194 : }
2195 :
2196 :
2197 : /**
2198 : * Analyze string in the middle
2199 : * All gone => true
2200 : * else => false
2201 : */
2202 2425 : bool ImpSvNumberInputScan::ScanMidString( const OUString& rString,
2203 : sal_uInt16 nStringPos, const SvNumberformat* pFormat )
2204 : {
2205 2425 : sal_Int32 nPos = 0;
2206 2425 : short eOldScannedType = eScannedType;
2207 :
2208 2425 : if ( nMatchedAllStrings )
2209 : { // Match against format in any case, so later on for a "1-2-3-4" input
2210 : // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
2211 : // format.
2212 1727 : if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) )
2213 : {
2214 6 : nMatchedAllStrings |= nMatchedMidString;
2215 : }
2216 : else
2217 : {
2218 1721 : nMatchedAllStrings = 0;
2219 : }
2220 : }
2221 :
2222 2425 : SkipBlanks(rString, nPos);
2223 2425 : if (GetDecSep(rString, nPos)) // decimal separator?
2224 : {
2225 571 : if (nDecPos == 1 || nDecPos == 3) // .12.4 or 1.E2.1
2226 : {
2227 0 : return MatchedReturn();
2228 : }
2229 571 : else if (nDecPos == 2) // . dup: 12.4.
2230 : {
2231 14 : if (bDecSepInDateSeps || // . also date separator
2232 7 : SkipDatePatternSeparator( nStringPos, nPos))
2233 : {
2234 0 : if ( eScannedType != css::util::NumberFormat::UNDEFINED &&
2235 0 : eScannedType != css::util::NumberFormat::DATE &&
2236 0 : eScannedType != css::util::NumberFormat::DATETIME) // already another type
2237 : {
2238 0 : return MatchedReturn();
2239 : }
2240 0 : if (eScannedType == css::util::NumberFormat::UNDEFINED)
2241 : {
2242 0 : eScannedType = css::util::NumberFormat::DATE; // !!! it IS a date
2243 : }
2244 0 : SkipBlanks(rString, nPos);
2245 : }
2246 : else
2247 : {
2248 7 : return MatchedReturn();
2249 : }
2250 : }
2251 : else
2252 : {
2253 564 : nDecPos = 2; // . in mid string
2254 564 : SkipBlanks(rString, nPos);
2255 : }
2256 : }
2257 1862 : else if ( (eScannedType & css::util::NumberFormat::TIME) &&
2258 8 : GetTime100SecSep( rString, nPos ) )
2259 : { // hundredth seconds separator
2260 0 : if ( nDecPos )
2261 : {
2262 0 : return MatchedReturn();
2263 : }
2264 0 : nDecPos = 2; // . in mid string
2265 0 : SkipBlanks(rString, nPos);
2266 : }
2267 :
2268 2418 : if (SkipChar('/', rString, nPos)) // fraction?
2269 : {
2270 21 : if ( eScannedType != css::util::NumberFormat::UNDEFINED && // already another type
2271 7 : eScannedType != css::util::NumberFormat::DATE) // except date
2272 : {
2273 0 : return MatchedReturn(); // => jan/31/1994
2274 : }
2275 21 : else if (eScannedType != css::util::NumberFormat::DATE && // analyzed no date until now
2276 14 : ( eSetType == css::util::NumberFormat::FRACTION || // and preset was fraction
2277 14 : (nAnzNums == 3 && // or 3 numbers
2278 7 : (nStringPos == 3 || // and 3rd string particle
2279 0 : (nStringPos == 4 && nSign))))) // or 4th if signed
2280 : {
2281 0 : SkipBlanks(rString, nPos);
2282 0 : if (nPos == rString.getLength())
2283 : {
2284 0 : eScannedType = css::util::NumberFormat::FRACTION; // !!! it IS a fraction (so far)
2285 0 : if (eSetType == css::util::NumberFormat::FRACTION &&
2286 0 : nAnzNums == 2 &&
2287 0 : (nStringPos == 1 || // for 4/5
2288 0 : (nStringPos == 2 && nSign))) // or signed -4/5
2289 : {
2290 0 : return true; // don't fall into date trap
2291 : }
2292 : }
2293 : }
2294 : else
2295 : {
2296 14 : nPos--; // put '/' back
2297 : }
2298 : }
2299 :
2300 2418 : if (GetThousandSep(rString, nPos, nStringPos)) // 1,000
2301 : {
2302 3 : if ( eScannedType != css::util::NumberFormat::UNDEFINED && // already another type
2303 0 : eScannedType != css::util::NumberFormat::CURRENCY) // except currency
2304 : {
2305 0 : return MatchedReturn();
2306 : }
2307 3 : nThousand++;
2308 : }
2309 :
2310 2418 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
2311 2418 : bool bDate = SkipDatePatternSeparator( nStringPos, nPos); // 12/31 31.12. 12/31/1999 31.12.1999
2312 2418 : if (!bDate)
2313 : {
2314 2404 : const OUString& rDate = pFormatter->GetDateSep();
2315 2404 : SkipBlanks(rString, nPos);
2316 2404 : bDate = SkipString( rDate, rString, nPos); // 10. 10- 10/
2317 : }
2318 3726 : if (bDate || ((MayBeIso8601() || MayBeMonthDate()) && // 1999-12-31 31-Dec-1999
2319 1308 : SkipChar( '-', rString, nPos)))
2320 : {
2321 1947 : if ( eScannedType != css::util::NumberFormat::UNDEFINED && // already another type
2322 649 : eScannedType != css::util::NumberFormat::DATE) // except date
2323 : {
2324 0 : return MatchedReturn();
2325 : }
2326 1298 : SkipBlanks(rString, nPos);
2327 1298 : eScannedType = css::util::NumberFormat::DATE; // !!! it IS a date
2328 1298 : short nTmpMonth = GetMonth(rString, nPos); // 10. Jan 94
2329 1298 : if (nMonth && nTmpMonth) // month dup
2330 : {
2331 0 : return MatchedReturn();
2332 : }
2333 1298 : if (nTmpMonth)
2334 : {
2335 0 : nMonth = nTmpMonth;
2336 0 : nMonthPos = 2; // month in the middle
2337 0 : if ( nMonth < 0 && SkipChar( '.', rString, nPos ) )
2338 : ; // short month may be abbreviated Jan.
2339 0 : else if ( SkipChar( '-', rString, nPos ) )
2340 : ; // #79632# recognize 17-Jan-2001 to be a date
2341 : // #99065# short and long month name
2342 : else
2343 : {
2344 0 : SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
2345 : }
2346 0 : SkipBlanks(rString, nPos);
2347 : }
2348 : }
2349 :
2350 2418 : const sal_Int32 nMonthStart = nPos;
2351 2418 : short nTempMonth = GetMonth(rString, nPos); // month in the middle (10 Jan 94)
2352 2418 : if (nTempMonth)
2353 : {
2354 442 : if (nMonth != 0) // month dup
2355 : {
2356 0 : return MatchedReturn();
2357 : }
2358 442 : if ( eScannedType != css::util::NumberFormat::UNDEFINED && // already another type
2359 0 : eScannedType != css::util::NumberFormat::DATE) // except date
2360 : {
2361 0 : return MatchedReturn();
2362 : }
2363 442 : if (nMonthStart > 0 && nPos < rString.getLength()) // 10Jan or Jan94 without separator are not dates
2364 : {
2365 442 : eScannedType = css::util::NumberFormat::DATE; // !!! it IS a date
2366 442 : nMonth = nTempMonth;
2367 442 : nMonthPos = 2; // month in the middle
2368 442 : if ( nMonth < 0 )
2369 : {
2370 222 : SkipChar( '.', rString, nPos ); // abbreviated
2371 : }
2372 442 : SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
2373 442 : SkipBlanks(rString, nPos);
2374 : }
2375 : else
2376 : {
2377 0 : nPos = nMonthStart; // rewind month
2378 : }
2379 : }
2380 :
2381 4836 : if ( SkipChar('E', rString, nPos) || // 10E, 10e, 10,Ee
2382 2418 : SkipChar('e', rString, nPos) )
2383 : {
2384 0 : if (eScannedType != css::util::NumberFormat::UNDEFINED) // already another type
2385 : {
2386 0 : return MatchedReturn();
2387 : }
2388 : else
2389 : {
2390 0 : SkipBlanks(rString, nPos);
2391 0 : eScannedType = css::util::NumberFormat::SCIENTIFIC; // !!! it IS scientific
2392 0 : if ( nThousand+2 == nAnzNums && nDecPos == 2 ) // special case 1.E2
2393 : {
2394 0 : nDecPos = 3; // 1,100.E2 1,100,100.E3
2395 : }
2396 : }
2397 0 : nESign = GetESign(rString, nPos); // signed exponent?
2398 0 : SkipBlanks(rString, nPos);
2399 : }
2400 :
2401 2418 : const OUString& rTime = pLoc->getTimeSep();
2402 2418 : if ( SkipString(rTime, rString, nPos) ) // time separator?
2403 : {
2404 62 : if (nDecPos) // already . => maybe error
2405 : {
2406 0 : if (bDecSepInDateSeps) // . also date sep
2407 : {
2408 0 : if ( eScannedType != css::util::NumberFormat::DATE && // already another type than date
2409 0 : eScannedType != css::util::NumberFormat::DATETIME) // or date time
2410 : {
2411 0 : return MatchedReturn();
2412 : }
2413 0 : if (eScannedType == css::util::NumberFormat::DATE)
2414 : {
2415 0 : nDecPos = 0; // reset for time transition
2416 : }
2417 : }
2418 : else
2419 : {
2420 0 : return MatchedReturn();
2421 : }
2422 : }
2423 116 : if ((eScannedType == css::util::NumberFormat::DATE || // already date type
2424 70 : eScannedType == css::util::NumberFormat::DATETIME) && // or date time
2425 16 : nAnzNums > 3) // and more than 3 numbers? (31.Dez.94 8:23)
2426 : {
2427 16 : SkipBlanks(rString, nPos);
2428 16 : eScannedType = css::util::NumberFormat::DATETIME; // !!! it IS date with time
2429 : }
2430 46 : else if ( eScannedType != css::util::NumberFormat::UNDEFINED && // already another type
2431 0 : eScannedType != css::util::NumberFormat::TIME) // except time
2432 : {
2433 0 : return MatchedReturn();
2434 : }
2435 : else
2436 : {
2437 46 : SkipBlanks(rString, nPos);
2438 46 : eScannedType = css::util::NumberFormat::TIME; // !!! it IS a time
2439 : }
2440 62 : if ( !nTimePos )
2441 : {
2442 54 : nTimePos = nStringPos + 1;
2443 : }
2444 : }
2445 :
2446 2418 : if (nPos < rString.getLength())
2447 : {
2448 38 : switch (eScannedType)
2449 : {
2450 : case css::util::NumberFormat::DATE:
2451 5 : if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY)
2452 : {
2453 : // #68232# recognize long date separators like ", " in "September 5, 1999"
2454 4 : if (SkipString( pLoc->getLongDateDaySep(), rString, nPos ))
2455 : {
2456 4 : SkipBlanks( rString, nPos );
2457 : }
2458 : }
2459 1 : else if (nPos == 0 && rString.getLength() == 1 && MayBeIso8601())
2460 : {
2461 0 : if (nStringPos == 5 && rString[0] == 'T')
2462 : {
2463 : // ISO 8601 combined date and time, yyyy-mm-ddThh:mm
2464 0 : ++nPos;
2465 : }
2466 0 : else if (nStringPos == 7 && rString[0] == ':')
2467 : {
2468 : // ISO 8601 combined date and time, the time part; we reach
2469 : // here if the locale's separator is not ':' so it couldn't
2470 : // be detected above in the time block.
2471 0 : if (nAnzNums >= 5)
2472 0 : eScannedType = css::util::NumberFormat::DATETIME;
2473 0 : ++nPos;
2474 : }
2475 : }
2476 5 : break;
2477 : case css::util::NumberFormat::DATETIME:
2478 0 : if (nPos == 0 && rString.getLength() == 1 && MayBeIso8601())
2479 : {
2480 0 : if (nStringPos == 9 && rString[0] == ':')
2481 : {
2482 : // ISO 8601 combined date and time, the time part continued.
2483 0 : ++nPos;
2484 : }
2485 : }
2486 : #if NF_RECOGNIZE_ISO8601_TIMEZONES
2487 : else if (nPos == 0 && rString.getLength() == 1 && nStringPos >= 9 && MayBeIso8601())
2488 : {
2489 : // ISO 8601 timezone offset
2490 : switch (rString[ 0 ])
2491 : {
2492 : case '+':
2493 : case '-':
2494 : if (nStringPos == nAnzStrings - 2 ||
2495 : nStringPos == nAnzStrings - 4)
2496 : {
2497 : ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy]
2498 : // nTimezonePos needed for GetTimeRef()
2499 : if (!nTimezonePos)
2500 : {
2501 : nTimezonePos = nStringPos + 1;
2502 : }
2503 : }
2504 : break;
2505 : case ':':
2506 : if (nTimezonePos && nStringPos >= 11 &&
2507 : nStringPos == nAnzStrings - 2)
2508 : {
2509 : ++nPos; // yyyy-mm-ddThh:mm[:ss]+xx:yy
2510 : }
2511 : break;
2512 : }
2513 : }
2514 : #endif
2515 0 : break;
2516 : }
2517 : }
2518 :
2519 2418 : if (nPos < rString.getLength()) // not everything consumed?
2520 : {
2521 34 : if ( nMatchedAllStrings & ~nMatchedVirgin )
2522 : {
2523 0 : eScannedType = eOldScannedType;
2524 : }
2525 : else
2526 : {
2527 34 : return false;
2528 : }
2529 : }
2530 :
2531 2384 : return true;
2532 : }
2533 :
2534 :
2535 : /**
2536 : * Analyze the end
2537 : * All gone => true
2538 : * else => false
2539 : */
2540 499 : bool ImpSvNumberInputScan::ScanEndString( const OUString& rString,
2541 : const SvNumberformat* pFormat )
2542 : {
2543 499 : sal_Int32 nPos = 0;
2544 :
2545 499 : if ( nMatchedAllStrings )
2546 : { // Match against format in any case, so later on for a "1-2-3-4" input
2547 : // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
2548 : // format.
2549 9 : if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) )
2550 : {
2551 0 : nMatchedAllStrings |= nMatchedEndString;
2552 : }
2553 : else
2554 : {
2555 9 : nMatchedAllStrings = 0;
2556 : }
2557 : }
2558 :
2559 499 : SkipBlanks(rString, nPos);
2560 499 : if (GetDecSep(rString, nPos)) // decimal separator?
2561 : {
2562 0 : if (nDecPos == 1 || nDecPos == 3) // .12.4 or 12.E4.
2563 : {
2564 0 : return MatchedReturn();
2565 : }
2566 0 : else if (nDecPos == 2) // . dup: 12.4.
2567 : {
2568 0 : if (bDecSepInDateSeps || // . also date separator
2569 0 : SkipDatePatternSeparator( nAnzStrings-1, nPos))
2570 : {
2571 0 : if ( eScannedType != css::util::NumberFormat::UNDEFINED &&
2572 0 : eScannedType != css::util::NumberFormat::DATE &&
2573 0 : eScannedType != css::util::NumberFormat::DATETIME) // already another type
2574 : {
2575 0 : return MatchedReturn();
2576 : }
2577 0 : if (eScannedType == css::util::NumberFormat::UNDEFINED)
2578 : {
2579 0 : eScannedType = css::util::NumberFormat::DATE; // !!! it IS a date
2580 : }
2581 0 : SkipBlanks(rString, nPos);
2582 : }
2583 : else
2584 : {
2585 0 : return MatchedReturn();
2586 : }
2587 : }
2588 : else
2589 : {
2590 0 : nDecPos = 3; // . in end string
2591 0 : SkipBlanks(rString, nPos);
2592 : }
2593 : }
2594 :
2595 499 : bool bSignDetectedHere = false;
2596 998 : if ( nSign == 0 && // conflict - not signed
2597 499 : eScannedType != css::util::NumberFormat::DATE) // and not date
2598 : //!? catch time too?
2599 : { // not signed yet
2600 57 : nSign = GetSign(rString, nPos); // 1- DM
2601 57 : if (nNegCheck) // '(' as sign
2602 : {
2603 0 : return MatchedReturn();
2604 : }
2605 57 : if (nSign)
2606 : {
2607 0 : bSignDetectedHere = true;
2608 : }
2609 : }
2610 :
2611 499 : SkipBlanks(rString, nPos);
2612 499 : if (nNegCheck && SkipChar(')', rString, nPos)) // skip ')' if appropriate
2613 : {
2614 0 : nNegCheck = 0;
2615 0 : SkipBlanks(rString, nPos);
2616 : }
2617 :
2618 499 : if ( GetCurrency(rString, nPos, pFormat) ) // currency symbol?
2619 : {
2620 0 : if (eScannedType != css::util::NumberFormat::UNDEFINED) // currency dup
2621 : {
2622 0 : return MatchedReturn();
2623 : }
2624 : else
2625 : {
2626 0 : SkipBlanks(rString, nPos);
2627 0 : eScannedType = css::util::NumberFormat::CURRENCY;
2628 : } // behind currency a '-' is allowed
2629 0 : if (nSign == 0) // not signed yet
2630 : {
2631 0 : nSign = GetSign(rString, nPos); // DM -
2632 0 : SkipBlanks(rString, nPos);
2633 0 : if (nNegCheck) // 3 DM (
2634 : {
2635 0 : return MatchedReturn();
2636 : }
2637 : }
2638 0 : if ( nNegCheck && eScannedType == css::util::NumberFormat::CURRENCY &&
2639 0 : SkipChar(')', rString, nPos) )
2640 : {
2641 0 : nNegCheck = 0; // ')' skipped
2642 0 : SkipBlanks(rString, nPos); // only if currency
2643 : }
2644 : }
2645 :
2646 499 : if ( SkipChar('%', rString, nPos) ) // 1%
2647 : {
2648 0 : if (eScannedType != css::util::NumberFormat::UNDEFINED) // already another type
2649 : {
2650 0 : return MatchedReturn();
2651 : }
2652 0 : SkipBlanks(rString, nPos);
2653 0 : eScannedType = css::util::NumberFormat::PERCENT;
2654 : }
2655 :
2656 499 : const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
2657 499 : const OUString& rTime = pLoc->getTimeSep();
2658 499 : if ( SkipString(rTime, rString, nPos) ) // 10:
2659 : {
2660 0 : if (nDecPos) // already , => error
2661 : {
2662 0 : return MatchedReturn();
2663 : }
2664 0 : if (eScannedType == css::util::NumberFormat::DATE && nAnzNums > 2) // 31.Dez.94 8:
2665 : {
2666 0 : SkipBlanks(rString, nPos);
2667 0 : eScannedType = css::util::NumberFormat::DATETIME;
2668 : }
2669 0 : else if (eScannedType != css::util::NumberFormat::UNDEFINED &&
2670 0 : eScannedType != css::util::NumberFormat::TIME) // already another type
2671 : {
2672 0 : return MatchedReturn();
2673 : }
2674 : else
2675 : {
2676 0 : SkipBlanks(rString, nPos);
2677 0 : eScannedType = css::util::NumberFormat::TIME;
2678 : }
2679 0 : if ( !nTimePos )
2680 : {
2681 0 : nTimePos = nAnzStrings;
2682 : }
2683 : }
2684 :
2685 499 : bool bDate = SkipDatePatternSeparator( nAnzStrings-1, nPos); // 12/31 31.12. 12/31/1999 31.12.1999
2686 499 : if (!bDate)
2687 : {
2688 499 : const OUString& rDate = pFormatter->GetDateSep();
2689 499 : bDate = SkipString( rDate, rString, nPos); // 10. 10- 10/
2690 : }
2691 499 : if (bDate && bSignDetectedHere)
2692 : {
2693 0 : nSign = 0; // 'D-' takes precedence over signed date
2694 : }
2695 499 : if (bDate || ((MayBeIso8601() || MayBeMonthDate())
2696 0 : && SkipChar( '-', rString, nPos)))
2697 : {
2698 0 : if (eScannedType != css::util::NumberFormat::UNDEFINED &&
2699 0 : eScannedType != css::util::NumberFormat::DATE) // already another type
2700 : {
2701 0 : return MatchedReturn();
2702 : }
2703 : else
2704 : {
2705 0 : SkipBlanks(rString, nPos);
2706 0 : eScannedType = css::util::NumberFormat::DATE;
2707 : }
2708 0 : short nTmpMonth = GetMonth(rString, nPos); // 10. Jan
2709 0 : if (nMonth && nTmpMonth) // month dup
2710 : {
2711 0 : return MatchedReturn();
2712 : }
2713 0 : if (nTmpMonth)
2714 : {
2715 0 : nMonth = nTmpMonth;
2716 0 : nMonthPos = 3; // month at end
2717 0 : if ( nMonth < 0 )
2718 : {
2719 0 : SkipChar( '.', rString, nPos ); // abbreviated
2720 : }
2721 0 : SkipBlanks(rString, nPos);
2722 : }
2723 : }
2724 :
2725 499 : const sal_Int32 nMonthStart = nPos;
2726 499 : short nTempMonth = GetMonth(rString, nPos); // 10 Jan
2727 499 : if (nTempMonth)
2728 : {
2729 0 : if (nMonth) // month dup
2730 : {
2731 0 : return MatchedReturn();
2732 : }
2733 0 : if (eScannedType != css::util::NumberFormat::UNDEFINED &&
2734 0 : eScannedType != css::util::NumberFormat::DATE) // already another type
2735 : {
2736 0 : return MatchedReturn();
2737 : }
2738 0 : if (nMonthStart > 0) // 10Jan without separator is not a date
2739 : {
2740 0 : eScannedType = css::util::NumberFormat::DATE;
2741 0 : nMonth = nTempMonth;
2742 0 : nMonthPos = 3; // month at end
2743 0 : if ( nMonth < 0 )
2744 : {
2745 0 : SkipChar( '.', rString, nPos ); // abbreviated
2746 : }
2747 0 : SkipBlanks(rString, nPos);
2748 : }
2749 : else
2750 : {
2751 0 : nPos = nMonthStart; // rewind month
2752 : }
2753 : }
2754 :
2755 499 : sal_Int32 nOrigPos = nPos;
2756 499 : if (GetTimeAmPm(rString, nPos))
2757 : {
2758 92 : if (eScannedType != css::util::NumberFormat::UNDEFINED &&
2759 46 : eScannedType != css::util::NumberFormat::TIME &&
2760 0 : eScannedType != css::util::NumberFormat::DATETIME) // already another type
2761 : {
2762 0 : return MatchedReturn();
2763 : }
2764 : else
2765 : {
2766 : // If not already scanned as time, 6.78am does not result in 6
2767 : // seconds and 78 hundredths in the morning. Keep as suffix.
2768 46 : if (eScannedType != css::util::NumberFormat::TIME && nDecPos == 2 && nAnzNums == 2)
2769 : {
2770 0 : nPos = nOrigPos; // rewind am/pm
2771 : }
2772 : else
2773 : {
2774 46 : SkipBlanks(rString, nPos);
2775 46 : if ( eScannedType != css::util::NumberFormat::DATETIME )
2776 : {
2777 46 : eScannedType = css::util::NumberFormat::TIME;
2778 : }
2779 : }
2780 : }
2781 : }
2782 :
2783 499 : if ( nNegCheck && SkipChar(')', rString, nPos) )
2784 : {
2785 0 : if (eScannedType == css::util::NumberFormat::CURRENCY) // only if currency
2786 : {
2787 0 : nNegCheck = 0; // skip ')'
2788 0 : SkipBlanks(rString, nPos);
2789 : }
2790 : else
2791 : {
2792 0 : return MatchedReturn();
2793 : }
2794 : }
2795 :
2796 1392 : if ( nPos < rString.getLength() &&
2797 460 : (eScannedType == css::util::NumberFormat::DATE ||
2798 9 : eScannedType == css::util::NumberFormat::DATETIME) )
2799 : {
2800 : // day of week is just parsed away
2801 442 : sal_Int32 nOldPos = nPos;
2802 442 : const OUString& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep();
2803 442 : if ( StringContains( rSep, rString, nPos ) )
2804 : {
2805 0 : nPos = nPos + rSep.getLength();
2806 0 : SkipBlanks(rString, nPos);
2807 : }
2808 442 : int nDayOfWeek = GetDayOfWeek( rString, nPos );
2809 442 : if ( nDayOfWeek )
2810 : {
2811 0 : if ( nPos < rString.getLength() )
2812 : {
2813 0 : if ( nDayOfWeek < 0 )
2814 : { // short
2815 0 : if ( rString[ nPos ] == (sal_Unicode)'.' )
2816 : {
2817 0 : ++nPos;
2818 : }
2819 : }
2820 0 : SkipBlanks(rString, nPos);
2821 : }
2822 : }
2823 : else
2824 : {
2825 442 : nPos = nOldPos;
2826 : }
2827 : }
2828 :
2829 : #if NF_RECOGNIZE_ISO8601_TIMEZONES
2830 : if (nPos == 0 && eScannedType == css::util::NumberFormat::DATETIME &&
2831 : rString.getLength() == 1 && rString[ 0 ] == (sal_Unicode)'Z' && MayBeIso8601())
2832 : {
2833 : // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ
2834 : ++nPos;
2835 : }
2836 : #endif
2837 :
2838 499 : if (nPos < rString.getLength()) // everything consumed?
2839 : {
2840 : // does input EndString equal EndString in Format?
2841 451 : if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) )
2842 : {
2843 451 : return false;
2844 : }
2845 : }
2846 :
2847 48 : return true;
2848 : }
2849 :
2850 :
2851 5377 : bool ImpSvNumberInputScan::ScanStringNumFor( const OUString& rString, // String to scan
2852 : sal_Int32 nPos, // Position until which was consumed
2853 : const SvNumberformat* pFormat, // The format to match
2854 : sal_uInt16 nString, // Substring of format, 0xFFFF => last
2855 : bool bDontDetectNegation) // Suppress sign detection
2856 : {
2857 5377 : if ( !pFormat )
2858 : {
2859 16 : return false;
2860 : }
2861 5361 : const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration();
2862 : const OUString* pStr;
2863 5361 : OUString aString( rString );
2864 5361 : bool bFound = false;
2865 5361 : bool bFirst = true;
2866 5361 : bool bContinue = true;
2867 : sal_uInt16 nSub;
2868 6084 : do
2869 : {
2870 : // Don't try "lower" subformats ff the very first match was the second
2871 : // or third subformat.
2872 6084 : nSub = nStringScanNumFor;
2873 18240 : do
2874 : { // Step through subformats, first positive, then negative, then
2875 : // other, but not the last (text) subformat.
2876 18240 : pStr = pFormat->GetNumForString( nSub, nString, true );
2877 18240 : if ( pStr && pTransliteration->isEqual( aString, *pStr ) )
2878 : {
2879 6 : bFound = true;
2880 6 : bContinue = false;
2881 : }
2882 18234 : else if ( nSub < 2 )
2883 : {
2884 12156 : ++nSub;
2885 : }
2886 : else
2887 : {
2888 6078 : bContinue = false;
2889 : }
2890 : }
2891 : while ( bContinue );
2892 6084 : if ( !bFound && bFirst && nPos )
2893 : {
2894 : // try remaining substring
2895 723 : bFirst = false;
2896 723 : aString = aString.copy(nPos);
2897 723 : bContinue = true;
2898 : }
2899 : }
2900 : while ( bContinue );
2901 :
2902 5361 : if ( !bFound )
2903 : {
2904 16045 : if ( !bDontDetectNegation && (nString == 0) &&
2905 7082 : !bFirst && (nSign < 0) && pFormat->IsSecondSubformatRealNegative() )
2906 : {
2907 : // simply negated twice? --1
2908 88 : aString = comphelper::string::remove(aString, ' ');
2909 88 : if ( (aString.getLength() == 1) && (aString[0] == '-') )
2910 : {
2911 0 : bFound = true;
2912 0 : nStringScanSign = -1;
2913 0 : nSub = 0; //! not 1
2914 : }
2915 : }
2916 5355 : if ( !bFound )
2917 : {
2918 5355 : return false;
2919 : }
2920 : }
2921 6 : else if ( !bDontDetectNegation && (nSub == 1) &&
2922 0 : pFormat->IsSecondSubformatRealNegative() )
2923 : {
2924 : // negative
2925 0 : if ( nStringScanSign < 0 )
2926 : {
2927 0 : if ( (nSign < 0) && (nStringScanNumFor != 1) )
2928 : {
2929 0 : nStringScanSign = 1; // triple negated --1 yyy
2930 : }
2931 : }
2932 0 : else if ( nStringScanSign == 0 )
2933 : {
2934 0 : if ( nSign < 0 )
2935 : { // nSign and nStringScanSign will be combined later,
2936 : // flip sign if doubly negated
2937 0 : if ( (nString == 0) && !bFirst &&
2938 0 : SvNumberformat::HasStringNegativeSign( aString ) )
2939 : {
2940 0 : nStringScanSign = -1; // direct double negation
2941 : }
2942 0 : else if ( pFormat->IsNegativeWithoutSign() )
2943 : {
2944 0 : nStringScanSign = -1; // indirect double negation
2945 : }
2946 : }
2947 : else
2948 : {
2949 0 : nStringScanSign = -1;
2950 : }
2951 : }
2952 : else // > 0
2953 : {
2954 0 : nStringScanSign = -1;
2955 : }
2956 : }
2957 6 : nStringScanNumFor = nSub;
2958 6 : return true;
2959 : }
2960 :
2961 :
2962 : /**
2963 : * Recognizes types of number, exponential, fraction, percent, currency, date, time.
2964 : * Else text => return false
2965 : */
2966 11339 : bool ImpSvNumberInputScan::IsNumberFormatMain( const OUString& rString, // string to be analyzed
2967 : const SvNumberformat* pFormat ) // maybe number format set to match against
2968 : {
2969 11339 : Reset();
2970 11339 : NumberStringDivision( rString ); // breakdown into strings and numbers
2971 11339 : if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements
2972 : {
2973 0 : return false; // Njet, Nope, ...
2974 : }
2975 11339 : if (nAnzNums == 0) // no number in input
2976 : {
2977 4000 : if ( nAnzStrings > 0 )
2978 : {
2979 : // Here we may change the original, we don't need it anymore.
2980 : // This saves copies and ToUpper() in GetLogical() and is faster.
2981 4000 : sStrArray[0] = comphelper::string::strip(sStrArray[0], ' ');
2982 4000 : OUString& rStrArray = sStrArray[0];
2983 4000 : nLogical = GetLogical( rStrArray );
2984 4000 : if ( nLogical )
2985 : {
2986 0 : eScannedType = css::util::NumberFormat::LOGICAL; // !!! it's a BOOLEAN
2987 0 : nMatchedAllStrings &= ~nMatchedVirgin;
2988 0 : return true;
2989 : }
2990 : else
2991 : {
2992 4000 : return false; // simple text
2993 : }
2994 : }
2995 : else
2996 : {
2997 0 : return false; // simple text
2998 : }
2999 : }
3000 :
3001 7339 : sal_uInt16 i = 0; // mark any symbol
3002 7339 : sal_uInt16 j = 0; // mark only numbers
3003 :
3004 7339 : switch ( nAnzNums )
3005 : {
3006 : case 1 : // Exactly 1 number in input
3007 : // nAnzStrings >= 1
3008 5457 : if (GetNextNumber(i,j)) // i=1,0
3009 : { // Number at start
3010 4004 : if (eSetType == css::util::NumberFormat::FRACTION) // Fraction 1 = 1/1
3011 : {
3012 0 : if (i >= nAnzStrings || // no end string nor decimal separator
3013 0 : sStrArray[i] == pFormatter->GetNumDecimalSep())
3014 : {
3015 0 : eScannedType = css::util::NumberFormat::FRACTION;
3016 0 : nMatchedAllStrings &= ~nMatchedVirgin;
3017 0 : return true;
3018 : }
3019 : }
3020 : }
3021 : else
3022 : { // Analyze start string
3023 1453 : if (!ScanStartString( sStrArray[i], pFormat )) // i=0
3024 : {
3025 1444 : return false; // already an error
3026 : }
3027 9 : i++; // next symbol, i=1
3028 : }
3029 4013 : GetNextNumber(i,j); // i=1,2
3030 4013 : if (eSetType == css::util::NumberFormat::FRACTION) // Fraction -1 = -1/1
3031 : {
3032 0 : if (nSign && !nNegCheck && // Sign +, -
3033 0 : eScannedType == css::util::NumberFormat::UNDEFINED && // not date or currency
3034 0 : nDecPos == 0 && // no previous decimal separator
3035 0 : (i >= nAnzStrings || // no end string nor decimal separator
3036 0 : sStrArray[i] == pFormatter->GetNumDecimalSep())
3037 : )
3038 : {
3039 0 : eScannedType = css::util::NumberFormat::FRACTION;
3040 0 : nMatchedAllStrings &= ~nMatchedVirgin;
3041 0 : return true;
3042 : }
3043 : }
3044 4013 : if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
3045 : {
3046 9 : return false;
3047 : }
3048 4004 : break;
3049 : case 2 : // Exactly 2 numbers in input
3050 : // nAnzStrings >= 3
3051 1141 : if (!GetNextNumber(i,j)) // i=1,0
3052 : { // Analyze start string
3053 107 : if (!ScanStartString( sStrArray[i], pFormat ))
3054 88 : return false; // already an error
3055 19 : i++; // i=1
3056 : }
3057 1053 : GetNextNumber(i,j); // i=1,2
3058 1053 : if ( !ScanMidString( sStrArray[i], i, pFormat ) )
3059 : {
3060 5 : return false;
3061 : }
3062 1048 : i++; // next symbol, i=2,3
3063 1048 : GetNextNumber(i,j); // i=3,4
3064 1048 : if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
3065 : {
3066 442 : return false;
3067 : }
3068 606 : if (eSetType == css::util::NumberFormat::FRACTION) // -1,200. as fraction
3069 : {
3070 0 : if (!nNegCheck && // no sign '('
3071 0 : eScannedType == css::util::NumberFormat::UNDEFINED &&
3072 0 : (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
3073 : )
3074 : {
3075 0 : eScannedType = css::util::NumberFormat::FRACTION;
3076 0 : nMatchedAllStrings &= ~nMatchedVirgin;
3077 0 : return true;
3078 : }
3079 : }
3080 606 : break;
3081 : case 3 : // Exactly 3 numbers in input
3082 : // nAnzStrings >= 5
3083 702 : if (!GetNextNumber(i,j)) // i=1,0
3084 : { // Analyze start string
3085 35 : if (!ScanStartString( sStrArray[i], pFormat ))
3086 : {
3087 35 : return false; // already an error
3088 : }
3089 0 : i++; // i=1
3090 0 : if (nDecPos == 1) // decimal separator at start => error
3091 : {
3092 0 : return false;
3093 : }
3094 : }
3095 667 : GetNextNumber(i,j); // i=1,2
3096 667 : if ( !ScanMidString( sStrArray[i], i, pFormat ) )
3097 : {
3098 16 : return false;
3099 : }
3100 651 : i++; // i=2,3
3101 651 : if (eScannedType == css::util::NumberFormat::SCIENTIFIC) // E only at end
3102 : {
3103 0 : return false;
3104 : }
3105 651 : GetNextNumber(i,j); // i=3,4
3106 651 : if ( !ScanMidString( sStrArray[i], i, pFormat ) )
3107 : {
3108 7 : return false;
3109 : }
3110 644 : i++; // i=4,5
3111 644 : GetNextNumber(i,j); // i=5,6
3112 644 : if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
3113 : {
3114 0 : return false;
3115 : }
3116 644 : if (eSetType == css::util::NumberFormat::FRACTION) // -1,200,100. as fraction
3117 : {
3118 0 : if (!nNegCheck && // no sign '('
3119 0 : eScannedType == css::util::NumberFormat::UNDEFINED &&
3120 0 : (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
3121 : )
3122 : {
3123 0 : eScannedType = css::util::NumberFormat::FRACTION;
3124 0 : nMatchedAllStrings &= ~nMatchedVirgin;
3125 0 : return true;
3126 : }
3127 : }
3128 644 : if ( eScannedType == css::util::NumberFormat::FRACTION && nDecPos )
3129 : {
3130 0 : return false; // #36857# not a real fraction
3131 : }
3132 644 : break;
3133 : default: // More than 3 numbers in input
3134 : // nAnzStrings >= 7
3135 39 : if (!GetNextNumber(i,j)) // i=1,0
3136 : { // Analyze startstring
3137 18 : if (!ScanStartString( sStrArray[i], pFormat ))
3138 18 : return false; // already an error
3139 0 : i++; // i=1
3140 0 : if (nDecPos == 1) // decimal separator at start => error
3141 0 : return false;
3142 : }
3143 21 : GetNextNumber(i,j); // i=1,2
3144 21 : if ( !ScanMidString( sStrArray[i], i, pFormat ) )
3145 : {
3146 12 : return false;
3147 : }
3148 9 : i++; // i=2,3
3149 : {
3150 9 : sal_uInt16 nThOld = 10; // just not 0 or 1
3151 26 : while (nThOld != nThousand && j < nAnzNums-1) // Execute at least one time
3152 : // but leave one number.
3153 : { // Loop over group separators
3154 9 : nThOld = nThousand;
3155 9 : if (eScannedType == css::util::NumberFormat::SCIENTIFIC) // E only at end
3156 : {
3157 0 : return false;
3158 : }
3159 9 : GetNextNumber(i,j);
3160 9 : if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
3161 : {
3162 1 : return false;
3163 : }
3164 8 : i++;
3165 : }
3166 : }
3167 8 : if (eScannedType == css::util::NumberFormat::DATE || // long date or
3168 0 : eScannedType == css::util::NumberFormat::TIME || // long time or
3169 0 : eScannedType == css::util::NumberFormat::UNDEFINED) // long number
3170 : {
3171 32 : for (sal_uInt16 k = j; k < nAnzNums-1; k++)
3172 : {
3173 24 : if (eScannedType == css::util::NumberFormat::SCIENTIFIC) // E only at endd
3174 : {
3175 0 : return false;
3176 : }
3177 24 : GetNextNumber(i,j);
3178 24 : if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
3179 : {
3180 0 : return false;
3181 : }
3182 24 : i++;
3183 : }
3184 : }
3185 8 : GetNextNumber(i,j);
3186 8 : if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
3187 : {
3188 0 : return false;
3189 : }
3190 8 : if (eSetType == css::util::NumberFormat::FRACTION) // -1,200,100. as fraction
3191 : {
3192 0 : if (!nNegCheck && // no sign '('
3193 0 : eScannedType == css::util::NumberFormat::UNDEFINED &&
3194 0 : (nDecPos == 0 || nDecPos == 3) // no decimal separator or at end
3195 : )
3196 : {
3197 0 : eScannedType = css::util::NumberFormat::FRACTION;
3198 0 : nMatchedAllStrings &= ~nMatchedVirgin;
3199 0 : return true;
3200 : }
3201 : }
3202 8 : if ( eScannedType == css::util::NumberFormat::FRACTION && nDecPos )
3203 : {
3204 0 : return false; // #36857# not a real fraction
3205 : }
3206 8 : break;
3207 : }
3208 :
3209 5262 : if (eScannedType == css::util::NumberFormat::UNDEFINED)
3210 : {
3211 4550 : nMatchedAllStrings &= ~nMatchedVirgin;
3212 : // did match including nMatchedUsedAsReturn
3213 4550 : bool bDidMatch = (nMatchedAllStrings != 0);
3214 4550 : if ( nMatchedAllStrings )
3215 : {
3216 0 : bool bMatch = pFormat && pFormat->IsNumForStringElementCountEqual(
3217 0 : nStringScanNumFor, nAnzStrings, nAnzNums );
3218 0 : if ( !bMatch )
3219 : {
3220 0 : nMatchedAllStrings = 0;
3221 : }
3222 : }
3223 4550 : if ( nMatchedAllStrings )
3224 : {
3225 0 : eScannedType = eSetType;
3226 : }
3227 4550 : else if ( bDidMatch )
3228 : {
3229 0 : return false;
3230 : }
3231 : else
3232 : {
3233 4550 : eScannedType = css::util::NumberFormat::NUMBER;
3234 : // everything else should have been recognized by now
3235 : }
3236 : }
3237 712 : else if ( eScannedType == css::util::NumberFormat::DATE )
3238 : {
3239 : // the very relaxed date input checks may interfere with a preset format
3240 648 : nMatchedAllStrings &= ~nMatchedVirgin;
3241 648 : bool bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0);
3242 648 : if ( nMatchedAllStrings )
3243 : {
3244 6 : bool bMatch = pFormat && pFormat->IsNumForStringElementCountEqual(
3245 6 : nStringScanNumFor, nAnzStrings, nAnzNums );
3246 3 : if ( !bMatch )
3247 : {
3248 0 : nMatchedAllStrings = 0;
3249 : }
3250 : }
3251 648 : if ( nMatchedAllStrings )
3252 : {
3253 3 : eScannedType = eSetType;
3254 : }
3255 645 : else if ( bWasReturn )
3256 : {
3257 0 : return false;
3258 : }
3259 : }
3260 : else
3261 : {
3262 64 : nMatchedAllStrings = 0; // reset flag to no substrings matched
3263 : }
3264 5262 : return true;
3265 : }
3266 :
3267 :
3268 : /**
3269 : * Return true or false depending on the nMatched... state and remember usage
3270 : */
3271 1592 : bool ImpSvNumberInputScan::MatchedReturn()
3272 : {
3273 1592 : if ( nMatchedAllStrings & ~nMatchedVirgin )
3274 : {
3275 0 : nMatchedAllStrings |= nMatchedUsedAsReturn;
3276 0 : return true;
3277 : }
3278 1592 : return false;
3279 : }
3280 :
3281 :
3282 : /**
3283 : * Initialize uppercase months and weekdays
3284 : */
3285 561 : void ImpSvNumberInputScan::InitText()
3286 : {
3287 : sal_Int32 j, nElems;
3288 561 : const CharClass* pChrCls = pFormatter->GetCharClass();
3289 561 : const CalendarWrapper* pCal = pFormatter->GetCalendar();
3290 :
3291 561 : delete [] pUpperMonthText;
3292 561 : delete [] pUpperAbbrevMonthText;
3293 : ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem2 > xElems
3294 561 : = pCal->getMonths();
3295 561 : nElems = xElems.getLength();
3296 561 : pUpperMonthText = new OUString[nElems];
3297 561 : pUpperAbbrevMonthText = new OUString[nElems];
3298 7293 : for ( j = 0; j < nElems; j++ )
3299 : {
3300 6732 : pUpperMonthText[j] = pChrCls->uppercase( xElems[j].FullName );
3301 6732 : pUpperAbbrevMonthText[j] = pChrCls->uppercase( xElems[j].AbbrevName );
3302 : }
3303 :
3304 561 : delete [] pUpperGenitiveMonthText;
3305 561 : delete [] pUpperGenitiveAbbrevMonthText;
3306 561 : xElems = pCal->getGenitiveMonths();
3307 561 : bScanGenitiveMonths = (nElems != xElems.getLength());
3308 561 : nElems = xElems.getLength();
3309 561 : pUpperGenitiveMonthText = new OUString[nElems];
3310 561 : pUpperGenitiveAbbrevMonthText = new OUString[nElems];
3311 7293 : for ( j = 0; j < nElems; j++ )
3312 : {
3313 6732 : pUpperGenitiveMonthText[j] = pChrCls->uppercase( xElems[j].FullName );
3314 6732 : pUpperGenitiveAbbrevMonthText[j] = pChrCls->uppercase( xElems[j].AbbrevName );
3315 13464 : if (!bScanGenitiveMonths &&
3316 13464 : (pUpperGenitiveMonthText[j] != pUpperMonthText[j] ||
3317 6732 : pUpperGenitiveAbbrevMonthText[j] != pUpperAbbrevMonthText[j]))
3318 : {
3319 0 : bScanGenitiveMonths = true;
3320 : }
3321 : }
3322 :
3323 561 : delete [] pUpperPartitiveMonthText;
3324 561 : delete [] pUpperPartitiveAbbrevMonthText;
3325 561 : xElems = pCal->getPartitiveMonths();
3326 561 : bScanPartitiveMonths = (nElems != xElems.getLength());
3327 561 : nElems = xElems.getLength();
3328 561 : pUpperPartitiveMonthText = new OUString[nElems];
3329 561 : pUpperPartitiveAbbrevMonthText = new OUString[nElems];
3330 7293 : for ( j = 0; j < nElems; j++ )
3331 : {
3332 6732 : pUpperPartitiveMonthText[j] = pChrCls->uppercase( xElems[j].FullName );
3333 6732 : pUpperPartitiveAbbrevMonthText[j] = pChrCls->uppercase( xElems[j].AbbrevName );
3334 13464 : if (!bScanPartitiveMonths &&
3335 13464 : (pUpperPartitiveMonthText[j] != pUpperGenitiveMonthText[j] ||
3336 6732 : pUpperPartitiveAbbrevMonthText[j] != pUpperGenitiveAbbrevMonthText[j]))
3337 : {
3338 0 : bScanPartitiveMonths = true;
3339 : }
3340 : }
3341 :
3342 561 : delete [] pUpperDayText;
3343 561 : delete [] pUpperAbbrevDayText;
3344 561 : xElems = pCal->getDays();
3345 561 : nElems = xElems.getLength();
3346 561 : pUpperDayText = new OUString[nElems];
3347 561 : pUpperAbbrevDayText = new OUString[nElems];
3348 4488 : for ( j = 0; j < nElems; j++ )
3349 : {
3350 3927 : pUpperDayText[j] = pChrCls->uppercase( xElems[j].FullName );
3351 3927 : pUpperAbbrevDayText[j] = pChrCls->uppercase( xElems[j].AbbrevName );
3352 : }
3353 :
3354 561 : bTextInitialized = true;
3355 561 : }
3356 :
3357 :
3358 : /**
3359 : * MUST be called if International/Locale is changed
3360 : */
3361 20928 : void ImpSvNumberInputScan::ChangeIntl()
3362 : {
3363 20928 : sal_Unicode cDecSep = pFormatter->GetNumDecimalSep()[0];
3364 41856 : bDecSepInDateSeps = ( cDecSep == (sal_Unicode)'-' ||
3365 41856 : cDecSep == pFormatter->GetDateSep()[0] );
3366 20928 : bTextInitialized = false;
3367 20928 : aUpperCurrSymbol.clear();
3368 20928 : InvalidateDateAcceptancePatterns();
3369 20928 : }
3370 :
3371 :
3372 20928 : void ImpSvNumberInputScan::InvalidateDateAcceptancePatterns()
3373 : {
3374 20928 : if (sDateAcceptancePatterns.getLength())
3375 : {
3376 29 : sDateAcceptancePatterns = ::com::sun::star::uno::Sequence< OUString >();
3377 : }
3378 20928 : }
3379 :
3380 :
3381 8303 : void ImpSvNumberInputScan::ChangeNullDate( const sal_uInt16 Day,
3382 : const sal_uInt16 Month,
3383 : const sal_uInt16 Year )
3384 : {
3385 8303 : if ( pNullDate )
3386 : {
3387 8303 : *pNullDate = Date(Day, Month, Year);
3388 : }
3389 : else
3390 : {
3391 0 : pNullDate = new Date(Day, Month, Year);
3392 : }
3393 8303 : }
3394 :
3395 :
3396 : /**
3397 : * Does rString represent a number (also date, time et al)
3398 : */
3399 12526 : bool ImpSvNumberInputScan::IsNumberFormat( const OUString& rString, // string to be analyzed
3400 : short& F_Type, // IN: old type, OUT: new type
3401 : double& fOutNumber, // OUT: number if convertible
3402 : const SvNumberformat* pFormat ) // maybe a number format to match against
3403 : {
3404 12526 : OUString aString;
3405 : bool res; // return value
3406 : sal_uInt16 k;
3407 12526 : eSetType = F_Type; // old type set
3408 :
3409 12526 : if ( !rString.getLength() )
3410 : {
3411 1187 : res = false;
3412 : }
3413 11339 : else if (rString.getLength() > 308) // arbitrary
3414 : {
3415 0 : res = false;
3416 : }
3417 : else
3418 : {
3419 : // NoMoreUpperNeeded, all comparisons on UpperCase
3420 11339 : aString = pFormatter->GetCharClass()->uppercase( rString );
3421 : // convert native number to ASCII if necessary
3422 11339 : TransformInput(pFormatter, aString);
3423 11339 : res = IsNumberFormatMain( aString, pFormat );
3424 : }
3425 :
3426 12526 : if (res)
3427 : {
3428 5262 : if ( nNegCheck || // ')' not found for '('
3429 20 : (nSign && (eScannedType == css::util::NumberFormat::DATE ||
3430 10 : eScannedType == css::util::NumberFormat::DATETIME))) // signed date/datetime
3431 : {
3432 0 : res = false;
3433 : }
3434 : else
3435 : { // check count of partial number strings
3436 5262 : switch (eScannedType)
3437 : {
3438 : case css::util::NumberFormat::PERCENT:
3439 : case css::util::NumberFormat::CURRENCY:
3440 : case css::util::NumberFormat::NUMBER:
3441 4560 : if (nDecPos == 1) // .05
3442 : {
3443 : // matched MidStrings function like group separators
3444 0 : if ( nMatchedAllStrings )
3445 : {
3446 0 : nThousand = nAnzNums - 1;
3447 : }
3448 0 : else if ( nAnzNums != 1 )
3449 : {
3450 0 : res = false;
3451 : }
3452 : }
3453 4560 : else if (nDecPos == 2) // 1.05
3454 : {
3455 : // matched MidStrings function like group separators
3456 557 : if ( nMatchedAllStrings )
3457 : {
3458 0 : nThousand = nAnzNums - 1;
3459 : }
3460 557 : else if ( nAnzNums != nThousand+2 )
3461 : {
3462 0 : res = false;
3463 : }
3464 : }
3465 : else // 1,100 or 1,100.
3466 : {
3467 : // matched MidStrings function like group separators
3468 4003 : if ( nMatchedAllStrings )
3469 : {
3470 0 : nThousand = nAnzNums - 1;
3471 : }
3472 4003 : else if ( nAnzNums != nThousand+1 )
3473 : {
3474 0 : res = false;
3475 : }
3476 : }
3477 4560 : break;
3478 :
3479 : case css::util::NumberFormat::SCIENTIFIC: // 1.0e-2
3480 0 : if (nDecPos == 1) // .05
3481 : {
3482 0 : if (nAnzNums != 2)
3483 : {
3484 0 : res = false;
3485 : }
3486 : }
3487 0 : else if (nDecPos == 2) // 1.05
3488 : {
3489 0 : if (nAnzNums != nThousand+3)
3490 : {
3491 0 : res = false;
3492 : }
3493 : }
3494 : else // 1,100 or 1,100.
3495 : {
3496 0 : if (nAnzNums != nThousand+2)
3497 : {
3498 0 : res = false;
3499 : }
3500 : }
3501 0 : break;
3502 :
3503 : case css::util::NumberFormat::DATE:
3504 648 : if (nMonth)
3505 : { // month name and numbers
3506 7 : if (nAnzNums > 2)
3507 : {
3508 0 : res = false;
3509 : }
3510 : }
3511 : else
3512 : {
3513 641 : if (nAnzNums > 3)
3514 : {
3515 0 : res = false;
3516 : }
3517 : else
3518 : {
3519 : // Even if a date pattern was matched, for abbreviated
3520 : // pattern like "D.M." an input of "D.M. #" was
3521 : // accepted because # could had been a time. Here we do
3522 : // not have a combined date/time input though and #
3523 : // would be taken as Year in this example, which it is
3524 : // not. The count of numbers in pattern must match the
3525 : // count of numbers in input.
3526 641 : res = (GetDatePatternNumbers() == nAnzNums)
3527 641 : || MayBeIso8601() || nMatchedAllStrings;
3528 : }
3529 : }
3530 648 : break;
3531 :
3532 : case css::util::NumberFormat::TIME:
3533 46 : if (nDecPos)
3534 : { // hundredth seconds included
3535 0 : if (nAnzNums > 4)
3536 : {
3537 0 : res = false;
3538 : }
3539 : }
3540 : else
3541 : {
3542 46 : if (nAnzNums > 3)
3543 : {
3544 0 : res = false;
3545 : }
3546 : }
3547 46 : break;
3548 :
3549 : case css::util::NumberFormat::DATETIME:
3550 8 : if (nMonth)
3551 : { // month name and numbers
3552 0 : if (nDecPos)
3553 : { // hundredth seconds included
3554 0 : if (nAnzNums > 6)
3555 : {
3556 0 : res = false;
3557 : }
3558 : }
3559 : else
3560 : {
3561 0 : if (nAnzNums > 5)
3562 : {
3563 0 : res = false;
3564 : }
3565 : }
3566 : }
3567 : else
3568 : {
3569 8 : if (nDecPos)
3570 : { // hundredth seconds included
3571 0 : if (nAnzNums > 7)
3572 : {
3573 0 : res = false;
3574 : }
3575 : }
3576 : else
3577 : {
3578 8 : if (nAnzNums > 6)
3579 : {
3580 0 : res = false;
3581 : }
3582 : }
3583 8 : if (res)
3584 : {
3585 8 : res = IsAcceptedDatePattern( nNums[0]) || MayBeIso8601() || nMatchedAllStrings;
3586 : }
3587 : }
3588 8 : break;
3589 :
3590 : default:
3591 0 : break;
3592 : } // switch
3593 : } // else
3594 : } // if (res)
3595 :
3596 12526 : OUStringBuffer sResString;
3597 :
3598 12526 : if (res)
3599 : { // we finally have a number
3600 5262 : switch (eScannedType)
3601 : {
3602 : case css::util::NumberFormat::LOGICAL:
3603 0 : if (nLogical == 1)
3604 : {
3605 0 : fOutNumber = 1.0; // True
3606 : }
3607 0 : else if (nLogical == -1)
3608 : {
3609 0 : fOutNumber = 0.0; // False
3610 : }
3611 : else
3612 : {
3613 0 : res = false; // Oops
3614 : }
3615 0 : break;
3616 :
3617 : case css::util::NumberFormat::PERCENT:
3618 : case css::util::NumberFormat::CURRENCY:
3619 : case css::util::NumberFormat::NUMBER:
3620 : case css::util::NumberFormat::SCIENTIFIC:
3621 : case css::util::NumberFormat::DEFINED: // if no category detected handle as number
3622 4560 : if ( nDecPos == 1 ) // . at start
3623 : {
3624 0 : sResString.append("0.");
3625 : }
3626 :
3627 9123 : for ( k = 0; k <= nThousand; k++)
3628 : {
3629 4563 : sResString.append(sStrArray[nNums[k]]); // integer part
3630 : }
3631 4560 : if ( nDecPos == 2 && k < nAnzNums ) // . somewhere
3632 : {
3633 557 : sResString.append('.');
3634 557 : sal_uInt16 nStop = (eScannedType == css::util::NumberFormat::SCIENTIFIC ?
3635 557 : nAnzNums-1 : nAnzNums);
3636 1114 : for ( ; k < nStop; k++)
3637 : {
3638 557 : sResString.append(sStrArray[nNums[k]]); // fractional part
3639 : }
3640 : }
3641 :
3642 4560 : if (eScannedType != css::util::NumberFormat::SCIENTIFIC)
3643 : {
3644 4560 : fOutNumber = StringToDouble(sResString.makeStringAndClear());
3645 : }
3646 : else
3647 : { // append exponent
3648 0 : sResString.append('E');
3649 0 : if ( nESign == -1 )
3650 : {
3651 0 : sResString.append('-');
3652 : }
3653 0 : sResString.append(sStrArray[nNums[nAnzNums-1]]);
3654 : rtl_math_ConversionStatus eStatus;
3655 0 : fOutNumber = ::rtl::math::stringToDouble( sResString.makeStringAndClear(), '.', ',', &eStatus, NULL );
3656 0 : if ( eStatus == rtl_math_ConversionStatus_OutOfRange )
3657 : {
3658 0 : F_Type = css::util::NumberFormat::TEXT; // overflow/underflow -> Text
3659 0 : if (nESign == -1)
3660 : {
3661 0 : fOutNumber = 0.0;
3662 : }
3663 : else
3664 : {
3665 0 : fOutNumber = DBL_MAX;
3666 : }
3667 0 : return true;
3668 : }
3669 : }
3670 :
3671 4560 : if ( nStringScanSign )
3672 : {
3673 0 : if ( nSign )
3674 : {
3675 0 : nSign *= nStringScanSign;
3676 : }
3677 : else
3678 : {
3679 0 : nSign = nStringScanSign;
3680 : }
3681 : }
3682 4560 : if ( nSign < 0 )
3683 : {
3684 10 : fOutNumber = -fOutNumber;
3685 : }
3686 :
3687 4560 : if (eScannedType == css::util::NumberFormat::PERCENT)
3688 : {
3689 0 : fOutNumber/= 100.0;
3690 : }
3691 4560 : break;
3692 :
3693 : case css::util::NumberFormat::FRACTION:
3694 0 : if (nAnzNums == 1)
3695 : {
3696 0 : fOutNumber = StringToDouble(sStrArray[nNums[0]]);
3697 : }
3698 0 : else if (nAnzNums == 2)
3699 : {
3700 0 : if (nThousand == 1)
3701 : {
3702 0 : sResString = sStrArray[nNums[0]];
3703 0 : sResString.append(sStrArray[nNums[1]]); // integer part
3704 0 : fOutNumber = StringToDouble(sResString.makeStringAndClear());
3705 : }
3706 : else
3707 : {
3708 0 : double fZaehler = StringToDouble(sStrArray[nNums[0]]);
3709 0 : double fNenner = StringToDouble(sStrArray[nNums[1]]);
3710 0 : if (fNenner != 0.0)
3711 : {
3712 0 : fOutNumber = fZaehler/fNenner;
3713 : }
3714 : else
3715 : {
3716 0 : res = false;
3717 : }
3718 : }
3719 : }
3720 : else // nAnzNums > 2
3721 : {
3722 0 : k = 1;
3723 0 : sResString = sStrArray[nNums[0]];
3724 0 : if (nThousand > 0)
3725 : {
3726 0 : for (; k <= nThousand; k++)
3727 : {
3728 0 : sResString.append(sStrArray[nNums[k]]);
3729 : }
3730 : }
3731 0 : fOutNumber = StringToDouble(sResString.makeStringAndClear());
3732 :
3733 0 : if (k == nAnzNums-2)
3734 : {
3735 0 : double fZaehler = StringToDouble(sStrArray[nNums[k]]);
3736 0 : double fNenner = StringToDouble(sStrArray[nNums[k + 1]]);
3737 0 : if (fNenner != 0.0)
3738 : {
3739 0 : fOutNumber += fZaehler/fNenner;
3740 : }
3741 : else
3742 : {
3743 0 : res = false;
3744 : }
3745 : }
3746 : }
3747 :
3748 0 : if ( nStringScanSign )
3749 : {
3750 0 : if ( nSign )
3751 : {
3752 0 : nSign *= nStringScanSign;
3753 : }
3754 : else
3755 : {
3756 0 : nSign = nStringScanSign;
3757 : }
3758 : }
3759 0 : if ( nSign < 0 )
3760 : {
3761 0 : fOutNumber = -fOutNumber;
3762 : }
3763 0 : break;
3764 :
3765 : case css::util::NumberFormat::TIME:
3766 46 : res = GetTimeRef(fOutNumber, 0, nAnzNums);
3767 46 : if ( nSign < 0 )
3768 : {
3769 0 : fOutNumber = -fOutNumber;
3770 : }
3771 46 : break;
3772 :
3773 : case css::util::NumberFormat::DATE:
3774 648 : res = GetDateRef( fOutNumber, k, pFormat );
3775 648 : break;
3776 :
3777 : case css::util::NumberFormat::DATETIME:
3778 8 : res = GetDateRef( fOutNumber, k, pFormat );
3779 8 : if ( res )
3780 : {
3781 : double fTime;
3782 8 : res = GetTimeRef( fTime, k, nAnzNums - k );
3783 8 : fOutNumber += fTime;
3784 : }
3785 8 : break;
3786 :
3787 : default:
3788 : SAL_WARN( "svl.numbers", "Some number recognized but what's it?" );
3789 0 : fOutNumber = 0.0;
3790 0 : break;
3791 : }
3792 : }
3793 :
3794 12526 : if (res) // overflow/underflow -> Text
3795 : {
3796 5262 : if (fOutNumber < -DBL_MAX) // -1.7E308
3797 : {
3798 0 : F_Type = css::util::NumberFormat::TEXT;
3799 0 : fOutNumber = -DBL_MAX;
3800 0 : return true;
3801 : }
3802 5262 : else if (fOutNumber > DBL_MAX) // 1.7E308
3803 : {
3804 0 : F_Type = css::util::NumberFormat::TEXT;
3805 0 : fOutNumber = DBL_MAX;
3806 0 : return true;
3807 : }
3808 : }
3809 :
3810 12526 : if (!res)
3811 : {
3812 7264 : eScannedType = css::util::NumberFormat::TEXT;
3813 7264 : fOutNumber = 0.0;
3814 : }
3815 :
3816 12526 : F_Type = eScannedType;
3817 12526 : return res;
3818 : }
3819 :
3820 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|