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

Generated by: LCOV version 1.10