xref: /aoo41x/main/svl/source/numbers/zforfind.cxx (revision dab0a4ea)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_svl.hxx"
26 
27 #include <ctype.h>
28 #include <stdlib.h>
29 #include <float.h>
30 #include <errno.h>
31 #include <tools/date.hxx>
32 #include <tools/debug.hxx>
33 #include <rtl/math.hxx>
34 #include <unotools/charclass.hxx>
35 #include <unotools/calendarwrapper.hxx>
36 #include <unotools/localedatawrapper.hxx>
37 #include <com/sun/star/i18n/CalendarFieldIndex.hpp>
38 #include <unotools/digitgroupingiterator.hxx>
39 
40 #include <svl/zforlist.hxx>         // NUMBERFORMAT_XXX
41 #include "zforscan.hxx"
42 #include <svl/zformat.hxx>
43 
44 #define _ZFORFIND_CXX
45 #include "zforfind.hxx"
46 #undef _ZFORFIND_CXX
47 
48 
49 #ifndef DBG_UTIL
50 #define NF_TEST_CALENDAR 0
51 #else
52 #define NF_TEST_CALENDAR 0
53 #endif
54 #if NF_TEST_CALENDAR
55 #include <comphelper/processfactory.hxx>
56 #include <com/sun/star/i18n/XExtendedCalendar.hpp>
57 #endif
58 
59 
60 const sal_uInt8 ImpSvNumberInputScan::nMatchedEndString    = 0x01;
61 const sal_uInt8 ImpSvNumberInputScan::nMatchedMidString    = 0x02;
62 const sal_uInt8 ImpSvNumberInputScan::nMatchedStartString  = 0x04;
63 const sal_uInt8 ImpSvNumberInputScan::nMatchedVirgin       = 0x08;
64 const sal_uInt8 ImpSvNumberInputScan::nMatchedUsedAsReturn = 0x10;
65 
66 /* It is not clear how we want timezones to be handled. Convert them to local
67  * time isn't wanted, as it isn't done in any other place and timezone
68  * information isn't stored anywhere. Ignoring them and pretending local time
69  * may be wrong too and might not be what the user expects. Keep the input as
70  * string so that no information is lost.
71  * Anyway, defining NF_RECOGNIZE_ISO8601_TIMEZONES to 1 would be the way how it
72  * would work, together with the nTimezonePos handling in GetTimeRef(). */
73 #define NF_RECOGNIZE_ISO8601_TIMEZONES 0
74 
75 //---------------------------------------------------------------------------
76 //      Konstruktor
77 
ImpSvNumberInputScan(SvNumberFormatter * pFormatterP)78 ImpSvNumberInputScan::ImpSvNumberInputScan( SvNumberFormatter* pFormatterP )
79         :
80         pUpperMonthText( NULL ),
81         pUpperAbbrevMonthText( NULL ),
82         pUpperDayText( NULL ),
83         pUpperAbbrevDayText( NULL )
84 {
85     pFormatter = pFormatterP;
86     pNullDate = new Date(30,12,1899);
87     nYear2000 = SvNumberFormatter::GetYear2000Default();
88     Reset();
89     ChangeIntl();
90 }
91 
92 
93 //---------------------------------------------------------------------------
94 //      Destruktor
95 
~ImpSvNumberInputScan()96 ImpSvNumberInputScan::~ImpSvNumberInputScan()
97 {
98     Reset();
99     delete pNullDate;
100     delete [] pUpperMonthText;
101     delete [] pUpperAbbrevMonthText;
102     delete [] pUpperDayText;
103     delete [] pUpperAbbrevDayText;
104 }
105 
106 
107 //---------------------------------------------------------------------------
108 //      Reset
109 
Reset()110 void ImpSvNumberInputScan::Reset()
111 {
112 #if 0
113 // ER 16.06.97 18:56 Vorbelegung erfolgt jetzt in NumberStringDivision,
114 // wozu immer alles loeschen wenn einiges wieder benutzt oder gar nicht
115 // gebraucht wird..
116     for (sal_uInt16 i = 0; i < SV_MAX_ANZ_INPUT_STRINGS; i++)
117     {
118         sStrArray[i].Erase();
119         nNums[i] = SV_MAX_ANZ_INPUT_STRINGS-1;
120         IsNum[i] = sal_False;
121     }
122 #endif
123     nMonth       = 0;
124     nMonthPos    = 0;
125     nTimePos     = 0;
126     nSign        = 0;
127     nESign       = 0;
128     nDecPos      = 0;
129     nNegCheck    = 0;
130     nAnzStrings  = 0;
131     nAnzNums     = 0;
132     nThousand    = 0;
133     eScannedType = NUMBERFORMAT_UNDEFINED;
134     nAmPm        = 0;
135     nPosThousandString = 0;
136     nLogical     = 0;
137     nStringScanNumFor = 0;
138     nStringScanSign = 0;
139     nMatchedAllStrings = nMatchedVirgin;
140     nMayBeIso8601 = 0;
141     nTimezonePos = 0;
142 }
143 
144 
145 //---------------------------------------------------------------------------
146 //
147 // static
MyIsdigit(sal_Unicode c)148 inline sal_Bool ImpSvNumberInputScan::MyIsdigit( sal_Unicode c )
149 {
150     // If the input string wouldn't be converted using TransformInput() we'd
151     // to use something similar to the following and to adapt many places.
152 #if 0
153     // use faster isdigit() if possible
154     if ( c < 128 )
155         return isdigit( (unsigned char) c ) != 0;
156     if ( c < 256 )
157         return sal_False;
158     String aTmp( c );
159     return pFormatter->GetCharClass()->isDigit( aTmp, 0 );
160 #else
161     return c < 128 && isdigit( (unsigned char) c );
162 #endif
163 }
164 
165 
166 //---------------------------------------------------------------------------
167 //
TransformInput(String & rStr)168 void ImpSvNumberInputScan::TransformInput( String& rStr )
169 {
170     xub_StrLen nPos, nLen;
171     for ( nPos = 0, nLen = rStr.Len(); nPos < nLen; ++nPos )
172     {
173         if ( 256 <= rStr.GetChar( nPos ) &&
174                 pFormatter->GetCharClass()->isDigit( rStr, nPos ) )
175             break;
176     }
177     if ( nPos < nLen )
178         rStr = pFormatter->GetNatNum()->getNativeNumberString( rStr,
179                 pFormatter->GetLocale(), 0 );
180 }
181 
182 
183 //---------------------------------------------------------------------------
184 //      StringToDouble
185 //
186 // Only simple unsigned floating point values without any error detection,
187 // decimal separator has to be '.'
188 
StringToDouble(const String & rStr,sal_Bool bForceFraction)189 double ImpSvNumberInputScan::StringToDouble( const String& rStr, sal_Bool bForceFraction )
190 {
191     double fNum = 0.0;
192     double fFrac = 0.0;
193     int nExp = 0;
194     xub_StrLen nPos = 0;
195     xub_StrLen nLen = rStr.Len();
196     sal_Bool bPreSep = !bForceFraction;
197 
198     while (nPos < nLen)
199     {
200         if (rStr.GetChar(nPos) == '.')
201             bPreSep = sal_False;
202         else if (bPreSep)
203             fNum = fNum * 10.0 + (double) (rStr.GetChar(nPos) - '0');
204         else
205         {
206             fFrac = fFrac * 10.0 + (double) (rStr.GetChar(nPos) - '0');
207             --nExp;
208         }
209         nPos++;
210     }
211     if ( fFrac )
212         return fNum + ::rtl::math::pow10Exp( fFrac, nExp );
213     return fNum;
214 }
215 
216 
217 //---------------------------------------------------------------------------
218 //       NextNumberStringSymbol
219 //
220 // Splits the input into numbers and strings for further processing
221 // (Turing-Machine).
222 //---------------------------------------------------------------------------
223 // Initial State = GetChar
224 //---------------+-------------------+-------------------------+-------------
225 // Former State  | Read Character    | Action                  | New State
226 //---------------+-------------------+-------------------------+-------------
227 // GetChar       | Digit             | Symbol=Character        | GetValue
228 //               | Else              | Symbol=Character        | GetString
229 //---------------|-------------------+-------------------------+-------------
230 // GetValue      | Digit             | Symbol=Symbol+Character | GetValue
231 //               | Else              | Dec(CharPos)            | Stop
232 //---------------+-------------------+-------------------------+-------------
233 // GetString     | Digit             | Dec(CharPos)            | Stop
234 //               | Else              | Symbol=Symbol+Character | GetString
235 //---------------+-------------------+-------------------------+-------------
236 
237 enum ScanState              // States of the Turing-Maschine
238 {
239     SsStop      = 0,
240     SsStart     = 1,
241     SsGetValue  = 2,
242     SsGetString = 3
243 };
244 
NextNumberStringSymbol(const sal_Unicode * & pStr,String & rSymbol)245 sal_Bool ImpSvNumberInputScan::NextNumberStringSymbol(
246         const sal_Unicode*& pStr,
247         String& rSymbol )
248 {
249     sal_Bool isNumber = sal_False;
250     sal_Unicode cToken;
251     ScanState eState = SsStart;
252     register const sal_Unicode* pHere = pStr;
253     register xub_StrLen nChars = 0;
254 
255     while ( ((cToken = *pHere) != 0) && eState != SsStop)
256     {
257         pHere++;
258         switch (eState)
259         {
260             case SsStart:
261                 if ( MyIsdigit( cToken ) )
262                 {
263                     eState = SsGetValue;
264                     isNumber = sal_True;
265                 }
266                 else
267                     eState = SsGetString;
268                 nChars++;
269                 break;
270             case SsGetValue:
271                 if ( MyIsdigit( cToken ) )
272                     nChars++;
273                 else
274                 {
275                     eState = SsStop;
276                     pHere--;
277                 }
278                 break;
279             case SsGetString:
280                 if ( !MyIsdigit( cToken ) )
281                     nChars++;
282                 else
283                 {
284                     eState = SsStop;
285                     pHere--;
286                 }
287                 break;
288             default:
289                 break;
290         }   // switch
291     }   // while
292 
293     if ( nChars )
294         rSymbol.Assign( pStr, nChars );
295     else
296         rSymbol.Erase();
297 
298     pStr = pHere;
299 
300     return isNumber;
301 }
302 
303 
304 //---------------------------------------------------------------------------
305 //      SkipThousands
306 
307 // FIXME: should be grouping; it is only used though in case nAnzStrings is
308 // near SV_MAX_ANZ_INPUT_STRINGS, in NumberStringDivision().
309 
SkipThousands(const sal_Unicode * & pStr,String & rSymbol)310 sal_Bool ImpSvNumberInputScan::SkipThousands(
311         const sal_Unicode*& pStr,
312         String& rSymbol )
313 {
314     sal_Bool res = sal_False;
315     sal_Unicode cToken;
316     const String& rThSep = pFormatter->GetNumThousandSep();
317     register const sal_Unicode* pHere = pStr;
318     ScanState eState = SsStart;
319     xub_StrLen nCounter = 0;                                // counts 3 digits
320 
321     while ( ((cToken = *pHere) != 0) && eState != SsStop)
322     {
323         pHere++;
324         switch (eState)
325         {
326             case SsStart:
327                 if ( StringPtrContains( rThSep, pHere-1, 0 ) )
328                 {
329                     nCounter = 0;
330                     eState = SsGetValue;
331                     pHere += rThSep.Len()-1;
332                 }
333                 else
334                 {
335                     eState = SsStop;
336                     pHere--;
337                 }
338                 break;
339             case SsGetValue:
340                 if ( MyIsdigit( cToken ) )
341                 {
342                     rSymbol += cToken;
343                     nCounter++;
344                     if (nCounter == 3)
345                     {
346                         eState = SsStart;
347                         res = sal_True;                 // .000 combination found
348                     }
349                 }
350                 else
351                 {
352                     eState = SsStop;
353                     pHere--;
354                 }
355                 break;
356             default:
357                 break;
358         }   // switch
359     }   // while
360 
361     if (eState == SsGetValue)               // break witth less than 3 digits
362     {
363         if ( nCounter )
364             rSymbol.Erase( rSymbol.Len() - nCounter, nCounter );
365         pHere -= nCounter + rThSep.Len();       // put back ThSep also
366     }
367     pStr = pHere;
368 
369     return res;
370 }
371 
372 
373 //---------------------------------------------------------------------------
374 //      NumberStringDivision
375 
NumberStringDivision(const String & rString)376 void ImpSvNumberInputScan::NumberStringDivision( const String& rString )
377 {
378     const sal_Unicode* pStr = rString.GetBuffer();
379     const sal_Unicode* const pEnd = pStr + rString.Len();
380     while ( pStr < pEnd && nAnzStrings < SV_MAX_ANZ_INPUT_STRINGS )
381     {
382         if ( NextNumberStringSymbol( pStr, sStrArray[nAnzStrings] ) )
383         {                                               // Zahl
384             IsNum[nAnzStrings] = sal_True;
385             nNums[nAnzNums] = nAnzStrings;
386             nAnzNums++;
387             if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS - 7 &&
388                 nPosThousandString == 0)                // nur einmal
389                 if ( SkipThousands( pStr, sStrArray[nAnzStrings] ) )
390                     nPosThousandString = nAnzStrings;
391         }
392         else
393         {
394             IsNum[nAnzStrings] = sal_False;
395         }
396         nAnzStrings++;
397     }
398 }
399 
400 
401 //---------------------------------------------------------------------------
402 // Whether rString contains rWhat at nPos
403 
StringContainsImpl(const String & rWhat,const String & rString,xub_StrLen nPos)404 sal_Bool ImpSvNumberInputScan::StringContainsImpl( const String& rWhat,
405             const String& rString, xub_StrLen nPos )
406 {
407     if ( nPos + rWhat.Len() <= rString.Len() )
408         return StringPtrContainsImpl( rWhat, rString.GetBuffer(), nPos );
409     return sal_False;
410 }
411 
412 
413 //---------------------------------------------------------------------------
414 // Whether pString contains rWhat at nPos
415 
StringPtrContainsImpl(const String & rWhat,const sal_Unicode * pString,xub_StrLen nPos)416 sal_Bool ImpSvNumberInputScan::StringPtrContainsImpl( const String& rWhat,
417             const sal_Unicode* pString, xub_StrLen nPos )
418 {
419     if ( rWhat.Len() == 0 )
420         return sal_False;
421     register const sal_Unicode* pWhat = rWhat.GetBuffer();
422     register const sal_Unicode* const pEnd = pWhat + rWhat.Len();
423     register const sal_Unicode* pStr = pString + nPos;
424     while ( pWhat < pEnd )
425     {
426         if ( *pWhat != *pStr )
427             return sal_False;
428         pWhat++;
429         pStr++;
430     }
431     return sal_True;
432 }
433 
434 
435 //---------------------------------------------------------------------------
436 //      SkipChar
437 //
438 // ueberspringt genau das angegebene Zeichen
439 
SkipChar(sal_Unicode c,const String & rString,xub_StrLen & nPos)440 inline sal_Bool ImpSvNumberInputScan::SkipChar( sal_Unicode c, const String& rString,
441         xub_StrLen& nPos )
442 {
443     if ((nPos < rString.Len()) && (rString.GetChar(nPos) == c))
444     {
445         nPos++;
446         return sal_True;
447     }
448     return sal_False;
449 }
450 
451 
452 //---------------------------------------------------------------------------
453 //      SkipBlanks
454 //
455 // Ueberspringt Leerzeichen
456 
SkipBlanks(const String & rString,xub_StrLen & nPos)457 inline void ImpSvNumberInputScan::SkipBlanks( const String& rString,
458         xub_StrLen& nPos )
459 {
460     if ( nPos < rString.Len() )
461     {
462         register const sal_Unicode* p = rString.GetBuffer() + nPos;
463         while ( *p == ' ' )
464         {
465             nPos++;
466             p++;
467         }
468     }
469 }
470 
471 
472 //---------------------------------------------------------------------------
473 //      SkipString
474 //
475 // jump over rWhat in rString at nPos
476 
SkipString(const String & rWhat,const String & rString,xub_StrLen & nPos)477 inline sal_Bool ImpSvNumberInputScan::SkipString( const String& rWhat,
478         const String& rString, xub_StrLen& nPos )
479 {
480     if ( StringContains( rWhat, rString, nPos ) )
481     {
482         nPos = nPos + rWhat.Len();
483         return sal_True;
484     }
485     return sal_False;
486 }
487 
488 
489 //---------------------------------------------------------------------------
490 //      GetThousandSep
491 //
492 // recognizes exactly ,111 in {3} and {3,2} or ,11 in {3,2} grouping
493 
GetThousandSep(const String & rString,xub_StrLen & nPos,sal_uInt16 nStringPos)494 inline sal_Bool ImpSvNumberInputScan::GetThousandSep(
495         const String& rString,
496         xub_StrLen& nPos,
497         sal_uInt16 nStringPos )
498 {
499     const String& rSep = pFormatter->GetNumThousandSep();
500     // Is it an ordinary space instead of a non-breaking space?
501     bool bSpaceBreak = rSep.GetChar(0) == 0xa0 && rString.GetChar(0) == 0x20 &&
502         rSep.Len() == 1 && rString.Len() == 1;
503     if (!( (rString == rSep || bSpaceBreak)             // nothing else
504                 && nStringPos < nAnzStrings - 1         // safety first!
505                 && IsNum[nStringPos+1] ))               // number follows
506         return sal_False;                                   // no? => out
507 
508     utl::DigitGroupingIterator aGrouping(
509             pFormatter->GetLocaleData()->getDigitGrouping());
510     // Match ,### in {3} or ,## in {3,2}
511     /* FIXME: this could be refined to match ,## in {3,2} only if ,##,## or
512      * ,##,### and to match ,### in {3,2} only if it's the last. However,
513      * currently there is no track kept where group separators occur. In {3,2}
514      * #,###,### and #,##,## would be valid input, which maybe isn't even bad
515      * for #,###,###. Other combinations such as #,###,## maybe not. */
516     xub_StrLen nLen = sStrArray[nStringPos+1].Len();
517     if (nLen == aGrouping.get()                         // with 3 (or so) digits
518             || nLen == aGrouping.advance().get()        // or with 2 (or 3 or so) digits
519             || nPosThousandString == nStringPos+1       // or concatenated
520        )
521     {
522         nPos = nPos + rSep.Len();
523         return sal_True;
524     }
525     return sal_False;
526 }
527 
528 
529 //---------------------------------------------------------------------------
530 //      GetLogical
531 //
532 // Conversion of text to logial value
533 // "sal_True" =>  1:
534 // "sal_False"=> -1:
535 // else   =>  0:
536 
GetLogical(const String & rString)537 short ImpSvNumberInputScan::GetLogical( const String& rString )
538 {
539     short res;
540 
541     const ImpSvNumberformatScan* pFS = pFormatter->GetFormatScanner();
542     if ( rString == pFS->GetTrueString() )
543         res = 1;
544     else if ( rString == pFS->GetFalseString() )
545         res = -1;
546     else
547         res = 0;
548 
549     return res;
550 }
551 
552 
553 //---------------------------------------------------------------------------
554 //      GetMonth
555 //
556 // Converts a string containing a month name (JAN, January) at nPos into the
557 // month number (negative if abbreviated), returns 0 if nothing found
558 
GetMonth(const String & rString,xub_StrLen & nPos)559 short ImpSvNumberInputScan::GetMonth( const String& rString, xub_StrLen& nPos )
560 {
561     // #102136# The correct English form of month September abbreviated is
562     // SEPT, but almost every data contains SEP instead.
563     static const String aSeptCorrect( RTL_CONSTASCII_USTRINGPARAM( "SEPT" ) );
564     static const String aSepShortened( RTL_CONSTASCII_USTRINGPARAM( "SEP" ) );
565 
566     short res = 0;      // no month found
567 
568     if (rString.Len() > nPos)                           // only if needed
569     {
570         if ( !bTextInitialized )
571             InitText();
572         sal_Int16 nMonths = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
573         for ( sal_Int16 i = 0; i < nMonths; i++ )
574         {
575             if ( StringContains( pUpperMonthText[i], rString, nPos ) )
576             {                                           // full names first
577                 nPos = nPos + pUpperMonthText[i].Len();
578                 res = i+1;
579                 break;  // for
580             }
581             else if ( StringContains( pUpperAbbrevMonthText[i], rString, nPos ) )
582             {                                           // abbreviated
583                 nPos = nPos + pUpperAbbrevMonthText[i].Len();
584                 res = sal::static_int_cast< short >(-(i+1)); // negative
585                 break;  // for
586             }
587             else if ( i == 8 && pUpperAbbrevMonthText[i] == aSeptCorrect &&
588                     StringContains( aSepShortened, rString, nPos ) )
589             {                                           // #102136# SEPT/SEP
590                 nPos = nPos + aSepShortened.Len();
591                 res = sal::static_int_cast< short >(-(i+1)); // negative
592                 break;  // for
593             }
594         }
595     }
596 
597     return res;
598 }
599 
600 
601 //---------------------------------------------------------------------------
602 //      GetDayOfWeek
603 //
604 // Converts a string containing a DayOfWeek name (Mon, Monday) at nPos into the
605 // DayOfWeek number + 1 (negative if abbreviated), returns 0 if nothing found
606 
GetDayOfWeek(const String & rString,xub_StrLen & nPos)607 int ImpSvNumberInputScan::GetDayOfWeek( const String& rString, xub_StrLen& nPos )
608 {
609     int res = 0;      // no day found
610 
611     if (rString.Len() > nPos)                           // only if needed
612     {
613         if ( !bTextInitialized )
614             InitText();
615         sal_Int16 nDays = pFormatter->GetCalendar()->getNumberOfDaysInWeek();
616         for ( sal_Int16 i = 0; i < nDays; i++ )
617         {
618             if ( StringContains( pUpperDayText[i], rString, nPos ) )
619             {                                           // full names first
620                 nPos = nPos + pUpperDayText[i].Len();
621                 res = i + 1;
622                 break;  // for
623             }
624             if ( StringContains( pUpperAbbrevDayText[i], rString, nPos ) )
625             {                                           // abbreviated
626                 nPos = nPos + pUpperAbbrevDayText[i].Len();
627                 res = -(i + 1);                         // negative
628                 break;  // for
629             }
630         }
631     }
632 
633     return res;
634 }
635 
636 
637 //---------------------------------------------------------------------------
638 //      GetCurrency
639 //
640 // Reading a currency symbol
641 // '$'   => sal_True
642 // else  => sal_False
643 
GetCurrency(const String & rString,xub_StrLen & nPos,const SvNumberformat * pFormat)644 sal_Bool ImpSvNumberInputScan::GetCurrency( const String& rString, xub_StrLen& nPos,
645             const SvNumberformat* pFormat )
646 {
647     if ( rString.Len() > nPos )
648     {
649         if ( !aUpperCurrSymbol.Len() )
650         {   // if no format specified the currency of the initialized formatter
651             LanguageType eLang = (pFormat ? pFormat->GetLanguage() :
652                 pFormatter->GetLanguage());
653             aUpperCurrSymbol = pFormatter->GetCharClass()->upper(
654                 SvNumberFormatter::GetCurrencyEntry( eLang ).GetSymbol() );
655         }
656         if ( StringContains( aUpperCurrSymbol, rString, nPos ) )
657         {
658             nPos = nPos + aUpperCurrSymbol.Len();
659             return sal_True;
660         }
661         if ( pFormat )
662         {
663             String aSymbol, aExtension;
664             if ( pFormat->GetNewCurrencySymbol( aSymbol, aExtension ) )
665             {
666                 if ( aSymbol.Len() <= rString.Len() - nPos )
667                 {
668                     pFormatter->GetCharClass()->toUpper( aSymbol );
669                     if ( StringContains( aSymbol, rString, nPos ) )
670                     {
671                         nPos = nPos + aSymbol.Len();
672                         return sal_True;
673                     }
674                 }
675             }
676         }
677     }
678 
679     return sal_False;
680 }
681 
682 
683 //---------------------------------------------------------------------------
684 //      GetTimeAmPm
685 //
686 // Lesen des Zeitsymbols (AM od. PM) f. kurze Zeitangabe
687 //
688 // Rueckgabe:
689 //  "AM" od. "PM" => sal_True
690 //  sonst         => sal_False
691 //
692 // nAmPos:
693 //  "AM"  =>  1
694 //  "PM"  => -1
695 //  sonst =>  0
696 
GetTimeAmPm(const String & rString,xub_StrLen & nPos)697 sal_Bool ImpSvNumberInputScan::GetTimeAmPm( const String& rString, xub_StrLen& nPos )
698 {
699 
700     if ( rString.Len() > nPos )
701     {
702         const CharClass* pChr = pFormatter->GetCharClass();
703         const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
704         if ( StringContains( pChr->upper( pLoc->getTimeAM() ), rString, nPos ) )
705         {
706             nAmPm = 1;
707             nPos = nPos + pLoc->getTimeAM().Len();
708             return sal_True;
709         }
710         else if ( StringContains( pChr->upper( pLoc->getTimePM() ), rString, nPos ) )
711         {
712             nAmPm = -1;
713             nPos = nPos + pLoc->getTimePM().Len();
714             return sal_True;
715         }
716     }
717 
718     return sal_False;
719 }
720 
721 
722 //---------------------------------------------------------------------------
723 //      GetDecSep
724 //
725 // Lesen eines Dezimaltrenners (',')
726 // ','   => sal_True
727 // sonst => sal_False
728 
GetDecSep(const String & rString,xub_StrLen & nPos)729 inline sal_Bool ImpSvNumberInputScan::GetDecSep( const String& rString, xub_StrLen& nPos )
730 {
731     if ( rString.Len() > nPos )
732     {
733         const String& rSep = pFormatter->GetNumDecimalSep();
734         if ( rString.Equals( rSep, nPos, rSep.Len() ) )
735         {
736             nPos = nPos + rSep.Len();
737             return sal_True;
738         }
739     }
740     return sal_False;
741 }
742 
743 
744 //---------------------------------------------------------------------------
745 // read a hundredth seconds separator
746 
GetTime100SecSep(const String & rString,xub_StrLen & nPos)747 inline sal_Bool ImpSvNumberInputScan::GetTime100SecSep( const String& rString, xub_StrLen& nPos )
748 {
749     if ( rString.Len() > nPos )
750     {
751         const String& rSep = pFormatter->GetLocaleData()->getTime100SecSep();
752         if ( rString.Equals( rSep, nPos, rSep.Len() ) )
753         {
754             nPos = nPos + rSep.Len();
755             return sal_True;
756         }
757     }
758     return sal_False;
759 }
760 
761 
762 //---------------------------------------------------------------------------
763 //      GetSign
764 //
765 // Lesen eines Vorzeichens, auch Klammer !?!
766 // '+'   =>  1
767 // '-'   => -1
768 // '('   => -1, nNegCheck = 1
769 // sonst =>  0
770 
GetSign(const String & rString,xub_StrLen & nPos)771 int ImpSvNumberInputScan::GetSign( const String& rString, xub_StrLen& nPos )
772 {
773     if (rString.Len() > nPos)
774         switch (rString.GetChar(nPos))
775         {
776             case '+':
777                 nPos++;
778                 return 1;
779             case '(':               // '(' aehnlich wie '-' ?!?
780                 nNegCheck = 1;
781                 //! fallthru
782             case '-':
783                 nPos++;
784                 return -1;
785             default:
786                 break;
787         }
788 
789     return 0;
790 }
791 
792 
793 //---------------------------------------------------------------------------
794 //      GetESign
795 //
796 // Lesen eines Vorzeichens, gedacht fuer Exponent ?!?
797 // '+'   =>  1
798 // '-'   => -1
799 // sonst =>  0
800 
GetESign(const String & rString,xub_StrLen & nPos)801 short ImpSvNumberInputScan::GetESign( const String& rString, xub_StrLen& nPos )
802 {
803     if (rString.Len() > nPos)
804         switch (rString.GetChar(nPos))
805         {
806             case '+':
807                 nPos++;
808                 return 1;
809             case '-':
810                 nPos++;
811                 return -1;
812             default:
813                 break;
814         }
815 
816     return 0;
817 }
818 
819 
820 //---------------------------------------------------------------------------
821 //      GetNextNumber
822 //
823 // i counts string portions, j counts numbers thereof.
824 // It should had been called SkipNumber instead.
825 
GetNextNumber(sal_uInt16 & i,sal_uInt16 & j)826 inline sal_Bool ImpSvNumberInputScan::GetNextNumber( sal_uInt16& i, sal_uInt16& j )
827 {
828     if ( i < nAnzStrings && IsNum[i] )
829     {
830         j++;
831         i++;
832         return sal_True;
833     }
834     return sal_False;
835 }
836 
837 
838 //---------------------------------------------------------------------------
839 //      GetTimeRef
840 
GetTimeRef(double & fOutNumber,sal_uInt16 nIndex,sal_uInt16 nAnz)841 void ImpSvNumberInputScan::GetTimeRef(
842         double& fOutNumber,
843         sal_uInt16 nIndex,          // j-value of the first numeric time part of input, default 0
844         sal_uInt16 nAnz )           // count of numeric time parts
845 {
846     sal_uInt16 nHour;
847     sal_uInt16 nMinute = 0;
848     sal_uInt16 nSecond = 0;
849     double fSecond100 = 0.0;
850     sal_uInt16 nStartIndex = nIndex;
851 
852     if (nTimezonePos)
853     {
854         // find first timezone number index and adjust count
855         for (sal_uInt16 j=0; j<nAnzNums; ++j)
856         {
857             if (nNums[j] == nTimezonePos)
858             {
859                 // nAnz is not total count, but count of time relevant strings.
860                 if (nStartIndex < j && j - nStartIndex < nAnz)
861                     nAnz = j - nStartIndex;
862                 break;  // for
863             }
864         }
865     }
866 
867     if (nDecPos == 2 && (nAnz == 3 || nAnz == 2))   // 20:45.5 or 45.5
868         nHour = 0;
869     else if (nIndex - nStartIndex < nAnz)
870         nHour   = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32();
871     else
872     {
873         nHour = 0;
874         DBG_ERRORFILE( "ImpSvNumberInputScan::GetTimeRef: bad number index");
875     }
876     if (nDecPos == 2 && nAnz == 2)                  // 45.5
877         nMinute = 0;
878     else if (nIndex - nStartIndex < nAnz)
879         nMinute = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32();
880     if (nIndex - nStartIndex < nAnz)
881         nSecond = (sal_uInt16) sStrArray[nNums[nIndex++]].ToInt32();
882     if (nIndex - nStartIndex < nAnz)
883         fSecond100 = StringToDouble( sStrArray[nNums[nIndex]], sal_True );
884     if (nAmPm == -1 && nHour != 12)             // PM
885         nHour += 12;
886     else if (nAmPm == 1 && nHour == 12)         // 12 AM
887         nHour = 0;
888 
889     fOutNumber = ((double)nHour*3600 +
890                   (double)nMinute*60 +
891                   (double)nSecond +
892                   fSecond100)/86400.0;
893 }
894 
895 
896 //---------------------------------------------------------------------------
897 //      ImplGetDay
898 
ImplGetDay(sal_uInt16 nIndex)899 sal_uInt16 ImpSvNumberInputScan::ImplGetDay( sal_uInt16 nIndex )
900 {
901     sal_uInt16 nRes = 0;
902 
903     if (sStrArray[nNums[nIndex]].Len() <= 2)
904     {
905         sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32();
906         if (nNum <= 31)
907             nRes = nNum;
908     }
909 
910     return nRes;
911 }
912 
913 
914 //---------------------------------------------------------------------------
915 //      ImplGetMonth
916 
ImplGetMonth(sal_uInt16 nIndex)917 sal_uInt16 ImpSvNumberInputScan::ImplGetMonth( sal_uInt16 nIndex )
918 {
919     // preset invalid month number
920     sal_uInt16 nRes = pFormatter->GetCalendar()->getNumberOfMonthsInYear();
921 
922     if (sStrArray[nNums[nIndex]].Len() <= 2)
923     {
924         sal_uInt16 nNum = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32();
925         if ( 0 < nNum && nNum <= nRes )
926             nRes = nNum - 1;        // zero based for CalendarFieldIndex::MONTH
927     }
928 
929     return nRes;
930 }
931 
932 
933 //---------------------------------------------------------------------------
934 //      ImplGetYear
935 //
936 // 30 -> 1930, 29 -> 2029, oder 56 -> 1756, 55 -> 1855, ...
937 
ImplGetYear(sal_uInt16 nIndex)938 sal_uInt16 ImpSvNumberInputScan::ImplGetYear( sal_uInt16 nIndex )
939 {
940     sal_uInt16 nYear = 0;
941 
942     if (sStrArray[nNums[nIndex]].Len() <= 4)
943     {
944         nYear = (sal_uInt16) sStrArray[nNums[nIndex]].ToInt32();
945         nYear = SvNumberFormatter::ExpandTwoDigitYear( nYear, nYear2000 );
946     }
947 
948     return nYear;
949 }
950 
951 //---------------------------------------------------------------------------
952 
MayBeIso8601()953 bool ImpSvNumberInputScan::MayBeIso8601()
954 {
955     if (nMayBeIso8601 == 0)
956     {
957         if (nAnzNums >= 3 && nNums[0] < nAnzStrings &&
958                 sStrArray[nNums[0]].ToInt32() > 31)
959             nMayBeIso8601 = 1;
960         else
961             nMayBeIso8601 = 2;
962     }
963     return nMayBeIso8601 == 1;
964 }
965 
966 //---------------------------------------------------------------------------
967 //      GetDateRef
968 
GetDateRef(double & fDays,sal_uInt16 & nCounter,const SvNumberformat * pFormat)969 sal_Bool ImpSvNumberInputScan::GetDateRef( double& fDays, sal_uInt16& nCounter,
970         const SvNumberformat* pFormat )
971 {
972     using namespace ::com::sun::star::i18n;
973     NfEvalDateFormat eEDF;
974     int nFormatOrder;
975     if ( pFormat && ((pFormat->GetType() & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE) )
976     {
977         eEDF = pFormatter->GetEvalDateFormat();
978         switch ( eEDF )
979         {
980             case NF_EVALDATEFORMAT_INTL :
981             case NF_EVALDATEFORMAT_FORMAT :
982                 nFormatOrder = 1;       // only one loop
983             break;
984             default:
985                 nFormatOrder = 2;
986                 if ( nMatchedAllStrings )
987                     eEDF = NF_EVALDATEFORMAT_FORMAT_INTL;
988                     // we have a complete match, use it
989         }
990     }
991     else
992     {
993         eEDF = NF_EVALDATEFORMAT_INTL;
994         nFormatOrder = 1;
995     }
996     sal_Bool res = sal_True;
997 
998     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
999     CalendarWrapper* pCal = pFormatter->GetCalendar();
1000     for ( int nTryOrder = 1; nTryOrder <= nFormatOrder; nTryOrder++ )
1001     {
1002         pCal->setGregorianDateTime( Date() );       // today
1003         String aOrgCalendar;        // empty => not changed yet
1004         DateFormat DateFmt;
1005         sal_Bool bFormatTurn;
1006         switch ( eEDF )
1007         {
1008             case NF_EVALDATEFORMAT_INTL :
1009                 bFormatTurn = sal_False;
1010                 DateFmt = pLoc->getDateFormat();
1011             break;
1012             case NF_EVALDATEFORMAT_FORMAT :
1013                 bFormatTurn = sal_True;
1014                 DateFmt = pFormat->GetDateOrder();
1015             break;
1016             case NF_EVALDATEFORMAT_INTL_FORMAT :
1017                 if ( nTryOrder == 1 )
1018                 {
1019                     bFormatTurn = sal_False;
1020                     DateFmt = pLoc->getDateFormat();
1021                 }
1022                 else
1023                 {
1024                     bFormatTurn = sal_True;
1025                     DateFmt = pFormat->GetDateOrder();
1026                 }
1027             break;
1028             case NF_EVALDATEFORMAT_FORMAT_INTL :
1029                 if ( nTryOrder == 2 )
1030                 {
1031                     bFormatTurn = sal_False;
1032                     DateFmt = pLoc->getDateFormat();
1033                 }
1034                 else
1035                 {
1036                     bFormatTurn = sal_True;
1037                     DateFmt = pFormat->GetDateOrder();
1038                 }
1039             break;
1040             default:
1041                 DBG_ERROR( "ImpSvNumberInputScan::GetDateRef: unknown NfEvalDateFormat" );
1042 				DateFmt = YMD;
1043 				bFormatTurn = sal_False;
1044         }
1045         if ( bFormatTurn )
1046         {
1047 #if 0
1048 /* TODO:
1049 We are currently not able to fully support a switch to another calendar during
1050 input for the following reasons:
1051 1. We do have a problem if both (locale's default and format's) calendars
1052    define the same YMD order and use the same date separator, there is no way
1053    to distinguish between them if the input results in valid calendar input for
1054    both calendars. How to solve? Would NfEvalDateFormat be sufficient? Should
1055    it always be set to NF_EVALDATEFORMAT_FORMAT_INTL and thus the format's
1056    calendar be preferred? This could be confusing if a Calc cell was formatted
1057    different to the locale's default and has no content yet, then the user has
1058    no clue about the format or calendar being set.
1059 2. In Calc cell edit mode a date is always displayed and edited using the
1060    default edit format of the default calendar (normally being Gregorian). If
1061    input was ambiguous due to issue #1 we'd need a mechanism to tell that a
1062    date was edited and not newly entered. Not feasible. Otherwise we'd need a
1063    mechanism to use a specific edit format with a specific calendar according
1064    to the format set.
1065 3. For some calendars like Japanese Gengou we'd need era input, which isn't
1066    implemented at all. Though this is a rare and special case, forcing a
1067    calendar dependent edit format as suggested in item #2 might require era
1068    input, if it shouldn't result in a fallback to Gregorian calendar.
1069 4. Last and least: the GetMonth() method currently only matches month names of
1070    the default calendar. Alternating month names of the actual format's
1071    calendar would have to be implemented. No problem.
1072 
1073 */
1074             if ( pFormat->IsOtherCalendar( nStringScanNumFor ) )
1075                 pFormat->SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime );
1076             else
1077                 pFormat->SwitchToSpecifiedCalendar( aOrgCalendar, fOrgDateTime,
1078                         nStringScanNumFor );
1079 #endif
1080         }
1081 
1082         res = sal_True;
1083         nCounter = 0;
1084         // For incomplete dates, always assume first day of month if not specified.
1085         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1086 
1087         switch (nAnzNums)       // count of numbers in string
1088         {
1089             case 0:                 // none
1090                 if (nMonthPos)          // only month (Jan)
1091                     pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1092                 else
1093                     res = sal_False;
1094                 break;
1095 
1096             case 1:                 // only one number
1097                 nCounter = 1;
1098                 switch (nMonthPos)  // where is the month
1099                 {
1100                     case 0:             // not found => only day entered
1101                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1102                         break;
1103                     case 1:             // month at the beginning (Jan 01)
1104                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1105                         switch (DateFmt)
1106                         {
1107                             case MDY:
1108                             case YMD:
1109                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1110                                 break;
1111                             case DMY:
1112                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1113                                 break;
1114                             default:
1115                                 res = sal_False;
1116                                 break;
1117                         }
1118                         break;
1119                     case 3:             // month at the end (10 Jan)
1120                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1121                         switch (DateFmt)
1122                         {
1123                             case DMY:
1124                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1125                                 break;
1126                             case YMD:
1127                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1128                                 break;
1129                             default:
1130                                 res = sal_False;
1131                                 break;
1132                         }
1133                         break;
1134                     default:
1135                         res = sal_False;
1136                         break;
1137                 }   // switch (nMonthPos)
1138                 break;
1139 
1140             case 2:                 // 2 numbers
1141                 nCounter = 2;
1142                 switch (nMonthPos)  // where is the month
1143                 {
1144                     case 0:             // not found
1145                     {
1146                         bool bHadExact;
1147                         sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1148                         if ( 0xff < nExactDateOrder && nExactDateOrder <= 0xffff )
1149                         {   // formatted as date and exactly 2 parts
1150                             bHadExact = true;
1151                             switch ( (nExactDateOrder >> 8) & 0xff )
1152                             {
1153                                 case 'Y':
1154                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1155                                 break;
1156                                 case 'M':
1157                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1158                                 break;
1159                                 case 'D':
1160                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1161                                 break;
1162                                 default:
1163                                     bHadExact = false;
1164                             }
1165                             switch ( nExactDateOrder & 0xff )
1166                             {
1167                                 case 'Y':
1168                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1169                                 break;
1170                                 case 'M':
1171                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1172                                 break;
1173                                 case 'D':
1174                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1175                                 break;
1176                                 default:
1177                                     bHadExact = false;
1178                             }
1179                         }
1180                         else
1181                             bHadExact = false;
1182                         if ( !bHadExact || !pCal->isValid() )
1183                         {
1184                             if ( !bHadExact && nExactDateOrder )
1185                                 pCal->setGregorianDateTime( Date() );   // reset today
1186                             switch (DateFmt)
1187                             {
1188                                 case MDY:
1189                                     // M D
1190                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1191                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1192                                     if ( !pCal->isValid() )             // 2nd try
1193                                     {                                   // M Y
1194                                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1195                                         pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1196                                         pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1197                                     }
1198                                     break;
1199                                 case DMY:
1200                                     // D M
1201                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1202                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1203                                     if ( !pCal->isValid() )             // 2nd try
1204                                     {                                   // M Y
1205                                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1206                                         pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1207                                         pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1208                                     }
1209                                     break;
1210                                 case YMD:
1211                                     // M D
1212                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1213                                     pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1214                                     if ( !pCal->isValid() )             // 2nd try
1215                                     {                                   // Y M
1216                                         pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, 1 );
1217                                         pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1218                                         pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1219                                     }
1220                                     break;
1221                                 default:
1222                                     res = sal_False;
1223                                     break;
1224                             }
1225                         }
1226                     }
1227                     break;
1228                     case 1:             // month at the beginning (Jan 01 01)
1229                     {
1230                         // The input is valid as MDY in almost any
1231                         // constellation, there is no date order (M)YD except if
1232                         // set in a format applied.
1233                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1234                         sal_uInt32 nExactDateOrder = (bFormatTurn ? pFormat->GetExactDateOrder() : 0);
1235                         if ((((nExactDateOrder >> 8) & 0xff) == 'Y') && ((nExactDateOrder & 0xff) == 'D'))
1236                         {
1237                             pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1238                             pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1239                         }
1240                         else
1241                         {
1242                             pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1243                             pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1244                         }
1245                     }
1246                     break;
1247                     case 2:             // month in the middle (10 Jan 94)
1248                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1249                         switch (DateFmt)
1250                         {
1251                             case MDY:   // yes, "10-Jan-94" is valid
1252                             case DMY:
1253                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1254                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1255                                 break;
1256                             case YMD:
1257                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1258                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1259                                 break;
1260                             default:
1261                                 res = sal_False;
1262                                 break;
1263                         }
1264                         break;
1265                     default:            // else, e.g. month at the end (94 10 Jan)
1266                         res = sal_False;
1267                         break;
1268                 }   // switch (nMonthPos)
1269                 break;
1270 
1271             default:                // more than two numbers (31.12.94 8:23) (31.12. 8:23)
1272                 switch (nMonthPos)  // where is the month
1273                 {
1274                     case 0:             // not found
1275                     {
1276                         nCounter = 3;
1277                         if ( nTimePos > 1 )
1278                         {   // find first time number index (should only be 3 or 2 anyway)
1279                             for ( sal_uInt16 j = 0; j < nAnzNums; j++ )
1280                             {
1281                                 if ( nNums[j] == nTimePos - 2 )
1282                                 {
1283                                     nCounter = j;
1284                                     break;  // for
1285                                 }
1286                             }
1287                         }
1288                         // ISO 8601 yyyy-mm-dd forced recognition
1289                         DateFormat eDF = (MayBeIso8601() ? YMD : DateFmt);
1290                         switch (eDF)
1291                         {
1292                             case MDY:
1293                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1294                                 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(0) );
1295                                 if ( nCounter > 2 )
1296                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1297                                 break;
1298                             case DMY:
1299                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1300                                 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1301                                 if ( nCounter > 2 )
1302                                     pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(2) );
1303                                 break;
1304                             case YMD:
1305                                 if ( nCounter > 2 )
1306                                     pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(2) );
1307                                 pCal->setValue( CalendarFieldIndex::MONTH, ImplGetMonth(1) );
1308                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1309                                 break;
1310                             default:
1311                                 res = sal_False;
1312                                 break;
1313                         }
1314                     }
1315                         break;
1316                     case 1:             // month at the beginning (Jan 01 01 8:23)
1317                         nCounter = 2;
1318                         switch (DateFmt)
1319                         {
1320                             case MDY:
1321                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1322                                 pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1323                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1324                                 break;
1325                             default:
1326                                 res = sal_False;
1327                                 break;
1328                         }
1329                         break;
1330                     case 2:             // month in the middle (10 Jan 94 8:23)
1331                         nCounter = 2;
1332                         pCal->setValue( CalendarFieldIndex::MONTH, Abs(nMonth)-1 );
1333                         switch (DateFmt)
1334                         {
1335                             case DMY:
1336                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(0) );
1337                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(1) );
1338                                 break;
1339                             case YMD:
1340                                 pCal->setValue( CalendarFieldIndex::DAY_OF_MONTH, ImplGetDay(1) );
1341                                 pCal->setValue( CalendarFieldIndex::YEAR, ImplGetYear(0) );
1342                                 break;
1343                             default:
1344                                 res = sal_False;
1345                                 break;
1346                         }
1347                         break;
1348                     default:            // else, e.g. month at the end (94 10 Jan 8:23)
1349                         nCounter = 2;
1350                         res = sal_False;
1351                         break;
1352                 }   // switch (nMonthPos)
1353                 break;
1354         }   // switch (nAnzNums)
1355 
1356         if ( res && pCal->isValid() )
1357         {
1358             double fDiff = DateTime(*pNullDate) - pCal->getEpochStart();
1359             fDays = ::rtl::math::approxFloor( pCal->getLocalDateTime() );
1360             fDays -= fDiff;
1361             nTryOrder = nFormatOrder;   // break for
1362         }
1363         else
1364             res = sal_False;
1365 
1366         if ( aOrgCalendar.Len() )
1367             pCal->loadCalendar( aOrgCalendar, pLoc->getLocale() );  // restore calendar
1368 
1369 #if NF_TEST_CALENDAR
1370 {
1371     using namespace ::com::sun::star;
1372     struct entry { const char* lan; const char* cou; const char* cal; };
1373     const entry cals[] = {
1374         { "en", "US",  "gregorian" },
1375         { "ar", "TN",      "hijri" },
1376         { "he", "IL",     "jewish" },
1377         { "ja", "JP",     "gengou" },
1378         { "ko", "KR", "hanja_yoil" },
1379         { "th", "TH",   "buddhist" },
1380         { "zh", "TW",        "ROC" },
1381         {0,0,0}
1382     };
1383     lang::Locale aLocale;
1384     sal_Bool bValid;
1385     sal_Int16 nDay, nMyMonth, nYear, nHour, nMinute, nSecond;
1386     sal_Int16 nDaySet, nMonthSet, nYearSet, nHourSet, nMinuteSet, nSecondSet;
1387     sal_Int16 nZO, nDST1, nDST2, nDST, nZOmillis, nDST1millis, nDST2millis, nDSTmillis;
1388     sal_Int32 nZoneInMillis, nDST1InMillis, nDST2InMillis;
1389     uno::Reference< lang::XMultiServiceFactory > xSMgr =
1390         ::comphelper::getProcessServiceFactory();
1391     uno::Reference< ::com::sun::star::i18n::XExtendedCalendar > xCal(
1392             xSMgr->createInstance( ::rtl::OUString(
1393                     RTL_CONSTASCII_USTRINGPARAM(
1394                         "com.sun.star.i18n.LocaleCalendar" ) ) ),
1395             uno::UNO_QUERY );
1396     for ( const entry* p = cals; p->lan; ++p )
1397     {
1398         aLocale.Language = ::rtl::OUString::createFromAscii( p->lan );
1399         aLocale.Country  = ::rtl::OUString::createFromAscii( p->cou );
1400         xCal->loadCalendar( ::rtl::OUString::createFromAscii( p->cal ),
1401                 aLocale );
1402         double nDateTime = 0.0;     // 1-Jan-1970 00:00:00
1403         nZO           = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1404         nZOmillis     = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1405         nZoneInMillis = static_cast<sal_Int32>(nZO) * 60000 +
1406             (nZO < 0 ? -1 : 1) * static_cast<sal_uInt16>(nZOmillis);
1407         nDST1         = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1408         nDST1millis   = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1409         nDST1InMillis = static_cast<sal_Int32>(nDST1) * 60000 +
1410             (nDST1 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST1millis);
1411         nDateTime    -= (double)(nZoneInMillis + nDST1InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1412         xCal->setDateTime( nDateTime );
1413         nDST2         = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1414         nDST2millis   = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1415         nDST2InMillis = static_cast<sal_Int32>(nDST2) * 60000 +
1416             (nDST2 < 0 ? -1 : 1) * static_cast<sal_uInt16>(nDST2millis);
1417         if ( nDST1InMillis != nDST2InMillis )
1418         {
1419             nDateTime = 0.0 - (double)(nZoneInMillis + nDST2InMillis) / 1000.0 / 60.0 / 60.0 / 24.0;
1420             xCal->setDateTime( nDateTime );
1421         }
1422         nDaySet    = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
1423         nMonthSet  = xCal->getValue( i18n::CalendarFieldIndex::MONTH );
1424         nYearSet   = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
1425         nHourSet   = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
1426         nMinuteSet = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
1427         nSecondSet = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
1428         nZO        = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET );
1429         nZOmillis  = xCal->getValue( i18n::CalendarFieldIndex::ZONE_OFFSET_SECOND_MILLIS );
1430         nDST       = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET );
1431         nDSTmillis = xCal->getValue( i18n::CalendarFieldIndex::DST_OFFSET_SECOND_MILLIS );
1432         xCal->setValue( i18n::CalendarFieldIndex::DAY_OF_MONTH, nDaySet );
1433         xCal->setValue( i18n::CalendarFieldIndex::MONTH, nMonthSet );
1434         xCal->setValue( i18n::CalendarFieldIndex::YEAR, nYearSet );
1435         xCal->setValue( i18n::CalendarFieldIndex::HOUR, nHourSet );
1436         xCal->setValue( i18n::CalendarFieldIndex::MINUTE, nMinuteSet );
1437         xCal->setValue( i18n::CalendarFieldIndex::SECOND, nSecondSet );
1438         bValid  = xCal->isValid();
1439         nDay    = xCal->getValue( i18n::CalendarFieldIndex::DAY_OF_MONTH );
1440         nMyMonth= xCal->getValue( i18n::CalendarFieldIndex::MONTH );
1441         nYear   = xCal->getValue( i18n::CalendarFieldIndex::YEAR );
1442         nHour   = xCal->getValue( i18n::CalendarFieldIndex::HOUR );
1443         nMinute = xCal->getValue( i18n::CalendarFieldIndex::MINUTE );
1444         nSecond = xCal->getValue( i18n::CalendarFieldIndex::SECOND );
1445         bValid = bValid && nDay == nDaySet && nMyMonth == nMonthSet && nYear ==
1446             nYearSet && nHour == nHourSet && nMinute == nMinuteSet && nSecond
1447             == nSecondSet;
1448     }
1449 }
1450 #endif  // NF_TEST_CALENDAR
1451 
1452     }
1453 
1454     return res;
1455 }
1456 
1457 
1458 //---------------------------------------------------------------------------
1459 //      ScanStartString
1460 //
1461 // Analyze the beginning of the string
1462 // Everything gone => sal_True
1463 // else            => sal_False
1464 
ScanStartString(const String & rString,const SvNumberformat * pFormat)1465 sal_Bool ImpSvNumberInputScan::ScanStartString( const String& rString,
1466         const SvNumberformat* pFormat )
1467 {
1468     xub_StrLen nPos = 0;
1469     int nDayOfWeek;
1470 
1471     // First of all, eat leading blanks
1472     SkipBlanks(rString, nPos);
1473 
1474     // Yes, nMatchedAllStrings should know about the sign position
1475     nSign = GetSign(rString, nPos);
1476     if ( nSign )           // sign?
1477         SkipBlanks(rString, nPos);
1478 
1479     // #102371# match against format string only if start string is not a sign character
1480     if ( nMatchedAllStrings && !(nSign && rString.Len() == 1) )
1481     {   // Match against format in any case, so later on for a "x1-2-3" input
1482         // we may distinguish between a xy-m-d (or similar) date and a x0-0-0
1483         // format. No sign detection here!
1484         if ( ScanStringNumFor( rString, nPos, pFormat, 0, sal_True ) )
1485             nMatchedAllStrings |= nMatchedStartString;
1486         else
1487             nMatchedAllStrings = 0;
1488     }
1489 
1490     if ( GetDecSep(rString, nPos) )                 // decimal separator in start string
1491     {
1492         nDecPos = 1;
1493         SkipBlanks(rString, nPos);
1494     }
1495     else if ( GetCurrency(rString, nPos, pFormat) ) // currency (DM 1)?
1496     {
1497         eScannedType = NUMBERFORMAT_CURRENCY;       // !!! it IS currency !!!
1498         SkipBlanks(rString, nPos);
1499         if (nSign == 0)                             // no sign yet
1500         {
1501             nSign = GetSign(rString, nPos);
1502             if ( nSign )   // DM -1
1503                 SkipBlanks(rString, nPos);
1504         }
1505         if ( GetDecSep(rString, nPos) )
1506         {
1507             nDecPos = 1;
1508             SkipBlanks(rString, nPos);
1509         }
1510     }
1511     else
1512     {
1513         nMonth = GetMonth(rString, nPos);
1514         if ( nMonth )    // month (Jan 1)?
1515         {
1516             eScannedType = NUMBERFORMAT_DATE;       // !!! it IS a date !!!
1517             nMonthPos = 1;                          // month at the beginning
1518             if ( nMonth < 0 )
1519                 SkipChar( '.', rString, nPos );     // abbreviated
1520             SkipBlanks(rString, nPos);
1521         }
1522         else
1523         {
1524             nDayOfWeek = GetDayOfWeek( rString, nPos );
1525             if ( nDayOfWeek )
1526             {   // day of week is just parsed away
1527                 eScannedType = NUMBERFORMAT_DATE;       // !!! it IS a date !!!
1528                 if ( nPos < rString.Len() )
1529                 {
1530                     if ( nDayOfWeek < 0 )
1531                     {   // abbreviated
1532                         if ( rString.GetChar( nPos ) == '.' )
1533                             ++nPos;
1534                     }
1535                     else
1536                     {   // full long name
1537                         SkipBlanks(rString, nPos);
1538                         SkipString( pFormatter->GetLocaleData()->getLongDateDayOfWeekSep(), rString, nPos );
1539                     }
1540                     SkipBlanks(rString, nPos);
1541                     nMonth = GetMonth(rString, nPos);
1542                     if ( nMonth ) // month (Jan 1)?
1543                     {
1544                         nMonthPos = 1;                  // month a the beginning
1545                         if ( nMonth < 0 )
1546                             SkipChar( '.', rString, nPos ); // abbreviated
1547                         SkipBlanks(rString, nPos);
1548                     }
1549                 }
1550             }
1551         }
1552     }
1553 
1554     if (nPos < rString.Len())                       // not everything consumed
1555     {
1556         // Does input StartString equal StartString of format?
1557         // This time with sign detection!
1558         if ( !ScanStringNumFor( rString, nPos, pFormat, 0 ) )
1559             return MatchedReturn();
1560     }
1561 
1562     return sal_True;
1563 }
1564 
1565 
1566 //---------------------------------------------------------------------------
1567 //      ScanMidString
1568 //
1569 // Analyze the middle of the string
1570 // Everything gone => sal_True
1571 // else            => sal_False
1572 
ScanMidString(const String & rString,sal_uInt16 nStringPos,const SvNumberformat * pFormat)1573 sal_Bool ImpSvNumberInputScan::ScanMidString( const String& rString,
1574         sal_uInt16 nStringPos, const SvNumberformat* pFormat )
1575 {
1576     xub_StrLen nPos = 0;
1577     short eOldScannedType = eScannedType;
1578 
1579     if ( nMatchedAllStrings )
1580     {   // Match against format in any case, so later on for a "1-2-3-4" input
1581         // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1582         // format.
1583         if ( ScanStringNumFor( rString, 0, pFormat, nStringPos ) )
1584             nMatchedAllStrings |= nMatchedMidString;
1585         else
1586             nMatchedAllStrings = 0;
1587     }
1588 
1589     SkipBlanks(rString, nPos);
1590     if (GetDecSep(rString, nPos))                   // decimal separator?
1591     {
1592         if (nDecPos == 1 || nDecPos == 3)           // .12.4 or 1.E2.1
1593             return MatchedReturn();
1594         else if (nDecPos == 2)                      // . dup: 12.4.
1595         {
1596             if (bDecSepInDateSeps)                  // . also date separator
1597             {
1598                 if (    eScannedType != NUMBERFORMAT_UNDEFINED &&
1599                         eScannedType != NUMBERFORMAT_DATE &&
1600                         eScannedType != NUMBERFORMAT_DATETIME)  // already another type
1601                     return MatchedReturn();
1602                 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1603                     eScannedType = NUMBERFORMAT_DATE;   // !!! it IS a date
1604                 SkipBlanks(rString, nPos);
1605             }
1606             else
1607                 return MatchedReturn();
1608         }
1609         else
1610         {
1611             nDecPos = 2;                            // . in mid string
1612             SkipBlanks(rString, nPos);
1613         }
1614     }
1615     else if ( ((eScannedType & NUMBERFORMAT_TIME) == NUMBERFORMAT_TIME)
1616             && GetTime100SecSep( rString, nPos ) )
1617     {                                               // hundredth seconds separator
1618         if ( nDecPos )
1619             return MatchedReturn();
1620         nDecPos = 2;                                // . in mid string
1621         SkipBlanks(rString, nPos);
1622     }
1623 
1624     if (SkipChar('/', rString, nPos))               // fraction?
1625     {
1626         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1627             && eScannedType != NUMBERFORMAT_DATE)       // except date
1628             return MatchedReturn();                               // => jan/31/1994
1629         else if (    eScannedType != NUMBERFORMAT_DATE      // analyzed date until now
1630                  && (    eSetType == NUMBERFORMAT_FRACTION  // and preset was fraction
1631                      || (nAnzNums == 3                      // or 3 numbers
1632                          && nStringPos > 2) ) )             // and what ???
1633         {
1634             SkipBlanks(rString, nPos);
1635             eScannedType = NUMBERFORMAT_FRACTION;   // !!! it IS a fraction
1636         }
1637         else
1638             nPos--;                                 // put '/' back
1639     }
1640 
1641     if (GetThousandSep(rString, nPos, nStringPos))  // 1,000
1642     {
1643         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1644             && eScannedType != NUMBERFORMAT_CURRENCY)   // except currency
1645             return MatchedReturn();
1646         nThousand++;
1647     }
1648 
1649     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1650     const String& rDate = pFormatter->GetDateSep();
1651     const String& rTime = pLoc->getTimeSep();
1652     sal_Unicode cTime = rTime.GetChar(0);
1653     SkipBlanks(rString, nPos);
1654     if (                      SkipString(rDate, rString, nPos)  // 10., 10-, 10/
1655         || ((cTime != '.') && SkipChar('.',   rString, nPos))   // TRICKY:
1656         || ((cTime != '/') && SkipChar('/',   rString, nPos))   // short boolean
1657         || ((cTime != '-') && SkipChar('-',   rString, nPos)) ) // evaluation!
1658     {
1659         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1660             && eScannedType != NUMBERFORMAT_DATE)       // except date
1661             return MatchedReturn();
1662         SkipBlanks(rString, nPos);
1663         eScannedType = NUMBERFORMAT_DATE;           // !!! it IS a date
1664         short nTmpMonth = GetMonth(rString, nPos);  // 10. Jan 94
1665         if (nMonth && nTmpMonth)                    // month dup
1666             return MatchedReturn();
1667         if (nTmpMonth)
1668         {
1669             nMonth = nTmpMonth;
1670             nMonthPos = 2;                          // month in the middle
1671             if ( nMonth < 0 && SkipChar( '.', rString, nPos ) )
1672                 ;   // short month may be abbreviated Jan.
1673             else if ( SkipChar( '-', rString, nPos ) )
1674                 ;   // #79632# recognize 17-Jan-2001 to be a date
1675                     // #99065# short and long month name
1676             else
1677                 SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1678             SkipBlanks(rString, nPos);
1679         }
1680     }
1681 
1682     short nTempMonth = GetMonth(rString, nPos);     // month in the middle (10 Jan 94)
1683     if (nTempMonth)
1684     {
1685         if (nMonth != 0)                            // month dup
1686             return MatchedReturn();
1687         if (   eScannedType != NUMBERFORMAT_UNDEFINED   // already another type
1688             && eScannedType != NUMBERFORMAT_DATE)       // except date
1689             return MatchedReturn();
1690         eScannedType = NUMBERFORMAT_DATE;           // !!! it IS a date
1691         nMonth = nTempMonth;
1692         nMonthPos = 2;                              // month in the middle
1693         if ( nMonth < 0 )
1694             SkipChar( '.', rString, nPos );         // abbreviated
1695         SkipString( pLoc->getLongDateMonthSep(), rString, nPos );
1696         SkipBlanks(rString, nPos);
1697     }
1698 
1699     if (    SkipChar('E', rString, nPos)            // 10E, 10e, 10,Ee
1700          || SkipChar('e', rString, nPos) )
1701     {
1702         if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1703             return MatchedReturn();
1704         else
1705         {
1706             SkipBlanks(rString, nPos);
1707             eScannedType = NUMBERFORMAT_SCIENTIFIC; // !!! it IS scientific
1708             if (    nThousand+2 == nAnzNums         // special case 1.E2
1709                  && nDecPos == 2 )
1710                 nDecPos = 3;                        // 1,100.E2 1,100,100.E3
1711         }
1712         nESign = GetESign(rString, nPos);           // signed exponent?
1713         SkipBlanks(rString, nPos);
1714     }
1715 
1716     if ( SkipString(rTime, rString, nPos) )         // time separator?
1717     {
1718         if (nDecPos)                                // already . => maybe error
1719         {
1720             if (bDecSepInDateSeps)                  // . also date sep
1721             {
1722                 if (    eScannedType != NUMBERFORMAT_DATE &&    // already another type than date
1723                         eScannedType != NUMBERFORMAT_DATETIME)  // or date time
1724                     return MatchedReturn();
1725                 if (eScannedType == NUMBERFORMAT_DATE)
1726                     nDecPos = 0;                    // reset for time transition
1727             }
1728             else
1729                 return MatchedReturn();
1730         }
1731         if (   (   eScannedType == NUMBERFORMAT_DATE        // already date type
1732                 || eScannedType == NUMBERFORMAT_DATETIME)   // or date time
1733             && nAnzNums > 3)                                // and more than 3 numbers? (31.Dez.94 8:23)
1734         {
1735             SkipBlanks(rString, nPos);
1736             eScannedType = NUMBERFORMAT_DATETIME;   // !!! it IS date with time
1737         }
1738         else if (   eScannedType != NUMBERFORMAT_UNDEFINED  // already another type
1739                  && eScannedType != NUMBERFORMAT_TIME)      // except time
1740             return MatchedReturn();
1741         else
1742         {
1743             SkipBlanks(rString, nPos);
1744             eScannedType = NUMBERFORMAT_TIME;       // !!! it IS a time
1745         }
1746         if ( !nTimePos )
1747             nTimePos = nStringPos + 1;
1748     }
1749 
1750     if (nPos < rString.Len())
1751     {
1752         switch (eScannedType)
1753         {
1754             case NUMBERFORMAT_DATE:
1755                 if (nMonthPos == 1 && pLoc->getLongDateFormat() == MDY)
1756                 {
1757                     // #68232# recognize long date separators like ", " in "September 5, 1999"
1758                     if (SkipString( pLoc->getLongDateDaySep(), rString, nPos ))
1759                         SkipBlanks( rString, nPos );
1760                 }
1761                 else if (nStringPos == 5 && nPos == 0 && rString.Len() == 1 &&
1762                         rString.GetChar(0) == 'T' && MayBeIso8601())
1763                 {
1764                     // ISO 8601 combined date and time, yyyy-mm-ddThh:mm
1765                     ++nPos;
1766                 }
1767                 break;
1768 #if NF_RECOGNIZE_ISO8601_TIMEZONES
1769             case NUMBERFORMAT_DATETIME:
1770                 if (nPos == 0 && rString.Len() == 1 && nStringPos >= 9 &&
1771                         MayBeIso8601())
1772                 {
1773                     // ISO 8601 timezone offset
1774                     switch (rString.GetChar(0))
1775                     {
1776                         case '+':
1777                         case '-':
1778                             if (nStringPos == nAnzStrings-2 ||
1779                                     nStringPos == nAnzStrings-4)
1780                             {
1781                                 ++nPos;     // yyyy-mm-ddThh:mm[:ss]+xx[[:]yy]
1782                                 // nTimezonePos needed for GetTimeRef()
1783                                 if (!nTimezonePos)
1784                                     nTimezonePos = nStringPos + 1;
1785                             }
1786                             break;
1787                         case ':':
1788                             if (nTimezonePos && nStringPos >= 11 &&
1789                                     nStringPos == nAnzStrings-2)
1790                                 ++nPos;     // yyyy-mm-ddThh:mm[:ss]+xx:yy
1791                             break;
1792                     }
1793                 }
1794                 break;
1795 #endif
1796         }
1797     }
1798 
1799     if (nPos < rString.Len())                       // not everything consumed?
1800     {
1801         if ( nMatchedAllStrings & ~nMatchedVirgin )
1802             eScannedType = eOldScannedType;
1803         else
1804             return sal_False;
1805     }
1806 
1807     return sal_True;
1808 }
1809 
1810 
1811 //---------------------------------------------------------------------------
1812 //      ScanEndString
1813 //
1814 // Analyze the conclusion
1815 // Everything gone => sal_True
1816 // else            => sal_False
1817 
ScanEndString(const String & rString,const SvNumberformat * pFormat)1818 sal_Bool ImpSvNumberInputScan::ScanEndString( const String& rString,
1819         const SvNumberformat* pFormat )
1820 {
1821     xub_StrLen nPos = 0;
1822 
1823     if ( nMatchedAllStrings )
1824     {   // Match against format in any case, so later on for a "1-2-3-4" input
1825         // we may distinguish between a y-m-d (or similar) date and a 0-0-0-0
1826         // format.
1827         if ( ScanStringNumFor( rString, 0, pFormat, 0xFFFF ) )
1828             nMatchedAllStrings |= nMatchedEndString;
1829         else
1830             nMatchedAllStrings = 0;
1831     }
1832 
1833     SkipBlanks(rString, nPos);
1834     if (GetDecSep(rString, nPos))                   // decimal separator?
1835     {
1836         if (nDecPos == 1 || nDecPos == 3)           // .12.4 or 12.E4.
1837             return MatchedReturn();
1838         else if (nDecPos == 2)                      // . dup: 12.4.
1839         {
1840             if (bDecSepInDateSeps)                  // . also date sep
1841             {
1842                 if (    eScannedType != NUMBERFORMAT_UNDEFINED &&
1843                         eScannedType != NUMBERFORMAT_DATE &&
1844                         eScannedType != NUMBERFORMAT_DATETIME)  // already another type
1845                     return MatchedReturn();
1846                 if (eScannedType == NUMBERFORMAT_UNDEFINED)
1847                     eScannedType = NUMBERFORMAT_DATE;   // !!! it IS a date
1848                 SkipBlanks(rString, nPos);
1849             }
1850             else
1851                 return MatchedReturn();
1852         }
1853         else
1854         {
1855             nDecPos = 3;                            // . in end string
1856             SkipBlanks(rString, nPos);
1857         }
1858     }
1859 
1860     if (   nSign == 0                               // conflict - not signed
1861         && eScannedType != NUMBERFORMAT_DATE)       // and not date
1862 //!? catch time too?
1863     {                                               // not signed yet
1864         nSign = GetSign(rString, nPos);             // 1- DM
1865         if (nNegCheck)                              // '(' as sign
1866             return MatchedReturn();
1867     }
1868 
1869     SkipBlanks(rString, nPos);
1870     if (nNegCheck && SkipChar(')', rString, nPos))  // skip ')' if appropriate
1871     {
1872         nNegCheck = 0;
1873         SkipBlanks(rString, nPos);
1874     }
1875 
1876     if ( GetCurrency(rString, nPos, pFormat) )      // currency symbol?
1877     {
1878         if (eScannedType != NUMBERFORMAT_UNDEFINED) // currency dup
1879             return MatchedReturn();
1880         else
1881         {
1882             SkipBlanks(rString, nPos);
1883             eScannedType = NUMBERFORMAT_CURRENCY;
1884         }                                           // behind currency a '-' is allowed
1885         if (nSign == 0)                             // not signed yet
1886         {
1887             nSign = GetSign(rString, nPos);         // DM -
1888             SkipBlanks(rString, nPos);
1889             if (nNegCheck)                          // 3 DM (
1890                 return MatchedReturn();
1891         }
1892         if ( nNegCheck && eScannedType == NUMBERFORMAT_CURRENCY
1893                        && SkipChar(')', rString, nPos) )
1894         {
1895             nNegCheck = 0;                          // ')' skipped
1896             SkipBlanks(rString, nPos);              // only if currency
1897         }
1898     }
1899 
1900     if ( SkipChar('%', rString, nPos) )             // 1 %
1901     {
1902         if (eScannedType != NUMBERFORMAT_UNDEFINED) // already another type
1903             return MatchedReturn();
1904         SkipBlanks(rString, nPos);
1905         eScannedType = NUMBERFORMAT_PERCENT;
1906     }
1907 
1908     const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData();
1909     const String& rDate = pFormatter->GetDateSep();
1910     const String& rTime = pLoc->getTimeSep();
1911     if ( SkipString(rTime, rString, nPos) )         // 10:
1912     {
1913         if (nDecPos)                                // already , => error
1914             return MatchedReturn();
1915         if (eScannedType == NUMBERFORMAT_DATE && nAnzNums > 2) // 31.Dez.94 8:
1916         {
1917             SkipBlanks(rString, nPos);
1918             eScannedType = NUMBERFORMAT_DATETIME;
1919         }
1920         else if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1921                  eScannedType != NUMBERFORMAT_TIME) // already another type
1922             return MatchedReturn();
1923         else
1924         {
1925             SkipBlanks(rString, nPos);
1926             eScannedType = NUMBERFORMAT_TIME;
1927         }
1928         if ( !nTimePos )
1929             nTimePos = nAnzStrings;
1930     }
1931 
1932     sal_Unicode cTime = rTime.GetChar(0);
1933     if (                      SkipString(rDate, rString, nPos)  // 10., 10-, 10/
1934         || ((cTime != '.') && SkipChar('.',   rString, nPos))   // TRICKY:
1935         || ((cTime != '/') && SkipChar('/',   rString, nPos))   // short boolean
1936         || ((cTime != '-') && SkipChar('-',   rString, nPos)) ) // evaluation!
1937     {
1938         if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1939             eScannedType != NUMBERFORMAT_DATE)          // already another type
1940             return MatchedReturn();
1941         else
1942         {
1943             SkipBlanks(rString, nPos);
1944             eScannedType = NUMBERFORMAT_DATE;
1945         }
1946         short nTmpMonth = GetMonth(rString, nPos);  // 10. Jan
1947         if (nMonth && nTmpMonth)                    // month dup
1948             return MatchedReturn();
1949         if (nTmpMonth)
1950         {
1951             nMonth = nTmpMonth;
1952             nMonthPos = 3;                          // month at end
1953             if ( nMonth < 0 )
1954                 SkipChar( '.', rString, nPos );     // abbreviated
1955             SkipBlanks(rString, nPos);
1956         }
1957     }
1958 
1959     short nTempMonth = GetMonth(rString, nPos);     // 10 Jan
1960     if (nTempMonth)
1961     {
1962         if (nMonth)                                 // month dup
1963             return MatchedReturn();
1964         if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1965             eScannedType != NUMBERFORMAT_DATE)      // already another type
1966             return MatchedReturn();
1967         eScannedType = NUMBERFORMAT_DATE;
1968         nMonth = nTempMonth;
1969         nMonthPos = 3;                              // month at end
1970         if ( nMonth < 0 )
1971             SkipChar( '.', rString, nPos );         // abbreviated
1972         SkipBlanks(rString, nPos);
1973     }
1974 
1975     xub_StrLen nOrigPos = nPos;
1976     if (GetTimeAmPm(rString, nPos))
1977     {
1978         if (eScannedType != NUMBERFORMAT_UNDEFINED &&
1979             eScannedType != NUMBERFORMAT_TIME &&
1980             eScannedType != NUMBERFORMAT_DATETIME)  // already another type
1981             return MatchedReturn();
1982         else
1983         {
1984             // If not already scanned as time, 6.78am does not result in 6
1985             // seconds and 78 hundredths in the morning. Keep as suffix.
1986             if (eScannedType != NUMBERFORMAT_TIME && nDecPos == 2 && nAnzNums == 2)
1987                 nPos = nOrigPos;     // rewind am/pm
1988             else
1989             {
1990                 SkipBlanks(rString, nPos);
1991                 if ( eScannedType != NUMBERFORMAT_DATETIME )
1992                     eScannedType = NUMBERFORMAT_TIME;
1993             }
1994         }
1995     }
1996 
1997     if ( nNegCheck && SkipChar(')', rString, nPos) )
1998     {
1999         if (eScannedType == NUMBERFORMAT_CURRENCY)  // only if currency
2000         {
2001             nNegCheck = 0;                          // skip ')'
2002             SkipBlanks(rString, nPos);
2003         }
2004         else
2005             return MatchedReturn();
2006     }
2007 
2008     if ( nPos < rString.Len() &&
2009             (eScannedType == NUMBERFORMAT_DATE
2010             || eScannedType == NUMBERFORMAT_DATETIME) )
2011     {   // day of week is just parsed away
2012         xub_StrLen nOldPos = nPos;
2013         const String& rSep = pFormatter->GetLocaleData()->getLongDateDayOfWeekSep();
2014         if ( StringContains( rSep, rString, nPos ) )
2015         {
2016             nPos = nPos + rSep.Len();
2017             SkipBlanks(rString, nPos);
2018         }
2019         int nDayOfWeek = GetDayOfWeek( rString, nPos );
2020         if ( nDayOfWeek )
2021         {
2022             if ( nPos < rString.Len() )
2023             {
2024                 if ( nDayOfWeek < 0 )
2025                 {   // short
2026                     if ( rString.GetChar( nPos ) == '.' )
2027                         ++nPos;
2028                 }
2029                 SkipBlanks(rString, nPos);
2030             }
2031         }
2032         else
2033             nPos = nOldPos;
2034     }
2035 
2036 #if NF_RECOGNIZE_ISO8601_TIMEZONES
2037     if (nPos == 0 && eScannedType == NUMBERFORMAT_DATETIME &&
2038             rString.Len() == 1 && rString.GetChar(0) == 'Z' && MayBeIso8601())
2039     {
2040         // ISO 8601 timezone UTC yyyy-mm-ddThh:mmZ
2041         ++nPos;
2042     }
2043 #endif
2044 
2045     if (nPos < rString.Len())                       // everything consumed?
2046     {
2047         // does input EndString equal EndString in Format?
2048         if ( !ScanStringNumFor( rString, nPos, pFormat, 0xFFFF ) )
2049             return sal_False;
2050     }
2051 
2052     return sal_True;
2053 }
2054 
2055 
ScanStringNumFor(const String & rString,xub_StrLen nPos,const SvNumberformat * pFormat,sal_uInt16 nString,sal_Bool bDontDetectNegation)2056 sal_Bool ImpSvNumberInputScan::ScanStringNumFor(
2057         const String& rString,          // String to scan
2058         xub_StrLen nPos,                // Position until which was consumed
2059         const SvNumberformat* pFormat,  // The format to match
2060         sal_uInt16 nString,                 // Substring of format, 0xFFFF => last
2061         sal_Bool bDontDetectNegation        // Suppress sign detection
2062         )
2063 {
2064     if ( !pFormat )
2065         return sal_False;
2066     const ::utl::TransliterationWrapper* pTransliteration = pFormatter->GetTransliteration();
2067     const String* pStr;
2068     String aString( rString );
2069     sal_Bool bFound = sal_False;
2070     sal_Bool bFirst = sal_True;
2071     sal_Bool bContinue = sal_True;
2072     sal_uInt16 nSub;
2073     do
2074     {
2075         // Don't try "lower" subformats ff the very first match was the second
2076         // or third subformat.
2077         nSub = nStringScanNumFor;
2078         do
2079         {   // Step through subformats, first positive, then negative, then
2080             // other, but not the last (text) subformat.
2081             pStr = pFormat->GetNumForString( nSub, nString, sal_True );
2082             if ( pStr && pTransliteration->isEqual( aString, *pStr ) )
2083             {
2084                 bFound = sal_True;
2085                 bContinue = sal_False;
2086             }
2087             else if ( nSub < 2 )
2088                 ++nSub;
2089             else
2090                 bContinue = sal_False;
2091         } while ( bContinue );
2092         if ( !bFound && bFirst && nPos )
2093         {   // try remaining substring
2094             bFirst = sal_False;
2095             aString.Erase( 0, nPos );
2096             bContinue = sal_True;
2097         }
2098     } while ( bContinue );
2099 
2100     if ( !bFound )
2101     {
2102         if ( !bDontDetectNegation && (nString == 0) && !bFirst && (nSign < 0)
2103                 && pFormat->IsNegativeRealNegative() )
2104         {   // simply negated twice? --1
2105             aString.EraseAllChars( ' ' );
2106             if ( (aString.Len() == 1) && (aString.GetChar(0) == '-') )
2107             {
2108                 bFound = sal_True;
2109                 nStringScanSign = -1;
2110                 nSub = 0;       //! not 1
2111             }
2112         }
2113         if ( !bFound )
2114             return sal_False;
2115     }
2116     else if ( !bDontDetectNegation && (nSub == 1) &&
2117             pFormat->IsNegativeRealNegative() )
2118     {   // negative
2119         if ( nStringScanSign < 0 )
2120         {
2121             if ( (nSign < 0) && (nStringScanNumFor != 1) )
2122                 nStringScanSign = 1;        // triple negated --1 yyy
2123         }
2124         else if ( nStringScanSign == 0 )
2125         {
2126             if ( nSign < 0 )
2127             {   // nSign and nStringScanSign will be combined later,
2128                 // flip sign if doubly negated
2129                 if ( (nString == 0) && !bFirst
2130                         && SvNumberformat::HasStringNegativeSign( aString ) )
2131                     nStringScanSign = -1;   // direct double negation
2132                 else if ( pFormat->IsNegativeWithoutSign() )
2133                     nStringScanSign = -1;   // indirect double negation
2134             }
2135             else
2136                 nStringScanSign = -1;
2137         }
2138         else    // > 0
2139             nStringScanSign = -1;
2140     }
2141     nStringScanNumFor = nSub;
2142     return sal_True;
2143 }
2144 
2145 
2146 //---------------------------------------------------------------------------
2147 //      IsNumberFormatMain
2148 //
2149 // Recognizes types of number, exponential, fraction, percent, currency, date, time.
2150 // Else text => return sal_False
2151 
IsNumberFormatMain(const String & rString,double &,const SvNumberformat * pFormat)2152 sal_Bool ImpSvNumberInputScan::IsNumberFormatMain(
2153         const String& rString,                  // string to be analyzed
2154         double& ,                               // OUT: result as number, if possible
2155         const SvNumberformat* pFormat )         // maybe number format set to match against
2156 {
2157     Reset();
2158     NumberStringDivision( rString );            // breakdown into strings and numbers
2159     if (nAnzStrings >= SV_MAX_ANZ_INPUT_STRINGS) // too many elements
2160         return sal_False;                           // Njet, Nope, ...
2161 
2162     if (nAnzNums == 0)                          // no number in input
2163     {
2164         if ( nAnzStrings > 0 )
2165         {
2166             // Here we may change the original, we don't need it anymore.
2167             // This saves copies and ToUpper() in GetLogical() and is faster.
2168             String& rStrArray = sStrArray[0];
2169             rStrArray.EraseTrailingChars( ' ' );
2170             rStrArray.EraseLeadingChars( ' ' );
2171             nLogical = GetLogical( rStrArray );
2172             if ( nLogical )
2173             {
2174                 eScannedType = NUMBERFORMAT_LOGICAL; // !!! it's a BOOLEAN
2175                 nMatchedAllStrings &= ~nMatchedVirgin;
2176                 return sal_True;
2177             }
2178             else
2179                 return sal_False;                   // simple text
2180         }
2181         else
2182             return sal_False;                       // simple text
2183     }
2184 
2185     sal_uInt16 i = 0;                               // mark any symbol
2186     sal_uInt16 j = 0;                               // mark only numbers
2187 
2188     switch ( nAnzNums )
2189     {
2190         case 1 :                                // Exactly 1 number in input
2191         {                                       // nAnzStrings >= 1
2192             if (GetNextNumber(i,j))             // i=1,0
2193             {                                   // Number at start
2194                 if (eSetType == NUMBERFORMAT_FRACTION)  // Fraction 1 = 1/1
2195                 {
2196                     if (i >= nAnzStrings ||     // no end string nor decimal separator
2197                         sStrArray[i] == pFormatter->GetNumDecimalSep())
2198                     {
2199                         eScannedType = NUMBERFORMAT_FRACTION;
2200                         nMatchedAllStrings &= ~nMatchedVirgin;
2201                         return sal_True;
2202                     }
2203                 }
2204             }
2205             else
2206             {                                   // Analyze start string
2207                 if (!ScanStartString( sStrArray[i], pFormat ))  // i=0
2208                     return sal_False;               // already an error
2209                 i++;                            // next symbol, i=1
2210             }
2211             GetNextNumber(i,j);                 // i=1,2
2212             if (eSetType == NUMBERFORMAT_FRACTION)  // Fraction -1 = -1/1
2213             {
2214                 if (nSign && !nNegCheck &&      // Sign +, -
2215                     eScannedType == NUMBERFORMAT_UNDEFINED &&   // not date or currency
2216                     nDecPos == 0 &&             // no previous decimal separator
2217                     (i >= nAnzStrings ||        // no end string nor decimal separator
2218                         sStrArray[i] == pFormatter->GetNumDecimalSep())
2219                 )
2220                 {
2221                     eScannedType = NUMBERFORMAT_FRACTION;
2222                     nMatchedAllStrings &= ~nMatchedVirgin;
2223                     return sal_True;
2224                 }
2225             }
2226             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2227                     return sal_False;
2228         }
2229         break;
2230         case 2 :                                // Exactly 2 numbers in input
2231         {                                       // nAnzStrings >= 3
2232             if (!GetNextNumber(i,j))            // i=1,0
2233             {                                   // Analyze start string
2234                 if (!ScanStartString( sStrArray[i], pFormat ))
2235                     return sal_False;               // already an error
2236                 i++;                            // i=1
2237             }
2238             GetNextNumber(i,j);                 // i=1,2
2239             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2240                 return sal_False;
2241             i++;                                // next symbol, i=2,3
2242             GetNextNumber(i,j);                 // i=3,4
2243             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2244                 return sal_False;
2245             if (eSetType == NUMBERFORMAT_FRACTION)  // -1,200. as fraction
2246             {
2247                 if (!nNegCheck  &&                  // no sign '('
2248                     eScannedType == NUMBERFORMAT_UNDEFINED &&
2249                     (nDecPos == 0 || nDecPos == 3)  // no decimal separator or at end
2250                     )
2251                 {
2252                     eScannedType = NUMBERFORMAT_FRACTION;
2253                     nMatchedAllStrings &= ~nMatchedVirgin;
2254                     return sal_True;
2255                 }
2256             }
2257         }
2258         break;
2259         case 3 :                                // Exactly 3 numbers in input
2260         {                                       // nAnzStrings >= 5
2261             if (!GetNextNumber(i,j))            // i=1,0
2262             {                                   // Analyze start string
2263                 if (!ScanStartString( sStrArray[i], pFormat ))
2264                     return sal_False;               // already an error
2265                 i++;                            // i=1
2266                 if (nDecPos == 1)               // decimal separator at start => error
2267                     return sal_False;
2268             }
2269             GetNextNumber(i,j);                 // i=1,2
2270             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2271                 return sal_False;
2272             i++;                                // i=2,3
2273             if (eScannedType == NUMBERFORMAT_SCIENTIFIC)    // E only at end
2274                 return sal_False;
2275             GetNextNumber(i,j);                 // i=3,4
2276             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2277                 return sal_False;
2278             i++;                                // i=4,5
2279             GetNextNumber(i,j);                 // i=5,6
2280             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2281                 return sal_False;
2282             if (eSetType == NUMBERFORMAT_FRACTION)  // -1,200,100. as fraction
2283             {
2284                 if (!nNegCheck  &&                  // no sign '('
2285                     eScannedType == NUMBERFORMAT_UNDEFINED &&
2286                     (nDecPos == 0 || nDecPos == 3)  // no decimal separator or at end
2287                 )
2288                 {
2289                     eScannedType = NUMBERFORMAT_FRACTION;
2290                     nMatchedAllStrings &= ~nMatchedVirgin;
2291                     return sal_True;
2292                 }
2293             }
2294             if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2295                 return sal_False;                   // #36857# not a real fraction
2296         }
2297         break;
2298         default:                                // More than 3 numbers in input
2299         {                                       // nAnzStrings >= 7
2300             if (!GetNextNumber(i,j))            // i=1,0
2301             {                                   // Analyze startstring
2302                 if (!ScanStartString( sStrArray[i], pFormat ))
2303                     return sal_False;               // already an error
2304                 i++;                            // i=1
2305                 if (nDecPos == 1)               // decimal separator at start => error
2306                     return sal_False;
2307             }
2308             GetNextNumber(i,j);                 // i=1,2
2309             if ( !ScanMidString( sStrArray[i], i, pFormat ) )
2310                 return sal_False;
2311             i++;                                // i=2,3
2312             sal_uInt16 nThOld = 10;                 // just not 0 or 1
2313             while (nThOld != nThousand && j < nAnzNums-1)
2314                                                 // Execute at least one time
2315                                                 // but leave one number.
2316             {                                   // Loop over group separators
2317                 nThOld = nThousand;
2318                 if (eScannedType == NUMBERFORMAT_SCIENTIFIC)    // E only at end
2319                     return sal_False;
2320                 GetNextNumber(i,j);
2321                 if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2322                     return sal_False;
2323                 i++;
2324             }
2325             if (eScannedType == NUMBERFORMAT_DATE ||    // long date or
2326                 eScannedType == NUMBERFORMAT_TIME ||    // long time or
2327                 eScannedType == NUMBERFORMAT_UNDEFINED) // long number
2328             {
2329                 for (sal_uInt16 k = j; k < nAnzNums-1; k++)
2330                 {
2331                     if (eScannedType == NUMBERFORMAT_SCIENTIFIC)    // E only at endd
2332                         return sal_False;
2333                     GetNextNumber(i,j);
2334                     if ( i < nAnzStrings && !ScanMidString( sStrArray[i], i, pFormat ) )
2335                         return sal_False;
2336                     i++;
2337                 }
2338             }
2339             GetNextNumber(i,j);
2340             if (i < nAnzStrings && !ScanEndString( sStrArray[i], pFormat ))
2341                 return sal_False;
2342             if (eSetType == NUMBERFORMAT_FRACTION)  // -1,200,100. as fraction
2343             {
2344                 if (!nNegCheck  &&                  // no sign '('
2345                     eScannedType == NUMBERFORMAT_UNDEFINED &&
2346                     (nDecPos == 0 || nDecPos == 3)  // no decimal separator or at end
2347                 )
2348                 {
2349                     eScannedType = NUMBERFORMAT_FRACTION;
2350                     nMatchedAllStrings &= ~nMatchedVirgin;
2351                     return sal_True;
2352                 }
2353             }
2354             if ( eScannedType == NUMBERFORMAT_FRACTION && nDecPos )
2355                 return sal_False;                       // #36857# not a real fraction
2356         }
2357     }
2358 
2359     if (eScannedType == NUMBERFORMAT_UNDEFINED)
2360     {
2361         nMatchedAllStrings &= ~nMatchedVirgin;
2362         // did match including nMatchedUsedAsReturn
2363         sal_Bool bDidMatch = (nMatchedAllStrings != 0);
2364         if ( nMatchedAllStrings )
2365         {
2366             sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2367                         nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False);
2368             if ( !bMatch )
2369                 nMatchedAllStrings = 0;
2370         }
2371         if ( nMatchedAllStrings )
2372             eScannedType = eSetType;
2373         else if ( bDidMatch )
2374             return sal_False;
2375         else
2376             eScannedType = NUMBERFORMAT_NUMBER;
2377             // everything else should have been recognized by now
2378     }
2379     else if ( eScannedType == NUMBERFORMAT_DATE )
2380     {   // the very relaxed date input checks may interfere with a preset format
2381         nMatchedAllStrings &= ~nMatchedVirgin;
2382         sal_Bool bWasReturn = ((nMatchedAllStrings & nMatchedUsedAsReturn) != 0);
2383         if ( nMatchedAllStrings )
2384         {
2385             sal_Bool bMatch = (pFormat ? pFormat->IsNumForStringElementCountEqual(
2386                         nStringScanNumFor, nAnzStrings, nAnzNums ) : sal_False);
2387             if ( !bMatch )
2388                 nMatchedAllStrings = 0;
2389         }
2390         if ( nMatchedAllStrings )
2391             eScannedType = eSetType;
2392         else if ( bWasReturn )
2393             return sal_False;
2394     }
2395     else
2396         nMatchedAllStrings = 0;  // reset flag to no substrings matched
2397 
2398     return sal_True;
2399 }
2400 
2401 
2402 //---------------------------------------------------------------------------
2403 // return sal_True or sal_False depending on the nMatched... state and remember usage
MatchedReturn()2404 sal_Bool ImpSvNumberInputScan::MatchedReturn()
2405 {
2406     if ( nMatchedAllStrings & ~nMatchedVirgin )
2407     {
2408         nMatchedAllStrings |= nMatchedUsedAsReturn;
2409         return sal_True;
2410     }
2411     return sal_False;
2412 }
2413 
2414 
2415 //---------------------------------------------------------------------------
2416 // Initialize uppercase months and weekdays
2417 
InitText()2418 void ImpSvNumberInputScan::InitText()
2419 {
2420     sal_Int32 j, nElems;
2421     const CharClass* pChrCls = pFormatter->GetCharClass();
2422     const CalendarWrapper* pCal = pFormatter->GetCalendar();
2423     delete [] pUpperMonthText;
2424     delete [] pUpperAbbrevMonthText;
2425     ::com::sun::star::uno::Sequence< ::com::sun::star::i18n::CalendarItem > xElems
2426         = pCal->getMonths();
2427     nElems = xElems.getLength();
2428     pUpperMonthText = new String[nElems];
2429     pUpperAbbrevMonthText = new String[nElems];
2430     for ( j=0; j<nElems; j++ )
2431     {
2432         pUpperMonthText[j] = pChrCls->upper( xElems[j].FullName );
2433         pUpperAbbrevMonthText[j] = pChrCls->upper( xElems[j].AbbrevName );
2434     }
2435     delete [] pUpperDayText;
2436     delete [] pUpperAbbrevDayText;
2437     xElems = pCal->getDays();
2438     nElems = xElems.getLength();
2439     pUpperDayText = new String[nElems];
2440     pUpperAbbrevDayText = new String[nElems];
2441     for ( j=0; j<nElems; j++ )
2442     {
2443         pUpperDayText[j] = pChrCls->upper( xElems[j].FullName );
2444         pUpperAbbrevDayText[j] = pChrCls->upper( xElems[j].AbbrevName );
2445     }
2446     bTextInitialized = sal_True;
2447 }
2448 
2449 
2450 //===========================================================================
2451 //          P U B L I C
2452 
2453 //---------------------------------------------------------------------------
2454 //      ChangeIntl
2455 //
2456 // MUST be called if International/Locale is changed
2457 
ChangeIntl()2458 void ImpSvNumberInputScan::ChangeIntl()
2459 {
2460     sal_Unicode cDecSep = pFormatter->GetNumDecimalSep().GetChar(0);
2461     bDecSepInDateSeps = ( cDecSep == '-' ||
2462                           cDecSep == '/' ||
2463                           cDecSep == '.' ||
2464                           cDecSep == pFormatter->GetDateSep().GetChar(0) );
2465     bTextInitialized = sal_False;
2466     aUpperCurrSymbol.Erase();
2467 }
2468 
2469 
2470 //---------------------------------------------------------------------------
2471 //      ChangeNullDate
2472 
ChangeNullDate(const sal_uInt16 Day,const sal_uInt16 Month,const sal_uInt16 Year)2473 void ImpSvNumberInputScan::ChangeNullDate(
2474         const sal_uInt16 Day,
2475         const sal_uInt16 Month,
2476         const sal_uInt16 Year )
2477 {
2478     if ( pNullDate )
2479         *pNullDate = Date(Day, Month, Year);
2480     else
2481         pNullDate = new Date(Day, Month, Year);
2482 }
2483 
2484 
2485 //---------------------------------------------------------------------------
2486 //      IsNumberFormat
2487 //
2488 // => does rString represent a number (also date, time et al)
2489 
IsNumberFormat(const String & rString,short & F_Type,double & fOutNumber,const SvNumberformat * pFormat)2490 sal_Bool ImpSvNumberInputScan::IsNumberFormat(
2491         const String& rString,                  // string to be analyzed
2492         short& F_Type,                          // IN: old type, OUT: new type
2493         double& fOutNumber,                     // OUT: number if convertable
2494         const SvNumberformat* pFormat )         // maybe a number format to match against
2495 {
2496     String sResString;
2497     String aString;
2498     sal_Bool res;                                   // return value
2499     eSetType = F_Type;                          // old type set
2500 
2501     if ( !rString.Len() )
2502         res = sal_False;
2503     else if (rString.Len() > 308)               // arbitrary
2504         res = sal_False;
2505     else
2506     {
2507         // NoMoreUpperNeeded, all comparisons on UpperCase
2508         aString = pFormatter->GetCharClass()->upper( rString );
2509         // convert native number to ASCII if necessary
2510         TransformInput( aString );
2511         res = IsNumberFormatMain( aString, fOutNumber, pFormat );
2512     }
2513 
2514     if (res)
2515     {
2516         if ( nNegCheck                              // ')' not found for '('
2517                 || (nSign && (eScannedType == NUMBERFORMAT_DATE
2518                     || eScannedType == NUMBERFORMAT_DATETIME))
2519             )                                       // signed date/datetime
2520             res = sal_False;
2521         else
2522         {                                           // check count of partial number strings
2523             switch (eScannedType)
2524             {
2525                 case NUMBERFORMAT_PERCENT:
2526                 case NUMBERFORMAT_CURRENCY:
2527                 case NUMBERFORMAT_NUMBER:
2528                     if (nDecPos == 1)               // .05
2529                     {
2530                         // matched MidStrings function like group separators
2531                         if ( nMatchedAllStrings )
2532                             nThousand = nAnzNums - 1;
2533                         else if ( nAnzNums != 1 )
2534                             res = sal_False;
2535                     }
2536                     else if (nDecPos == 2)          // 1.05
2537                     {
2538                         // matched MidStrings function like group separators
2539                         if ( nMatchedAllStrings )
2540                             nThousand = nAnzNums - 1;
2541                         else if ( nAnzNums != nThousand+2 )
2542                             res = sal_False;
2543                     }
2544                     else                            // 1,100 or 1,100.
2545                     {
2546                         // matched MidStrings function like group separators
2547                         if ( nMatchedAllStrings )
2548                             nThousand = nAnzNums - 1;
2549                         else if ( nAnzNums != nThousand+1 )
2550                             res = sal_False;
2551                     }
2552                     break;
2553 
2554                 case NUMBERFORMAT_SCIENTIFIC:       // 1.0e-2
2555                     if (nDecPos == 1)               // .05
2556                     {
2557                         if (nAnzNums != 2)
2558                             res = sal_False;
2559                     }
2560                     else if (nDecPos == 2)          // 1.05
2561                     {
2562                         if (nAnzNums != nThousand+3)
2563                             res = sal_False;
2564                     }
2565                     else                            // 1,100 or 1,100.
2566                     {
2567                         if (nAnzNums != nThousand+2)
2568                             res = sal_False;
2569                     }
2570                     break;
2571 
2572                 case NUMBERFORMAT_DATE:
2573                     if (nMonth)
2574                     {                               // month name and numbers
2575                         if (nAnzNums > 2)
2576                             res = sal_False;
2577                     }
2578                     else
2579                     {
2580                         if (nAnzNums > 3)
2581                             res = sal_False;
2582                     }
2583                     break;
2584 
2585                 case NUMBERFORMAT_TIME:
2586                     if (nDecPos)
2587                     {                               // hundredth seconds included
2588                         if (nAnzNums > 4)
2589                             res = sal_False;
2590                     }
2591                     else
2592                     {
2593                         if (nAnzNums > 3)
2594                             res = sal_False;
2595                     }
2596                     break;
2597 
2598                 case NUMBERFORMAT_DATETIME:
2599                     if (nMonth)
2600                     {                               // month name and numbers
2601                         if (nDecPos)
2602                         {                           // hundredth seconds included
2603                             if (nAnzNums > 6)
2604                                 res = sal_False;
2605                         }
2606                         else
2607                         {
2608                             if (nAnzNums > 5)
2609                                 res = sal_False;
2610                         }
2611                     }
2612                     else
2613                     {
2614                         if (nDecPos)
2615                         {                           // hundredth seconds included
2616                             if (nAnzNums > 7)
2617                                 res = sal_False;
2618                         }
2619                         else
2620                         {
2621                             if (nAnzNums > 6)
2622                                 res = sal_False;
2623                         }
2624                     }
2625                     break;
2626 
2627                 default:
2628                     break;
2629             }   // switch
2630         }   // else
2631     }   // if (res)
2632 
2633     if (res)
2634     {                                           // we finally have a number
2635         switch (eScannedType)
2636         {
2637             case NUMBERFORMAT_LOGICAL:
2638                 if      (nLogical ==  1)
2639                     fOutNumber = 1.0;           // True
2640                 else if (nLogical == -1)
2641                     fOutNumber = 0.0;           // False
2642                 else
2643                     res = sal_False;                // Oops
2644                 break;
2645 
2646             case NUMBERFORMAT_PERCENT:
2647             case NUMBERFORMAT_CURRENCY:
2648             case NUMBERFORMAT_NUMBER:
2649             case NUMBERFORMAT_SCIENTIFIC:
2650             case NUMBERFORMAT_DEFINED:          // if no category detected handle as number
2651             {
2652                 if ( nDecPos == 1 )                         // . at start
2653                     sResString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0." ) );
2654                 else
2655                     sResString.Erase();
2656                 sal_uInt16 k;
2657                 for ( k = 0; k <= nThousand; k++)
2658                     sResString += sStrArray[nNums[k]];  // integer part
2659                 if ( nDecPos == 2 && k < nAnzNums )     // . somewhere
2660                 {
2661                     sResString += '.';
2662                     sal_uInt16 nStop = (eScannedType == NUMBERFORMAT_SCIENTIFIC ?
2663                             nAnzNums-1 : nAnzNums);
2664                     for ( ; k < nStop; k++)
2665                         sResString += sStrArray[nNums[k]];  // fractional part
2666                 }
2667 
2668                 if (eScannedType != NUMBERFORMAT_SCIENTIFIC)
2669                     fOutNumber = StringToDouble(sResString);
2670                 else
2671                 {                                           // append exponent
2672                     sResString += 'E';
2673                     if ( nESign == -1 )
2674                         sResString += '-';
2675                     sResString += sStrArray[nNums[nAnzNums-1]];
2676                     rtl_math_ConversionStatus eStatus;
2677                     fOutNumber = ::rtl::math::stringToDouble(
2678                         sResString, '.', ',', &eStatus, NULL );
2679                     if ( eStatus == rtl_math_ConversionStatus_OutOfRange )
2680                     {
2681                         F_Type = NUMBERFORMAT_TEXT;         // overflow/underflow -> Text
2682                         if (nESign == -1)
2683                             fOutNumber = 0.0;
2684                         else
2685                             fOutNumber = DBL_MAX;
2686 /*!*/                   return sal_True;
2687                     }
2688                 }
2689 
2690                 if ( nStringScanSign )
2691                 {
2692                     if ( nSign )
2693                         nSign *= nStringScanSign;
2694                     else
2695                         nSign = nStringScanSign;
2696                 }
2697                 if ( nSign < 0 )
2698                     fOutNumber = -fOutNumber;
2699 
2700                 if (eScannedType == NUMBERFORMAT_PERCENT)
2701                     fOutNumber/= 100.0;
2702             }
2703             break;
2704 
2705             case NUMBERFORMAT_FRACTION:
2706                 if (nAnzNums == 1)
2707                     fOutNumber = StringToDouble(sStrArray[nNums[0]]);
2708                 else if (nAnzNums == 2)
2709                 {
2710                     if (nThousand == 1)
2711                     {
2712                         sResString = sStrArray[nNums[0]];
2713                         sResString += sStrArray[nNums[1]];  // integer part
2714                         fOutNumber = StringToDouble(sResString);
2715                     }
2716                     else
2717                     {
2718                         double fZaehler = StringToDouble(sStrArray[nNums[0]]);
2719                         double fNenner = StringToDouble(sStrArray[nNums[1]]);
2720                         if (fNenner != 0.0)
2721                             fOutNumber = fZaehler/fNenner;
2722                         else
2723                             res = sal_False;
2724                     }
2725                 }
2726                 else                                        // nAnzNums > 2
2727                 {
2728                     sal_uInt16 k = 1;
2729                     sResString = sStrArray[nNums[0]];
2730                     if (nThousand > 0)
2731                         for (k = 1; k <= nThousand; k++)
2732                             sResString += sStrArray[nNums[k]];
2733                     fOutNumber = StringToDouble(sResString);
2734 
2735                     if (k == nAnzNums-2)
2736                     {
2737                         double fZaehler = StringToDouble(sStrArray[nNums[k]]);
2738                         double fNenner = StringToDouble(sStrArray[nNums[k+1]]);
2739                         if (fNenner != 0.0)
2740                             fOutNumber += fZaehler/fNenner;
2741                         else
2742                             res = sal_False;
2743                     }
2744                 }
2745 
2746                 if ( nStringScanSign )
2747                 {
2748                     if ( nSign )
2749                         nSign *= nStringScanSign;
2750                     else
2751                         nSign = nStringScanSign;
2752                 }
2753                 if ( nSign < 0 )
2754                     fOutNumber = -fOutNumber;
2755                 break;
2756 
2757             case NUMBERFORMAT_TIME:
2758                 GetTimeRef(fOutNumber, 0, nAnzNums);
2759                 if ( nSign < 0 )
2760                     fOutNumber = -fOutNumber;
2761                 break;
2762 
2763             case NUMBERFORMAT_DATE:
2764             {
2765                 sal_uInt16 nCounter = 0;                        // dummy here
2766                 res = GetDateRef( fOutNumber, nCounter, pFormat );
2767             }
2768             break;
2769 
2770             case NUMBERFORMAT_DATETIME:
2771             {
2772                 sal_uInt16 nCounter = 0;                        // needed here
2773                 res = GetDateRef( fOutNumber, nCounter, pFormat );
2774                 if ( res )
2775                 {
2776                     double fTime;
2777                     GetTimeRef( fTime, nCounter, nAnzNums - nCounter );
2778                     fOutNumber += fTime;
2779                 }
2780             }
2781             break;
2782 
2783             default:
2784                 DBG_ERRORFILE( "Some number recognized but what's it?" );
2785                 fOutNumber = 0.0;
2786                 break;
2787         }
2788     }
2789 
2790     if (res)        // overflow/underflow -> Text
2791     {
2792         if      (fOutNumber < -DBL_MAX) // -1.7E308
2793         {
2794             F_Type = NUMBERFORMAT_TEXT;
2795             fOutNumber = -DBL_MAX;
2796             return sal_True;
2797         }
2798         else if (fOutNumber >  DBL_MAX) // 1.7E308
2799         {
2800             F_Type = NUMBERFORMAT_TEXT;
2801             fOutNumber = DBL_MAX;
2802             return sal_True;
2803         }
2804     }
2805 
2806     if (res == sal_False)
2807     {
2808         eScannedType = NUMBERFORMAT_TEXT;
2809         fOutNumber = 0.0;
2810     }
2811 
2812     F_Type = eScannedType;
2813     return res;
2814 }
2815 
2816 
2817 
2818