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