LCOV - code coverage report
Current view: top level - svl/source/numbers - zforfind.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 955 1629 58.6 %
Date: 2014-11-03 Functions: 49 50 98.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10