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