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