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

Generated by: LCOV version 1.10