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

Generated by: LCOV version 1.10