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