LCOV - code coverage report
Current view: top level - svl/source/numbers - zforfind.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 981 1637 59.9 %
Date: 2015-06-13 12:38:46 Functions: 49 50 98.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11