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

Generated by: LCOV version 1.10