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