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