1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_svl.hxx" 30 #include <stdio.h> 31 #include <ctype.h> 32 #include <float.h> 33 // #include <math.h> 34 #include <errno.h> 35 #include <stdlib.h> 36 #include <tools/debug.hxx> 37 #include <i18npool/mslangid.hxx> 38 #include <rtl/math.hxx> 39 #include <rtl/instance.hxx> 40 #include <unotools/charclass.hxx> 41 #include <unotools/calendarwrapper.hxx> 42 #include <unotools/nativenumberwrapper.hxx> 43 #include <com/sun/star/i18n/CalendarFieldIndex.hpp> 44 #include <com/sun/star/i18n/CalendarDisplayIndex.hpp> 45 #include <com/sun/star/i18n/CalendarDisplayCode.hpp> 46 #include <com/sun/star/i18n/AmPmValue.hpp> 47 48 #define _ZFORMAT_CXX 49 #include <svl/zformat.hxx> 50 #include <zforscan.hxx> 51 52 #include "zforfind.hxx" 53 #include <svl/zforlist.hxx> 54 #include "numhead.hxx" 55 #include <unotools/digitgroupingiterator.hxx> 56 #include <svl/nfsymbol.hxx> 57 58 #include <cmath> 59 60 using namespace svt; 61 62 namespace { 63 struct Gregorian 64 : public rtl::StaticWithInit<const ::rtl::OUString, Gregorian> { 65 const ::rtl::OUString operator () () { 66 return ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("gregorian")); 67 } 68 }; 69 70 const sal_uInt16 UPPER_PRECISION = 300; // entirely arbitrary... 71 const double EXP_LOWER_BOUND = 1.0E-4; // prefer scientific notation below this value. 72 73 } 74 75 const double _D_MAX_U_LONG_ = (double) 0xffffffff; // 4294967295.0 76 const double _D_MAX_LONG_ = (double) 0x7fffffff; // 2147483647.0 77 const sal_uInt16 _MAX_FRACTION_PREC = 3; 78 const double D_EPS = 1.0E-2; 79 80 const double _D_MAX_D_BY_100 = 1.7E306; 81 const double _D_MIN_M_BY_1000 = 2.3E-305; 82 83 static sal_uInt8 cCharWidths[ 128-32 ] = { 84 1,1,1,2,2,3,2,1,1,1,1,2,1,1,1,1, 85 2,2,2,2,2,2,2,2,2,2,1,1,2,2,2,2, 86 3,2,2,2,2,2,2,3,2,1,2,2,2,3,3,3, 87 2,3,2,2,2,2,2,3,2,2,2,1,1,1,2,2, 88 1,2,2,2,2,2,1,2,2,1,1,2,1,3,2,2, 89 2,2,1,2,1,2,2,2,2,2,2,1,1,1,2,1 90 }; 91 92 // static 93 xub_StrLen SvNumberformat::InsertBlanks( String& r, xub_StrLen nPos, sal_Unicode c ) 94 { 95 if( c >= 32 ) 96 { 97 sal_uInt16 n = 2; // Default fuer Zeichen > 128 (HACK!) 98 if( c <= 127 ) 99 n = cCharWidths[ c - 32 ]; 100 while( n-- ) 101 r.Insert( ' ', nPos++ ); 102 } 103 return nPos; 104 } 105 106 static long GetPrecExp( double fAbsVal ) 107 { 108 DBG_ASSERT( fAbsVal > 0.0, "GetPrecExp: fAbsVal <= 0.0" ); 109 if ( fAbsVal < 1e-7 || fAbsVal > 1e7 ) 110 { // die Schere, ob's schneller ist oder nicht, liegt zwischen 1e6 und 1e7 111 return (long) floor( log10( fAbsVal ) ) + 1; 112 } 113 else 114 { 115 long nPrecExp = 1; 116 while( fAbsVal < 1 ) 117 { 118 fAbsVal *= 10; 119 nPrecExp--; 120 } 121 while( fAbsVal >= 10 ) 122 { 123 fAbsVal /= 10; 124 nPrecExp++; 125 } 126 return nPrecExp; 127 } 128 } 129 130 const sal_uInt16 nNewCurrencyVersionId = 0x434E; // "NC" 131 const sal_Unicode cNewCurrencyMagic = 0x01; // Magic for format code in comment 132 const sal_uInt16 nNewStandardFlagVersionId = 0x4653; // "SF" 133 134 /***********************Funktion SvNumberformatInfo******************************/ 135 136 void ImpSvNumberformatInfo::Copy( const ImpSvNumberformatInfo& rNumFor, sal_uInt16 nAnz ) 137 { 138 for (sal_uInt16 i = 0; i < nAnz; i++) 139 { 140 sStrArray[i] = rNumFor.sStrArray[i]; 141 nTypeArray[i] = rNumFor.nTypeArray[i]; 142 } 143 eScannedType = rNumFor.eScannedType; 144 bThousand = rNumFor.bThousand; 145 nThousand = rNumFor.nThousand; 146 nCntPre = rNumFor.nCntPre; 147 nCntPost = rNumFor.nCntPost; 148 nCntExp = rNumFor.nCntExp; 149 } 150 151 void ImpSvNumberformatInfo::Save(SvStream& rStream, sal_uInt16 nAnz) const 152 { 153 for (sal_uInt16 i = 0; i < nAnz; i++) 154 { 155 rStream.WriteByteString( sStrArray[i], rStream.GetStreamCharSet() ); 156 short nType = nTypeArray[i]; 157 switch ( nType ) 158 { // der Krampf fuer Versionen vor SV_NUMBERFORMATTER_VERSION_NEW_CURR 159 case NF_SYMBOLTYPE_CURRENCY : 160 rStream << short( NF_SYMBOLTYPE_STRING ); 161 break; 162 case NF_SYMBOLTYPE_CURRDEL : 163 case NF_SYMBOLTYPE_CURREXT : 164 rStream << short(0); // werden ignoriert (hoffentlich..) 165 break; 166 default: 167 if ( nType > NF_KEY_LASTKEYWORD_SO5 ) 168 rStream << short( NF_SYMBOLTYPE_STRING ); // all new keywords are string 169 else 170 rStream << nType; 171 } 172 173 } 174 rStream << eScannedType << bThousand << nThousand 175 << nCntPre << nCntPost << nCntExp; 176 } 177 178 void ImpSvNumberformatInfo::Load(SvStream& rStream, sal_uInt16 nAnz) 179 { 180 for (sal_uInt16 i = 0; i < nAnz; i++) 181 { 182 SvNumberformat::LoadString( rStream, sStrArray[i] ); 183 rStream >> nTypeArray[i]; 184 } 185 rStream >> eScannedType >> bThousand >> nThousand 186 >> nCntPre >> nCntPost >> nCntExp; 187 } 188 189 190 //============================================================================ 191 192 // static 193 sal_uInt8 SvNumberNatNum::MapDBNumToNatNum( sal_uInt8 nDBNum, LanguageType eLang, sal_Bool bDate ) 194 { 195 sal_uInt8 nNatNum = 0; 196 eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc. 197 eLang &= 0x03FF; // 10 bit primary language 198 if ( bDate ) 199 { 200 if ( nDBNum == 4 && eLang == LANGUAGE_KOREAN ) 201 nNatNum = 9; 202 else if ( nDBNum <= 3 ) 203 nNatNum = nDBNum; // known to be good for: zh,ja,ko / 1,2,3 204 } 205 else 206 { 207 switch ( nDBNum ) 208 { 209 case 1: 210 switch ( eLang ) 211 { 212 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 4; break; 213 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 1; break; 214 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 1; break; 215 } 216 break; 217 case 2: 218 switch ( eLang ) 219 { 220 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 5; break; 221 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 4; break; 222 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 2; break; 223 } 224 break; 225 case 3: 226 switch ( eLang ) 227 { 228 case (LANGUAGE_CHINESE & 0x03FF) : nNatNum = 6; break; 229 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 5; break; 230 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 3; break; 231 } 232 break; 233 case 4: 234 switch ( eLang ) 235 { 236 case (LANGUAGE_JAPANESE & 0x03FF) : nNatNum = 7; break; 237 case (LANGUAGE_KOREAN & 0x03FF) : nNatNum = 9; break; 238 } 239 break; 240 } 241 } 242 return nNatNum; 243 } 244 245 246 // static 247 sal_uInt8 SvNumberNatNum::MapNatNumToDBNum( sal_uInt8 nNatNum, LanguageType eLang, sal_Bool bDate ) 248 { 249 sal_uInt8 nDBNum = 0; 250 eLang = MsLangId::getRealLanguage( eLang ); // resolve SYSTEM etc. 251 eLang &= 0x03FF; // 10 bit primary language 252 if ( bDate ) 253 { 254 if ( nNatNum == 9 && eLang == LANGUAGE_KOREAN ) 255 nDBNum = 4; 256 else if ( nNatNum <= 3 ) 257 nDBNum = nNatNum; // known to be good for: zh,ja,ko / 1,2,3 258 } 259 else 260 { 261 switch ( nNatNum ) 262 { 263 case 1: 264 switch ( eLang ) 265 { 266 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 1; break; 267 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 1; break; 268 } 269 break; 270 case 2: 271 switch ( eLang ) 272 { 273 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 2; break; 274 } 275 break; 276 case 3: 277 switch ( eLang ) 278 { 279 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 3; break; 280 } 281 break; 282 case 4: 283 switch ( eLang ) 284 { 285 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 1; break; 286 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 2; break; 287 } 288 break; 289 case 5: 290 switch ( eLang ) 291 { 292 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 2; break; 293 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 3; break; 294 } 295 break; 296 case 6: 297 switch ( eLang ) 298 { 299 case (LANGUAGE_CHINESE & 0x03FF) : nDBNum = 3; break; 300 } 301 break; 302 case 7: 303 switch ( eLang ) 304 { 305 case (LANGUAGE_JAPANESE & 0x03FF) : nDBNum = 4; break; 306 } 307 break; 308 case 8: 309 break; 310 case 9: 311 switch ( eLang ) 312 { 313 case (LANGUAGE_KOREAN & 0x03FF) : nDBNum = 4; break; 314 } 315 break; 316 case 10: 317 break; 318 case 11: 319 break; 320 } 321 } 322 return nDBNum; 323 } 324 325 /***********************Funktionen SvNumFor******************************/ 326 327 ImpSvNumFor::ImpSvNumFor() 328 { 329 nAnzStrings = 0; 330 aI.nTypeArray = NULL; 331 aI.sStrArray = NULL; 332 aI.eScannedType = NUMBERFORMAT_UNDEFINED; 333 aI.bThousand = sal_False; 334 aI.nThousand = 0; 335 aI.nCntPre = 0; 336 aI.nCntPost = 0; 337 aI.nCntExp = 0; 338 pColor = NULL; 339 } 340 341 ImpSvNumFor::~ImpSvNumFor() 342 { 343 for (sal_uInt16 i = 0; i < nAnzStrings; i++) 344 aI.sStrArray[i].Erase(); 345 delete [] aI.sStrArray; 346 delete [] aI.nTypeArray; 347 } 348 349 void ImpSvNumFor::Enlarge(sal_uInt16 nAnz) 350 { 351 if ( nAnzStrings != nAnz ) 352 { 353 if ( aI.nTypeArray ) 354 delete [] aI.nTypeArray; 355 if ( aI.sStrArray ) 356 delete [] aI.sStrArray; 357 nAnzStrings = nAnz; 358 if ( nAnz ) 359 { 360 aI.nTypeArray = new short[nAnz]; 361 aI.sStrArray = new String[nAnz]; 362 } 363 else 364 { 365 aI.nTypeArray = NULL; 366 aI.sStrArray = NULL; 367 } 368 } 369 } 370 371 void ImpSvNumFor::Copy( const ImpSvNumFor& rNumFor, ImpSvNumberformatScan* pSc ) 372 { 373 Enlarge( rNumFor.nAnzStrings ); 374 aI.Copy( rNumFor.aI, nAnzStrings ); 375 sColorName = rNumFor.sColorName; 376 if ( pSc ) 377 pColor = pSc->GetColor( sColorName ); // #121103# don't copy pointer between documents 378 else 379 pColor = rNumFor.pColor; 380 aNatNum = rNumFor.aNatNum; 381 } 382 383 void ImpSvNumFor::Save(SvStream& rStream) const 384 { 385 rStream << nAnzStrings; 386 aI.Save(rStream, nAnzStrings); 387 rStream.WriteByteString( sColorName, rStream.GetStreamCharSet() ); 388 } 389 390 void ImpSvNumFor::Load(SvStream& rStream, ImpSvNumberformatScan& rSc, 391 String& rLoadedColorName ) 392 { 393 sal_uInt16 nAnz; 394 rStream >> nAnz; //! noch nicht direkt nAnzStrings wg. Enlarge 395 Enlarge( nAnz ); 396 aI.Load( rStream, nAnz ); 397 rStream.ReadByteString( sColorName, rStream.GetStreamCharSet() ); 398 rLoadedColorName = sColorName; 399 pColor = rSc.GetColor(sColorName); 400 } 401 402 403 sal_Bool ImpSvNumFor::HasNewCurrency() const 404 { 405 for ( sal_uInt16 j=0; j<nAnzStrings; j++ ) 406 { 407 if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) 408 return sal_True; 409 } 410 return sal_False; 411 } 412 413 414 sal_Bool ImpSvNumFor::GetNewCurrencySymbol( String& rSymbol, 415 String& rExtension ) const 416 { 417 for ( sal_uInt16 j=0; j<nAnzStrings; j++ ) 418 { 419 if ( aI.nTypeArray[j] == NF_SYMBOLTYPE_CURRENCY ) 420 { 421 rSymbol = aI.sStrArray[j]; 422 if ( j < nAnzStrings-1 && aI.nTypeArray[j+1] == NF_SYMBOLTYPE_CURREXT ) 423 rExtension = aI.sStrArray[j+1]; 424 else 425 rExtension.Erase(); 426 return sal_True; 427 } 428 } 429 //! kein Erase an rSymbol, rExtension 430 return sal_False; 431 } 432 433 434 void ImpSvNumFor::SaveNewCurrencyMap( SvStream& rStream ) const 435 { 436 sal_uInt16 j; 437 sal_uInt16 nCnt = 0; 438 for ( j=0; j<nAnzStrings; j++ ) 439 { 440 switch ( aI.nTypeArray[j] ) 441 { 442 case NF_SYMBOLTYPE_CURRENCY : 443 case NF_SYMBOLTYPE_CURRDEL : 444 case NF_SYMBOLTYPE_CURREXT : 445 nCnt++; 446 break; 447 } 448 } 449 rStream << nCnt; 450 for ( j=0; j<nAnzStrings; j++ ) 451 { 452 switch ( aI.nTypeArray[j] ) 453 { 454 case NF_SYMBOLTYPE_CURRENCY : 455 case NF_SYMBOLTYPE_CURRDEL : 456 case NF_SYMBOLTYPE_CURREXT : 457 rStream << j << aI.nTypeArray[j]; 458 break; 459 } 460 } 461 } 462 463 464 void ImpSvNumFor::LoadNewCurrencyMap( SvStream& rStream ) 465 { 466 sal_uInt16 nCnt; 467 rStream >> nCnt; 468 for ( sal_uInt16 j=0; j<nCnt; j++ ) 469 { 470 sal_uInt16 nPos; 471 short nType; 472 rStream >> nPos >> nType; 473 if ( nPos < nAnzStrings ) 474 aI.nTypeArray[nPos] = nType; 475 } 476 } 477 478 479 /***********************Funktionen SvNumberformat************************/ 480 481 enum BracketFormatSymbolType 482 { 483 BRACKET_SYMBOLTYPE_FORMAT = -1, // subformat string 484 BRACKET_SYMBOLTYPE_COLOR = -2, // color 485 BRACKET_SYMBOLTYPE_ERROR = -3, // error 486 BRACKET_SYMBOLTYPE_DBNUM1 = -4, // DoubleByteNumber, represent numbers 487 BRACKET_SYMBOLTYPE_DBNUM2 = -5, // using CJK characters, Excel compatible. 488 BRACKET_SYMBOLTYPE_DBNUM3 = -6, 489 BRACKET_SYMBOLTYPE_DBNUM4 = -7, 490 BRACKET_SYMBOLTYPE_DBNUM5 = -8, 491 BRACKET_SYMBOLTYPE_DBNUM6 = -9, 492 BRACKET_SYMBOLTYPE_DBNUM7 = -10, 493 BRACKET_SYMBOLTYPE_DBNUM8 = -11, 494 BRACKET_SYMBOLTYPE_DBNUM9 = -12, 495 BRACKET_SYMBOLTYPE_LOCALE = -13, 496 BRACKET_SYMBOLTYPE_NATNUM0 = -14, // Our NativeNumber support, ASCII 497 BRACKET_SYMBOLTYPE_NATNUM1 = -15, // Our NativeNumber support, represent 498 BRACKET_SYMBOLTYPE_NATNUM2 = -16, // numbers using CJK, CTL, ... 499 BRACKET_SYMBOLTYPE_NATNUM3 = -17, 500 BRACKET_SYMBOLTYPE_NATNUM4 = -18, 501 BRACKET_SYMBOLTYPE_NATNUM5 = -19, 502 BRACKET_SYMBOLTYPE_NATNUM6 = -20, 503 BRACKET_SYMBOLTYPE_NATNUM7 = -21, 504 BRACKET_SYMBOLTYPE_NATNUM8 = -22, 505 BRACKET_SYMBOLTYPE_NATNUM9 = -23, 506 BRACKET_SYMBOLTYPE_NATNUM10 = -24, 507 BRACKET_SYMBOLTYPE_NATNUM11 = -25, 508 BRACKET_SYMBOLTYPE_NATNUM12 = -26, 509 BRACKET_SYMBOLTYPE_NATNUM13 = -27, 510 BRACKET_SYMBOLTYPE_NATNUM14 = -28, 511 BRACKET_SYMBOLTYPE_NATNUM15 = -29, 512 BRACKET_SYMBOLTYPE_NATNUM16 = -30, 513 BRACKET_SYMBOLTYPE_NATNUM17 = -31, 514 BRACKET_SYMBOLTYPE_NATNUM18 = -32, 515 BRACKET_SYMBOLTYPE_NATNUM19 = -33 516 }; 517 518 SvNumberformat::SvNumberformat( ImpSvNumberformatScan& rSc, LanguageType eLge ) 519 : 520 rScan(rSc), 521 eLnge(eLge), 522 nNewStandardDefined(0), 523 bStarFlag( sal_False ) 524 { 525 } 526 527 void SvNumberformat::ImpCopyNumberformat( const SvNumberformat& rFormat ) 528 { 529 sFormatstring = rFormat.sFormatstring; 530 eType = rFormat.eType; 531 eLnge = rFormat.eLnge; 532 fLimit1 = rFormat.fLimit1; 533 fLimit2 = rFormat.fLimit2; 534 eOp1 = rFormat.eOp1; 535 eOp2 = rFormat.eOp2; 536 bStandard = rFormat.bStandard; 537 bIsUsed = rFormat.bIsUsed; 538 sComment = rFormat.sComment; 539 nNewStandardDefined = rFormat.nNewStandardDefined; 540 541 // #121103# when copying between documents, get color pointers from own scanner 542 ImpSvNumberformatScan* pColorSc = ( &rScan != &rFormat.rScan ) ? &rScan : NULL; 543 544 for (sal_uInt16 i = 0; i < 4; i++) 545 NumFor[i].Copy(rFormat.NumFor[i], pColorSc); 546 } 547 548 SvNumberformat::SvNumberformat( SvNumberformat& rFormat ) 549 : rScan(rFormat.rScan), bStarFlag( rFormat.bStarFlag ) 550 { 551 ImpCopyNumberformat( rFormat ); 552 } 553 554 SvNumberformat::SvNumberformat( SvNumberformat& rFormat, ImpSvNumberformatScan& rSc ) 555 : rScan(rSc), bStarFlag( rFormat.bStarFlag ) 556 { 557 ImpCopyNumberformat( rFormat ); 558 } 559 560 561 sal_Bool lcl_SvNumberformat_IsBracketedPrefix( short nSymbolType ) 562 { 563 if ( nSymbolType > 0 ) 564 return sal_True; // conditions 565 switch ( nSymbolType ) 566 { 567 case BRACKET_SYMBOLTYPE_COLOR : 568 case BRACKET_SYMBOLTYPE_DBNUM1 : 569 case BRACKET_SYMBOLTYPE_DBNUM2 : 570 case BRACKET_SYMBOLTYPE_DBNUM3 : 571 case BRACKET_SYMBOLTYPE_DBNUM4 : 572 case BRACKET_SYMBOLTYPE_DBNUM5 : 573 case BRACKET_SYMBOLTYPE_DBNUM6 : 574 case BRACKET_SYMBOLTYPE_DBNUM7 : 575 case BRACKET_SYMBOLTYPE_DBNUM8 : 576 case BRACKET_SYMBOLTYPE_DBNUM9 : 577 case BRACKET_SYMBOLTYPE_LOCALE : 578 case BRACKET_SYMBOLTYPE_NATNUM0 : 579 case BRACKET_SYMBOLTYPE_NATNUM1 : 580 case BRACKET_SYMBOLTYPE_NATNUM2 : 581 case BRACKET_SYMBOLTYPE_NATNUM3 : 582 case BRACKET_SYMBOLTYPE_NATNUM4 : 583 case BRACKET_SYMBOLTYPE_NATNUM5 : 584 case BRACKET_SYMBOLTYPE_NATNUM6 : 585 case BRACKET_SYMBOLTYPE_NATNUM7 : 586 case BRACKET_SYMBOLTYPE_NATNUM8 : 587 case BRACKET_SYMBOLTYPE_NATNUM9 : 588 case BRACKET_SYMBOLTYPE_NATNUM10 : 589 case BRACKET_SYMBOLTYPE_NATNUM11 : 590 case BRACKET_SYMBOLTYPE_NATNUM12 : 591 case BRACKET_SYMBOLTYPE_NATNUM13 : 592 case BRACKET_SYMBOLTYPE_NATNUM14 : 593 case BRACKET_SYMBOLTYPE_NATNUM15 : 594 case BRACKET_SYMBOLTYPE_NATNUM16 : 595 case BRACKET_SYMBOLTYPE_NATNUM17 : 596 case BRACKET_SYMBOLTYPE_NATNUM18 : 597 case BRACKET_SYMBOLTYPE_NATNUM19 : 598 return sal_True; 599 } 600 return sal_False; 601 } 602 603 604 SvNumberformat::SvNumberformat(String& rString, 605 ImpSvNumberformatScan* pSc, 606 ImpSvNumberInputScan* pISc, 607 xub_StrLen& nCheckPos, 608 LanguageType& eLan, 609 sal_Bool bStan) 610 : 611 rScan(*pSc), 612 nNewStandardDefined(0), 613 bStarFlag( sal_False ) 614 { 615 // If the group (AKA thousand) separator is a Non-Breaking Space (French) 616 // replace all occurences by a simple space. 617 // The tokens will be changed to the LocaleData separator again later on. 618 const sal_Unicode cNBSp = 0xA0; 619 const String& rThSep = GetFormatter().GetNumThousandSep(); 620 if ( rThSep.GetChar(0) == cNBSp && rThSep.Len() == 1 ) 621 { 622 xub_StrLen nIndex = 0; 623 do 624 nIndex = rString.SearchAndReplace( cNBSp, ' ', nIndex ); 625 while ( nIndex != STRING_NOTFOUND ); 626 } 627 628 if (rScan.GetConvertMode()) 629 { 630 eLnge = rScan.GetNewLnge(); 631 eLan = eLnge; // Wechsel auch zurueckgeben 632 } 633 else 634 eLnge = eLan; 635 bStandard = bStan; 636 bIsUsed = sal_False; 637 fLimit1 = 0.0; 638 fLimit2 = 0.0; 639 eOp1 = NUMBERFORMAT_OP_NO; 640 eOp2 = NUMBERFORMAT_OP_NO; 641 eType = NUMBERFORMAT_DEFINED; 642 643 sal_Bool bCancel = sal_False; 644 sal_Bool bCondition = sal_False; 645 short eSymbolType; 646 xub_StrLen nPos = 0; 647 xub_StrLen nPosOld; 648 nCheckPos = 0; 649 String aComment; 650 651 // Split into 4 sub formats 652 sal_uInt16 nIndex; 653 for ( nIndex = 0; nIndex < 4 && !bCancel; nIndex++ ) 654 { 655 // Original language/country may have to be reestablished 656 if (rScan.GetConvertMode()) 657 (rScan.GetNumberformatter())->ChangeIntl(rScan.GetTmpLnge()); 658 659 String sStr; 660 nPosOld = nPos; // Start position of substring 661 // first get bracketed prefixes; e.g. conditions, color 662 do 663 { 664 eSymbolType = ImpNextSymbol(rString, nPos, sStr); 665 if (eSymbolType > 0) // condition 666 { 667 if ( nIndex == 0 && !bCondition ) 668 { 669 bCondition = sal_True; 670 eOp1 = (SvNumberformatLimitOps) eSymbolType; 671 } 672 else if ( nIndex == 1 && bCondition ) 673 eOp2 = (SvNumberformatLimitOps) eSymbolType; 674 else // error 675 { 676 bCancel = sal_True; // break for 677 nCheckPos = nPosOld; 678 } 679 if (!bCancel) 680 { 681 double fNumber; 682 xub_StrLen nAnzChars = ImpGetNumber(rString, nPos, sStr); 683 if (nAnzChars > 0) 684 { 685 short F_Type = NUMBERFORMAT_UNDEFINED; 686 if (!pISc->IsNumberFormat(sStr,F_Type,fNumber) || 687 ( F_Type != NUMBERFORMAT_NUMBER && 688 F_Type != NUMBERFORMAT_SCIENTIFIC) ) 689 { 690 fNumber = 0.0; 691 nPos = nPos - nAnzChars; 692 rString.Erase(nPos, nAnzChars); 693 rString.Insert('0',nPos); 694 nPos++; 695 } 696 } 697 else 698 { 699 fNumber = 0.0; 700 rString.Insert('0',nPos++); 701 } 702 if (nIndex == 0) 703 fLimit1 = fNumber; 704 else 705 fLimit2 = fNumber; 706 if ( rString.GetChar(nPos) == ']' ) 707 nPos++; 708 else 709 { 710 bCancel = sal_True; // break for 711 nCheckPos = nPos; 712 } 713 } 714 nPosOld = nPos; // position before string 715 } 716 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) 717 { 718 switch ( eSymbolType ) 719 { 720 case BRACKET_SYMBOLTYPE_COLOR : 721 { 722 if ( NumFor[nIndex].GetColor() != NULL ) 723 { // error, more than one color 724 bCancel = sal_True; // break for 725 nCheckPos = nPosOld; 726 } 727 else 728 { 729 Color* pColor = pSc->GetColor( sStr); 730 NumFor[nIndex].SetColor( pColor, sStr); 731 if (pColor == NULL) 732 { // error 733 bCancel = sal_True; // break for 734 nCheckPos = nPosOld; 735 } 736 } 737 } 738 break; 739 case BRACKET_SYMBOLTYPE_NATNUM0 : 740 case BRACKET_SYMBOLTYPE_NATNUM1 : 741 case BRACKET_SYMBOLTYPE_NATNUM2 : 742 case BRACKET_SYMBOLTYPE_NATNUM3 : 743 case BRACKET_SYMBOLTYPE_NATNUM4 : 744 case BRACKET_SYMBOLTYPE_NATNUM5 : 745 case BRACKET_SYMBOLTYPE_NATNUM6 : 746 case BRACKET_SYMBOLTYPE_NATNUM7 : 747 case BRACKET_SYMBOLTYPE_NATNUM8 : 748 case BRACKET_SYMBOLTYPE_NATNUM9 : 749 case BRACKET_SYMBOLTYPE_NATNUM10 : 750 case BRACKET_SYMBOLTYPE_NATNUM11 : 751 case BRACKET_SYMBOLTYPE_NATNUM12 : 752 case BRACKET_SYMBOLTYPE_NATNUM13 : 753 case BRACKET_SYMBOLTYPE_NATNUM14 : 754 case BRACKET_SYMBOLTYPE_NATNUM15 : 755 case BRACKET_SYMBOLTYPE_NATNUM16 : 756 case BRACKET_SYMBOLTYPE_NATNUM17 : 757 case BRACKET_SYMBOLTYPE_NATNUM18 : 758 case BRACKET_SYMBOLTYPE_NATNUM19 : 759 { 760 if ( NumFor[nIndex].GetNatNum().IsSet() ) 761 { 762 bCancel = sal_True; // break for 763 nCheckPos = nPosOld; 764 } 765 else 766 { 767 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "NatNum" ) ); 768 //! eSymbolType is negative 769 sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(0 - (eSymbolType - BRACKET_SYMBOLTYPE_NATNUM0)); 770 sStr += String::CreateFromInt32( nNum ); 771 NumFor[nIndex].SetNatNumNum( nNum, sal_False ); 772 } 773 } 774 break; 775 case BRACKET_SYMBOLTYPE_DBNUM1 : 776 case BRACKET_SYMBOLTYPE_DBNUM2 : 777 case BRACKET_SYMBOLTYPE_DBNUM3 : 778 case BRACKET_SYMBOLTYPE_DBNUM4 : 779 case BRACKET_SYMBOLTYPE_DBNUM5 : 780 case BRACKET_SYMBOLTYPE_DBNUM6 : 781 case BRACKET_SYMBOLTYPE_DBNUM7 : 782 case BRACKET_SYMBOLTYPE_DBNUM8 : 783 case BRACKET_SYMBOLTYPE_DBNUM9 : 784 { 785 if ( NumFor[nIndex].GetNatNum().IsSet() ) 786 { 787 bCancel = sal_True; // break for 788 nCheckPos = nPosOld; 789 } 790 else 791 { 792 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "DBNum" ) ); 793 //! eSymbolType is negative 794 sal_uInt8 nNum = sal::static_int_cast< sal_uInt8 >(1 - (eSymbolType - BRACKET_SYMBOLTYPE_DBNUM1)); 795 sStr += static_cast< sal_Unicode >('0' + nNum); 796 NumFor[nIndex].SetNatNumNum( nNum, sal_True ); 797 } 798 } 799 break; 800 case BRACKET_SYMBOLTYPE_LOCALE : 801 { 802 if ( NumFor[nIndex].GetNatNum().GetLang() != LANGUAGE_DONTKNOW ) 803 { 804 bCancel = sal_True; // break for 805 nCheckPos = nPosOld; 806 } 807 else 808 { 809 xub_StrLen nTmp = 2; 810 LanguageType eLang = ImpGetLanguageType( sStr, nTmp ); 811 if ( eLang == LANGUAGE_DONTKNOW ) 812 { 813 bCancel = sal_True; // break for 814 nCheckPos = nPosOld; 815 } 816 else 817 { 818 sStr.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "$-" ) ); 819 sStr += String::CreateFromInt32( sal_Int32( eLang ), 16 ).ToUpperAscii(); 820 NumFor[nIndex].SetNatNumLang( eLang ); 821 } 822 } 823 } 824 break; 825 } 826 if ( !bCancel ) 827 { 828 rString.Erase(nPosOld,nPos-nPosOld); 829 rString.Insert(sStr,nPosOld); 830 nPos = nPosOld + sStr.Len(); 831 rString.Insert(']', nPos); 832 rString.Insert('[', nPosOld); 833 nPos += 2; 834 nPosOld = nPos; // position before string 835 } 836 } 837 } while ( !bCancel && lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ); 838 839 // The remaining format code string 840 if ( !bCancel ) 841 { 842 if (eSymbolType == BRACKET_SYMBOLTYPE_FORMAT) 843 { 844 if (nIndex == 1 && eOp1 == NUMBERFORMAT_OP_NO) 845 eOp1 = NUMBERFORMAT_OP_GT; // undefined condition, default: > 0 846 else if (nIndex == 2 && eOp2 == NUMBERFORMAT_OP_NO) 847 eOp2 = NUMBERFORMAT_OP_LT; // undefined condition, default: < 0 848 if (sStr.Len() == 0) 849 { // empty sub format 850 } 851 else 852 { 853 xub_StrLen nStrPos = pSc->ScanFormat( sStr, aComment ); 854 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 855 if (nAnz == 0) // error 856 nStrPos = 1; 857 if (nStrPos == 0) // ok 858 { 859 // e.g. Thai T speciality 860 if (pSc->GetNatNumModifier() && !NumFor[nIndex].GetNatNum().IsSet()) 861 { 862 String aNat( RTL_CONSTASCII_USTRINGPARAM( "[NatNum")); 863 aNat += String::CreateFromInt32( pSc->GetNatNumModifier()); 864 aNat += ']'; 865 sStr.Insert( aNat, 0); 866 NumFor[nIndex].SetNatNumNum( pSc->GetNatNumModifier(), sal_False ); 867 } 868 // #i53826# #i42727# For the Thai T speciality we need 869 // to freeze the locale and immunize it against 870 // conversions during exports, just in case we want to 871 // save to Xcl. This disables the feature of being able 872 // to convert a NatNum to another locale. You can't 873 // have both. 874 // FIXME: implement a specialized export conversion 875 // that works on tokens (have to tokenize all first) 876 // and doesn't use the format string and 877 // PutandConvertEntry() to LANGUAGE_ENGLISH_US in 878 // sc/source/filter/excel/xestyle.cxx 879 // XclExpNumFmtBuffer::WriteFormatRecord(). 880 LanguageType eLanguage; 881 if (NumFor[nIndex].GetNatNum().GetNatNum() == 1 && 882 ((eLanguage = 883 MsLangId::getRealLanguage( eLan)) 884 == LANGUAGE_THAI) && 885 NumFor[nIndex].GetNatNum().GetLang() == 886 LANGUAGE_DONTKNOW) 887 { 888 String aLID( RTL_CONSTASCII_USTRINGPARAM( "[$-")); 889 aLID += String::CreateFromInt32( sal_Int32( 890 eLanguage), 16 ).ToUpperAscii(); 891 aLID += ']'; 892 sStr.Insert( aLID, 0); 893 NumFor[nIndex].SetNatNumLang( eLanguage); 894 } 895 rString.Erase(nPosOld,nPos-nPosOld); 896 rString.Insert(sStr,nPosOld); 897 nPos = nPosOld + sStr.Len(); 898 if (nPos < rString.Len()) 899 { 900 rString.Insert(';',nPos); 901 nPos++; 902 } 903 NumFor[nIndex].Enlarge(nAnz); 904 pSc->CopyInfo(&(NumFor[nIndex].Info()), nAnz); 905 // type check 906 if (nIndex == 0) 907 eType = (short) NumFor[nIndex].Info().eScannedType; 908 else if (nIndex == 3) 909 { // #77026# Everything recognized IS text 910 NumFor[nIndex].Info().eScannedType = NUMBERFORMAT_TEXT; 911 } 912 else if ( (short) NumFor[nIndex].Info().eScannedType != 913 eType) 914 eType = NUMBERFORMAT_DEFINED; 915 } 916 else 917 { 918 nCheckPos = nPosOld + nStrPos; // error in string 919 bCancel = sal_True; // break for 920 } 921 } 922 } 923 else if (eSymbolType == BRACKET_SYMBOLTYPE_ERROR) // error 924 { 925 nCheckPos = nPosOld; 926 bCancel = sal_True; 927 } 928 else if ( lcl_SvNumberformat_IsBracketedPrefix( eSymbolType ) ) 929 { 930 nCheckPos = nPosOld+1; // error, prefix in string 931 bCancel = sal_True; // break for 932 } 933 } 934 if ( bCancel && !nCheckPos ) 935 nCheckPos = 1; // nCheckPos is used as an error condition 936 if ( !bCancel ) 937 { 938 if ( NumFor[nIndex].GetNatNum().IsSet() && 939 NumFor[nIndex].GetNatNum().GetLang() == LANGUAGE_DONTKNOW ) 940 NumFor[nIndex].SetNatNumLang( eLan ); 941 } 942 if (rString.Len() == nPos) 943 { 944 if ( nIndex == 2 && eSymbolType == BRACKET_SYMBOLTYPE_FORMAT && 945 rString.GetChar(nPos-1) == ';' ) 946 { // #83510# A 4th subformat explicitly specified to be empty 947 // hides any text. Need the type here for HasTextFormat() 948 NumFor[3].Info().eScannedType = NUMBERFORMAT_TEXT; 949 } 950 bCancel = sal_True; 951 } 952 if ( NumFor[nIndex].GetNatNum().IsSet() ) 953 NumFor[nIndex].SetNatNumDate( 954 (NumFor[nIndex].Info().eScannedType & NUMBERFORMAT_DATE) != 0 ); 955 } 956 957 if ( bCondition && !nCheckPos ) 958 { 959 if ( nIndex == 1 && NumFor[0].GetnAnz() == 0 && 960 rString.GetChar(rString.Len()-1) != ';' ) 961 { // No format code => GENERAL but not if specified empty 962 String aAdd( pSc->GetStandardName() ); 963 String aTmp; 964 if ( !pSc->ScanFormat( aAdd, aTmp ) ) 965 { 966 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 967 if ( nAnz ) 968 { 969 NumFor[0].Enlarge(nAnz); 970 pSc->CopyInfo( &(NumFor[0].Info()), nAnz ); 971 rString += aAdd; 972 } 973 } 974 } 975 else if ( nIndex == 1 && NumFor[nIndex].GetnAnz() == 0 && 976 rString.GetChar(rString.Len()-1) != ';' && 977 (NumFor[0].GetnAnz() > 1 || (NumFor[0].GetnAnz() == 1 && 978 NumFor[0].Info().nTypeArray[0] != NF_KEY_GENERAL)) ) 979 { // No trailing second subformat => GENERAL but not if specified empty 980 // and not if first subformat is GENERAL 981 String aAdd( pSc->GetStandardName() ); 982 String aTmp; 983 if ( !pSc->ScanFormat( aAdd, aTmp ) ) 984 { 985 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 986 if ( nAnz ) 987 { 988 NumFor[nIndex].Enlarge(nAnz); 989 pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz ); 990 rString += ';'; 991 rString += aAdd; 992 } 993 } 994 } 995 else if ( nIndex == 2 && NumFor[nIndex].GetnAnz() == 0 && 996 rString.GetChar(rString.Len()-1) != ';' && 997 eOp2 != NUMBERFORMAT_OP_NO ) 998 { // No trailing third subformat => GENERAL but not if specified empty 999 String aAdd( pSc->GetStandardName() ); 1000 String aTmp; 1001 if ( !pSc->ScanFormat( aAdd, aTmp ) ) 1002 { 1003 sal_uInt16 nAnz = pSc->GetAnzResStrings(); 1004 if ( nAnz ) 1005 { 1006 NumFor[nIndex].Enlarge(nAnz); 1007 pSc->CopyInfo( &(NumFor[nIndex].Info()), nAnz ); 1008 rString += ';'; 1009 rString += aAdd; 1010 } 1011 } 1012 } 1013 } 1014 sFormatstring = rString; 1015 if ( aComment.Len() ) 1016 { 1017 SetComment( aComment ); // setzt sComment und sFormatstring 1018 rString = sFormatstring; // geaenderten sFormatstring uebernehmen 1019 } 1020 if (NumFor[2].GetnAnz() == 0 && // kein 3. Teilstring 1021 eOp1 == NUMBERFORMAT_OP_GT && eOp2 == NUMBERFORMAT_OP_NO && 1022 fLimit1 == 0.0 && fLimit2 == 0.0) 1023 eOp1 = NUMBERFORMAT_OP_GE; // 0 zum ersten Format dazu 1024 1025 } 1026 1027 SvNumberformat::~SvNumberformat() 1028 { 1029 } 1030 1031 //--------------------------------------------------------------------------- 1032 // Next_Symbol 1033 //--------------------------------------------------------------------------- 1034 // Zerlegt die Eingabe in Symbole fuer die weitere 1035 // Verarbeitung (Turing-Maschine). 1036 //--------------------------------------------------------------------------- 1037 // Ausgangs Zustand = SsStart 1038 //---------------+-------------------+-----------------------+--------------- 1039 // Alter Zustand | gelesenes Zeichen | Aktion | Neuer Zustand 1040 //---------------+-------------------+-----------------------+--------------- 1041 // SsStart | ; | Pos-- | SsGetString 1042 // | [ | Symbol += Zeichen | SsGetBracketed 1043 // | ] | Fehler | SsStop 1044 // | BLANK | | 1045 // | Sonst | Symbol += Zeichen | SsGetString 1046 //---------------+-------------------+-----------------------+--------------- 1047 // SsGetString | ; | | SsStop 1048 // | Sonst | Symbol+=Zeichen | 1049 //---------------+-------------------+-----------------------+--------------- 1050 // SsGetBracketed| <, > = | del [ | 1051 // | | Symbol += Zeichen | SsGetCon 1052 // | BLANK | | 1053 // | h, H, m, M, s, S | Symbol += Zeichen | SsGetTime 1054 // | sonst | del [ | 1055 // | | Symbol += Zeichen | SsGetPrefix 1056 //---------------+-------------------+-----------------------+--------------- 1057 // SsGetTime | ] | Symbol += Zeichen | SsGetString 1058 // | h, H, m, M, s, S | Symbol += Zeichen, * | SsGetString 1059 // | sonst | del [; Symbol+=Zeichen| SsGetPrefix 1060 //---------------+-------------------+-----------------------+--------------- 1061 // SsGetPrefix | ] | | SsStop 1062 // | sonst | Symbol += Zeichen | 1063 //---------------+-------------------+-----------------------+--------------- 1064 // SsGetCon | >, = | Symbol+=Zeichen | 1065 // | ] | | SsStop 1066 // | sonst | Fehler | SsStop 1067 //---------------+-------------------+-----------------------+--------------- 1068 // * : Sonderbedingung 1069 1070 enum ScanState 1071 { 1072 SsStop, 1073 SsStart, 1074 SsGetCon, // condition 1075 SsGetString, // format string 1076 SsGetPrefix, // color or NatNumN 1077 SsGetTime, // [HH] for time 1078 SsGetBracketed // any [...] not decided yet 1079 }; 1080 1081 1082 // read a string until ']' and delete spaces in input 1083 // static 1084 xub_StrLen SvNumberformat::ImpGetNumber(String& rString, 1085 xub_StrLen& nPos, 1086 String& sSymbol) 1087 { 1088 xub_StrLen nStartPos = nPos; 1089 sal_Unicode cToken; 1090 xub_StrLen nLen = rString.Len(); 1091 sSymbol.Erase(); 1092 while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') ) 1093 { 1094 if (cToken == ' ') 1095 { // delete spaces 1096 rString.Erase(nPos,1); 1097 nLen--; 1098 } 1099 else 1100 { 1101 nPos++; 1102 sSymbol += cToken; 1103 } 1104 } 1105 return nPos - nStartPos; 1106 } 1107 1108 1109 // static 1110 LanguageType SvNumberformat::ImpGetLanguageType( const String& rString, 1111 xub_StrLen& nPos ) 1112 { 1113 sal_Int32 nNum = 0; 1114 sal_Unicode cToken = 0; 1115 xub_StrLen nLen = rString.Len(); 1116 while ( nPos < nLen && ((cToken = rString.GetChar(nPos)) != ']') ) 1117 { 1118 if ( '0' <= cToken && cToken <= '9' ) 1119 { 1120 nNum *= 16; 1121 nNum += cToken - '0'; 1122 } 1123 else if ( 'a' <= cToken && cToken <= 'f' ) 1124 { 1125 nNum *= 16; 1126 nNum += cToken - 'a' + 10; 1127 } 1128 else if ( 'A' <= cToken && cToken <= 'F' ) 1129 { 1130 nNum *= 16; 1131 nNum += cToken - 'A' + 10; 1132 } 1133 else 1134 return LANGUAGE_DONTKNOW; 1135 ++nPos; 1136 } 1137 return (nNum && (cToken == ']' || nPos == nLen)) ? (LanguageType)nNum : 1138 LANGUAGE_DONTKNOW; 1139 } 1140 1141 1142 short SvNumberformat::ImpNextSymbol(String& rString, 1143 xub_StrLen& nPos, 1144 String& sSymbol) 1145 { 1146 short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1147 sal_Unicode cToken; 1148 sal_Unicode cLetter = ' '; // Zwischenergebnis 1149 xub_StrLen nLen = rString.Len(); 1150 ScanState eState = SsStart; 1151 sSymbol.Erase(); 1152 const NfKeywordTable & rKeywords = rScan.GetKeywords(); 1153 while (nPos < nLen && eState != SsStop) 1154 { 1155 cToken = rString.GetChar(nPos); 1156 nPos++; 1157 switch (eState) 1158 { 1159 case SsStart: 1160 { 1161 if (cToken == '[') 1162 { 1163 eState = SsGetBracketed; 1164 sSymbol += cToken; 1165 } 1166 else if (cToken == ';') 1167 { 1168 eState = SsGetString; 1169 nPos--; 1170 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1171 } 1172 else if (cToken == ']') 1173 { 1174 eState = SsStop; 1175 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1176 } 1177 else if (cToken == ' ') // Skip Blanks 1178 { 1179 rString.Erase(nPos-1,1); 1180 nPos--; 1181 nLen--; 1182 } 1183 else 1184 { 1185 sSymbol += cToken; 1186 eState = SsGetString; 1187 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1188 } 1189 } 1190 break; 1191 case SsGetBracketed: 1192 { 1193 switch (cToken) 1194 { 1195 case '<': 1196 case '>': 1197 case '=': 1198 { 1199 sSymbol.EraseAllChars('['); 1200 sSymbol += cToken; 1201 cLetter = cToken; 1202 eState = SsGetCon; 1203 switch (cToken) 1204 { 1205 case '<': eSymbolType = NUMBERFORMAT_OP_LT; break; 1206 case '>': eSymbolType = NUMBERFORMAT_OP_GT; break; 1207 case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break; 1208 default: break; 1209 } 1210 } 1211 break; 1212 case ' ': 1213 { 1214 rString.Erase(nPos-1,1); 1215 nPos--; 1216 nLen--; 1217 } 1218 break; 1219 case '$' : 1220 { 1221 if ( rString.GetChar(nPos) == '-' ) 1222 { // [$-xxx] locale 1223 sSymbol.EraseAllChars('['); 1224 eSymbolType = BRACKET_SYMBOLTYPE_LOCALE; 1225 eState = SsGetPrefix; 1226 } 1227 else 1228 { // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR 1229 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1230 eState = SsGetString; 1231 } 1232 sSymbol += cToken; 1233 } 1234 break; 1235 case '~' : 1236 { // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR 1237 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1238 sSymbol += cToken; 1239 eState = SsGetString; 1240 } 1241 break; 1242 default: 1243 { 1244 static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) ); 1245 static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) ); 1246 String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) ); 1247 String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) ); 1248 sal_Unicode cUpper = aUpperNatNum.GetChar(0); 1249 sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32(); 1250 sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() ); 1251 if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 ) 1252 { 1253 sSymbol.EraseAllChars('['); 1254 sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 ); 1255 nPos += aNatNum.Len()+1; 1256 //! SymbolType is negative 1257 eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum); 1258 eState = SsGetPrefix; 1259 } 1260 else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' ) 1261 { 1262 sSymbol.EraseAllChars('['); 1263 sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 ); 1264 nPos += aDBNum.Len()+1; 1265 //! SymbolType is negative 1266 eSymbolType = sal::static_int_cast< short >( 1267 BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1')); 1268 eState = SsGetPrefix; 1269 } 1270 else if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H 1271 cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M 1272 cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S 1273 { 1274 sSymbol += cToken; 1275 eState = SsGetTime; 1276 cLetter = cToken; 1277 } 1278 else 1279 { 1280 sSymbol.EraseAllChars('['); 1281 sSymbol += cToken; 1282 eSymbolType = BRACKET_SYMBOLTYPE_COLOR; 1283 eState = SsGetPrefix; 1284 } 1285 } 1286 break; 1287 } 1288 } 1289 break; 1290 case SsGetString: 1291 { 1292 if (cToken == ';') 1293 eState = SsStop; 1294 else 1295 sSymbol += cToken; 1296 } 1297 break; 1298 case SsGetTime: 1299 { 1300 if (cToken == ']') 1301 { 1302 sSymbol += cToken; 1303 eState = SsGetString; 1304 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1305 } 1306 else 1307 { 1308 sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0); 1309 if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H 1310 cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M 1311 cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S 1312 { 1313 if (cLetter == cToken) 1314 { 1315 sSymbol += cToken; 1316 cLetter = ' '; 1317 } 1318 else 1319 { 1320 sSymbol.EraseAllChars('['); 1321 sSymbol += cToken; 1322 eState = SsGetPrefix; 1323 } 1324 } 1325 else 1326 { 1327 sSymbol.EraseAllChars('['); 1328 sSymbol += cToken; 1329 eSymbolType = BRACKET_SYMBOLTYPE_COLOR; 1330 eState = SsGetPrefix; 1331 } 1332 } 1333 } 1334 break; 1335 case SsGetCon: 1336 { 1337 switch (cToken) 1338 { 1339 case '<': 1340 { 1341 eState = SsStop; 1342 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1343 } 1344 break; 1345 case '>': 1346 { 1347 if (cLetter == '<') 1348 { 1349 sSymbol += cToken; 1350 cLetter = ' '; 1351 eState = SsStop; 1352 eSymbolType = NUMBERFORMAT_OP_NE; 1353 } 1354 else 1355 { 1356 eState = SsStop; 1357 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1358 } 1359 } 1360 break; 1361 case '=': 1362 { 1363 if (cLetter == '<') 1364 { 1365 sSymbol += cToken; 1366 cLetter = ' '; 1367 eSymbolType = NUMBERFORMAT_OP_LE; 1368 } 1369 else if (cLetter == '>') 1370 { 1371 sSymbol += cToken; 1372 cLetter = ' '; 1373 eSymbolType = NUMBERFORMAT_OP_GE; 1374 } 1375 else 1376 { 1377 eState = SsStop; 1378 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1379 } 1380 } 1381 break; 1382 case ' ': 1383 { 1384 rString.Erase(nPos-1,1); 1385 nPos--; 1386 nLen--; 1387 } 1388 break; 1389 default: 1390 { 1391 eState = SsStop; 1392 nPos--; 1393 } 1394 break; 1395 } 1396 } 1397 break; 1398 case SsGetPrefix: 1399 { 1400 if (cToken == ']') 1401 eState = SsStop; 1402 else 1403 sSymbol += cToken; 1404 } 1405 break; 1406 default: 1407 break; 1408 } // of switch 1409 } // of while 1410 1411 return eSymbolType; 1412 } 1413 1414 NfHackConversion SvNumberformat::Load( SvStream& rStream, 1415 ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter, 1416 ImpSvNumberInputScan& rISc ) 1417 { 1418 rHdr.StartEntry(); 1419 sal_uInt16 nOp1, nOp2; 1420 SvNumberformat::LoadString( rStream, sFormatstring ); 1421 rStream >> eType >> fLimit1 >> fLimit2 1422 >> nOp1 >> nOp2 >> bStandard >> bIsUsed; 1423 NfHackConversion eHackConversion = NF_CONVERT_NONE; 1424 sal_Bool bOldConvert = sal_False; 1425 LanguageType eOldTmpLang = 0; 1426 LanguageType eOldNewLang = 0; 1427 if ( pHackConverter ) 1428 { // werden nur hierbei gebraucht 1429 bOldConvert = rScan.GetConvertMode(); 1430 eOldTmpLang = rScan.GetTmpLnge(); 1431 eOldNewLang = rScan.GetNewLnge(); 1432 } 1433 String aLoadedColorName; 1434 for (sal_uInt16 i = 0; i < 4; i++) 1435 { 1436 NumFor[i].Load( rStream, rScan, aLoadedColorName ); 1437 if ( pHackConverter && eHackConversion == NF_CONVERT_NONE ) 1438 { 1439 //! HACK! ER 29.07.97 13:52 1440 // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/ 1441 // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert.. 1442 // System-German FARBE nach System-xxx COLOR umsetzen und vice versa, 1443 //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in 1444 //! ImpSvNumberformatScan existierten 1445 if ( aLoadedColorName.Len() && !NumFor[i].GetColor() 1446 && aLoadedColorName != rScan.GetColorString() ) 1447 { 1448 if ( rScan.GetColorString().EqualsAscii( "FARBE" ) ) 1449 { // English -> German 1450 eHackConversion = NF_CONVERT_ENGLISH_GERMAN; 1451 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US ); 1452 rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN ); 1453 } 1454 else 1455 { // German -> English 1456 eHackConversion = NF_CONVERT_GERMAN_ENGLISH; 1457 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN ); 1458 rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US ); 1459 } 1460 String aColorName = NumFor[i].GetColorName(); 1461 const Color* pColor = rScan.GetColor( aColorName ); 1462 if ( !pColor && aLoadedColorName == aColorName ) 1463 eHackConversion = NF_CONVERT_NONE; 1464 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM ); 1465 rScan.SetConvertMode( eOldTmpLang, eOldNewLang ); 1466 rScan.SetConvertMode( bOldConvert ); 1467 } 1468 } 1469 } 1470 eOp1 = (SvNumberformatLimitOps) nOp1; 1471 eOp2 = (SvNumberformatLimitOps) nOp2; 1472 String aComment; // wird nach dem NewCurrency-Geraffel richtig gesetzt 1473 if ( rHdr.BytesLeft() ) 1474 { // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD 1475 SvNumberformat::LoadString( rStream, aComment ); 1476 rStream >> nNewStandardDefined; 1477 } 1478 1479 xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND; 1480 sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic && 1481 (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND ); 1482 sal_Bool bNewCurrencyLoaded = sal_False; 1483 sal_Bool bNewCurrency = sal_False; 1484 1485 sal_Bool bGoOn = sal_True; 1486 while ( rHdr.BytesLeft() && bGoOn ) 1487 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR 1488 sal_uInt16 nId; 1489 rStream >> nId; 1490 switch ( nId ) 1491 { 1492 case nNewCurrencyVersionId : 1493 { 1494 bNewCurrencyLoaded = sal_True; 1495 rStream >> bNewCurrency; 1496 if ( bNewCurrency ) 1497 { 1498 for ( sal_uInt16 j=0; j<4; j++ ) 1499 { 1500 NumFor[j].LoadNewCurrencyMap( rStream ); 1501 } 1502 } 1503 } 1504 break; 1505 case nNewStandardFlagVersionId : 1506 rStream >> bStandard; // the real standard flag 1507 break; 1508 default: 1509 DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" ); 1510 bGoOn = sal_False; // stop reading unknown stream left over of newer versions 1511 // Would be nice to have multiple read/write headers instead 1512 // but old versions wouldn't know it, TLOT. 1513 } 1514 } 1515 rHdr.EndEntry(); 1516 1517 if ( bNewCurrencyLoaded ) 1518 { 1519 if ( bNewCurrency && bNewCurrencyComment ) 1520 { // original Formatstring und Kommentar wiederherstellen 1521 sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 ); 1522 aComment.Erase( 0, nNewCurrencyEnd+1 ); 1523 } 1524 } 1525 else if ( bNewCurrencyComment ) 1526 { // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert 1527 // original Formatstring und Kommentar wiederherstellen 1528 sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 ); 1529 aComment.Erase( 0, nNewCurrencyEnd+1 ); 1530 // Zustaende merken 1531 short nDefined = ( eType & NUMBERFORMAT_DEFINED ); 1532 sal_uInt16 nNewStandard = nNewStandardDefined; 1533 // neu parsen etc. 1534 String aStr( sFormatstring ); 1535 xub_StrLen nCheckPos = 0; 1536 SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc, 1537 nCheckPos, eLnge, bStandard ); 1538 DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" ); 1539 ImpCopyNumberformat( *pFormat ); 1540 delete pFormat; 1541 // Zustaende wiederherstellen 1542 eType |= nDefined; 1543 if ( nNewStandard ) 1544 SetNewStandardDefined( nNewStandard ); 1545 } 1546 SetComment( aComment ); 1547 1548 if ( eHackConversion != NF_CONVERT_NONE ) 1549 { //! und weiter mit dem HACK! 1550 switch ( eHackConversion ) 1551 { 1552 case NF_CONVERT_ENGLISH_GERMAN : 1553 ConvertLanguage( *pHackConverter, 1554 LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, sal_True ); 1555 break; 1556 case NF_CONVERT_GERMAN_ENGLISH : 1557 ConvertLanguage( *pHackConverter, 1558 LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True ); 1559 break; 1560 default: 1561 DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" ); 1562 } 1563 } 1564 return eHackConversion; 1565 } 1566 1567 void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter, 1568 LanguageType eConvertFrom, LanguageType eConvertTo, sal_Bool bSystem ) 1569 { 1570 xub_StrLen nCheckPos; 1571 sal_uInt32 nKey; 1572 short nType = eType; 1573 String aFormatString( sFormatstring ); 1574 if ( bSystem ) 1575 rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType, 1576 nKey, eConvertFrom, eConvertTo ); 1577 else 1578 rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType, 1579 nKey, eConvertFrom, eConvertTo ); 1580 const SvNumberformat* pFormat = rConverter.GetEntry( nKey ); 1581 DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" ); 1582 if ( pFormat ) 1583 { 1584 ImpCopyNumberformat( *pFormat ); 1585 // aus Formatter/Scanner uebernommene Werte zuruecksetzen 1586 if ( bSystem ) 1587 eLnge = LANGUAGE_SYSTEM; 1588 // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner 1589 for ( sal_uInt16 i = 0; i < 4; i++ ) 1590 { 1591 String aColorName = NumFor[i].GetColorName(); 1592 Color* pColor = rScan.GetColor( aColorName ); 1593 NumFor[i].SetColor( pColor, aColorName ); 1594 } 1595 } 1596 } 1597 1598 1599 // static 1600 void SvNumberformat::LoadString( SvStream& rStream, String& rStr ) 1601 { 1602 CharSet eStream = rStream.GetStreamCharSet(); 1603 ByteString aStr; 1604 rStream.ReadByteString( aStr ); 1605 sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream ); 1606 if ( aStr.Search( cStream ) == STRING_NOTFOUND ) 1607 { // simple conversion to unicode 1608 rStr = UniString( aStr, eStream ); 1609 } 1610 else 1611 { 1612 sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol(); 1613 register const sal_Char* p = aStr.GetBuffer(); 1614 register const sal_Char* const pEnd = p + aStr.Len(); 1615 register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() ); 1616 while ( p < pEnd ) 1617 { 1618 if ( *p == cStream ) 1619 *pUni = cTarget; 1620 else 1621 *pUni = ByteString::ConvertToUnicode( *p, eStream ); 1622 p++; 1623 pUni++; 1624 } 1625 *pUni = 0; 1626 } 1627 } 1628 1629 1630 void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const 1631 { 1632 String aFormatstring( sFormatstring ); 1633 String aComment( sComment ); 1634 #if NF_COMMENT_IN_FORMATSTRING 1635 // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen 1636 // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung 1637 // (z.B. im Dialog) zu ermoeglichen 1638 SetComment( "", aFormatstring, aComment ); 1639 #endif 1640 1641 sal_Bool bNewCurrency = HasNewCurrency(); 1642 if ( bNewCurrency ) 1643 { // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern 1644 aComment.Insert( cNewCurrencyMagic, 0 ); 1645 aComment.Insert( cNewCurrencyMagic, 0 ); 1646 aComment.Insert( aFormatstring, 1 ); 1647 Build50Formatstring( aFormatstring ); // alten Formatstring generieren 1648 } 1649 1650 // old SO5 versions do behave strange (no output) if standard flag is set 1651 // on formats not prepared for it (not having the following exact types) 1652 sal_Bool bOldStandard = bStandard; 1653 if ( bOldStandard ) 1654 { 1655 switch ( eType ) 1656 { 1657 case NUMBERFORMAT_NUMBER : 1658 case NUMBERFORMAT_DATE : 1659 case NUMBERFORMAT_TIME : 1660 case NUMBERFORMAT_DATETIME : 1661 case NUMBERFORMAT_PERCENT : 1662 case NUMBERFORMAT_SCIENTIFIC : 1663 // ok to save 1664 break; 1665 default: 1666 bOldStandard = sal_False; 1667 } 1668 } 1669 1670 rHdr.StartEntry(); 1671 rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() ); 1672 rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2 1673 << bOldStandard << bIsUsed; 1674 for (sal_uInt16 i = 0; i < 4; i++) 1675 NumFor[i].Save(rStream); 1676 // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD 1677 rStream.WriteByteString( aComment, rStream.GetStreamCharSet() ); 1678 rStream << nNewStandardDefined; 1679 // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR 1680 rStream << nNewCurrencyVersionId; 1681 rStream << bNewCurrency; 1682 if ( bNewCurrency ) 1683 { 1684 for ( sal_uInt16 j=0; j<4; j++ ) 1685 { 1686 NumFor[j].SaveNewCurrencyMap( rStream ); 1687 } 1688 } 1689 1690 // the real standard flag to load with versions >638 if different 1691 if ( bStandard != bOldStandard ) 1692 { 1693 rStream << nNewStandardFlagVersionId; 1694 rStream << bStandard; 1695 } 1696 1697 rHdr.EndEntry(); 1698 } 1699 1700 1701 sal_Bool SvNumberformat::HasNewCurrency() const 1702 { 1703 for ( sal_uInt16 j=0; j<4; j++ ) 1704 { 1705 if ( NumFor[j].HasNewCurrency() ) 1706 return sal_True; 1707 } 1708 return sal_False; 1709 } 1710 1711 1712 sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol, 1713 String& rExtension ) const 1714 { 1715 for ( sal_uInt16 j=0; j<4; j++ ) 1716 { 1717 if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) ) 1718 return sal_True; 1719 } 1720 rSymbol.Erase(); 1721 rExtension.Erase(); 1722 return sal_False; 1723 } 1724 1725 1726 // static 1727 String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr, 1728 sal_Bool bQuoteSymbol ) 1729 { 1730 String aTmp; 1731 xub_StrLen nStartPos, nPos, nLen; 1732 nLen = rStr.Len(); 1733 nStartPos = 0; 1734 while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND ) 1735 { 1736 xub_StrLen nEnd; 1737 if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen ) 1738 { 1739 aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos ); 1740 nStartPos = nEnd; 1741 } 1742 else 1743 { 1744 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1745 nStartPos = nPos + 2; 1746 xub_StrLen nDash; 1747 nEnd = nStartPos - 1; 1748 do 1749 { 1750 nDash = rStr.Search( '-', ++nEnd ); 1751 } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen ); 1752 xub_StrLen nClose; 1753 nEnd = nStartPos - 1; 1754 do 1755 { 1756 nClose = rStr.Search( ']', ++nEnd ); 1757 } while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen ); 1758 nPos = ( nDash < nClose ? nDash : nClose ); 1759 if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' ) 1760 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1761 else 1762 { 1763 aTmp += '"'; 1764 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1765 aTmp += '"'; 1766 } 1767 nStartPos = nClose + 1; 1768 } 1769 } 1770 if ( nLen > nStartPos ) 1771 aTmp += rStr.Copy( nStartPos, nLen - nStartPos ); 1772 return aTmp; 1773 } 1774 1775 1776 void SvNumberformat::Build50Formatstring( String& rStr ) const 1777 { 1778 rStr = StripNewCurrencyDelimiters( sFormatstring, sal_True ); 1779 } 1780 1781 1782 void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString) 1783 { 1784 sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); 1785 1786 if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16 1787 { 1788 nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals 1789 OutString = ::rtl::math::doubleToUString( fNumber, 1790 rtl_math_StringFormat_E, nStandardPrec /*2*/, 1791 GetFormatter().GetNumDecimalSep().GetChar(0)); 1792 } 1793 else 1794 ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec); 1795 } 1796 1797 void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const 1798 { 1799 // Make sure the precision doesn't go over the maximum allowable precision. 1800 nPrecision = ::std::min(UPPER_PRECISION, nPrecision); 1801 1802 #if 0 1803 { 1804 // debugger test case for ANSI standard correctness 1805 ::rtl::OUString aTest; 1806 // expect 0.00123 OK 1807 aTest = ::rtl::math::doubleToUString( 0.001234567, 1808 rtl_math_StringFormat_G, 3, '.', sal_True ); 1809 // expect 123 OK 1810 aTest = ::rtl::math::doubleToUString( 123.4567, 1811 rtl_math_StringFormat_G, 3, '.', sal_True ); 1812 // expect 123.5 OK 1813 aTest = ::rtl::math::doubleToUString( 123.4567, 1814 rtl_math_StringFormat_G, 4, '.', sal_True ); 1815 // expect 1e+03 (as 999.6 rounded to 3 significant digits results in 1816 // 1000 with an exponent equal to significant digits) 1817 // Currently (24-Jan-2003) we do fail in this case and output 1000 1818 // instead, negligible. 1819 aTest = ::rtl::math::doubleToUString( 999.6, 1820 rtl_math_StringFormat_G, 3, '.', sal_True ); 1821 // expect what? result is 1.2e+004 1822 aTest = ::rtl::math::doubleToUString( 12345.6789, 1823 rtl_math_StringFormat_G, -3, '.', sal_True ); 1824 } 1825 #endif 1826 1827 // We decided to strip trailing zeros unconditionally, since binary 1828 // double-precision rounding error makes it impossible to determine e.g. 1829 // whether 844.10000000000002273737 is what the user has typed, or the 1830 // user has typed 844.1 but IEEE 754 represents it that way internally. 1831 1832 rOutString = ::rtl::math::doubleToUString( rNumber, 1833 rtl_math_StringFormat_F, nPrecision /*2*/, 1834 GetFormatter().GetNumDecimalSep().GetChar(0), true ); 1835 if (rOutString.GetChar(0) == '-' && 1836 rOutString.GetTokenCount('0') == rOutString.Len()) 1837 rOutString.EraseLeadingChars('-'); // nicht -0 1838 1839 ImpTransliterate( rOutString, NumFor[0].GetNatNum() ); 1840 } 1841 1842 void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString) 1843 { 1844 sal_Bool bModified = sal_False; 1845 if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100)) 1846 { 1847 if (fNumber == 0.0) 1848 { 1849 OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) ); 1850 return; 1851 } 1852 fNumber *= 100; 1853 bModified = sal_True; 1854 } 1855 1856 if (fNumber == 0.0) 1857 { 1858 OutString = '0'; 1859 return; 1860 } 1861 1862 OutString = ::rtl::math::doubleToUString( fNumber, 1863 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 1864 GetFormatter().GetNumDecimalSep().GetChar(0), sal_True ); 1865 1866 if ( eType & NUMBERFORMAT_PERCENT && bModified) 1867 OutString += '%'; 1868 return; 1869 } 1870 1871 short SvNumberformat::ImpCheckCondition(double& fNumber, 1872 double& fLimit, 1873 SvNumberformatLimitOps eOp) 1874 { 1875 switch(eOp) 1876 { 1877 case NUMBERFORMAT_OP_NO: return -1; 1878 case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit); 1879 case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit); 1880 case NUMBERFORMAT_OP_LT: return (short) (fNumber < fLimit); 1881 case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit); 1882 case NUMBERFORMAT_OP_GT: return (short) (fNumber > fLimit); 1883 case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit); 1884 default: return -1; 1885 } 1886 } 1887 1888 sal_Bool SvNumberformat::GetOutputString(String& sString, 1889 String& OutString, 1890 Color** ppColor) 1891 { 1892 OutString.Erase(); 1893 sal_uInt16 nIx; 1894 if (eType & NUMBERFORMAT_TEXT) 1895 nIx = 0; 1896 else if (NumFor[3].GetnAnz() > 0) 1897 nIx = 3; 1898 else 1899 { 1900 *ppColor = NULL; // no change of color 1901 return sal_False; 1902 } 1903 *ppColor = NumFor[nIx].GetColor(); 1904 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 1905 if (rInfo.eScannedType == NUMBERFORMAT_TEXT) 1906 { 1907 sal_Bool bRes = sal_False; 1908 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 1909 for (sal_uInt16 i = 0; i < nAnz; i++) 1910 { 1911 switch (rInfo.nTypeArray[i]) 1912 { 1913 case NF_SYMBOLTYPE_STAR: 1914 if( bStarFlag ) 1915 { 1916 OutString += (sal_Unicode) 0x1B; 1917 OutString += rInfo.sStrArray[i].GetChar(1); 1918 bRes = sal_True; 1919 } 1920 break; 1921 case NF_SYMBOLTYPE_BLANK: 1922 InsertBlanks( OutString, OutString.Len(), 1923 rInfo.sStrArray[i].GetChar(1) ); 1924 break; 1925 case NF_KEY_GENERAL : // #77026# "General" is the same as "@" 1926 case NF_SYMBOLTYPE_DEL : 1927 OutString += sString; 1928 break; 1929 default: 1930 OutString += rInfo.sStrArray[i]; 1931 } 1932 } 1933 return bRes; 1934 } 1935 return sal_False; 1936 } 1937 /* 1938 void SvNumberformat::GetNextFareyNumber(sal_uLong nPrec, sal_uLong x0, sal_uLong x1, 1939 sal_uLong y0, sal_uLong y1, 1940 sal_uLong& x2,sal_uLong& y2) 1941 { 1942 x2 = ((y0+nPrec)/y1)*x1 - x0; 1943 y2 = ((y0+nPrec)/y1)*y1 - y0; 1944 } 1945 */ 1946 sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y) 1947 { 1948 if (y == 0) 1949 return x; 1950 else 1951 { 1952 sal_uLong z = x%y; 1953 while (z) 1954 { 1955 x = y; 1956 y = z; 1957 z = x%y; 1958 } 1959 return y; 1960 } 1961 } 1962 1963 sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y) 1964 { 1965 if (y == 0) 1966 return x; 1967 else 1968 { 1969 sal_uLong z = x%y; 1970 while ((double)z/(double)y > D_EPS) 1971 { 1972 x = y; 1973 y = z; 1974 z = x%y; 1975 } 1976 return y; 1977 } 1978 } 1979 1980 namespace { 1981 1982 void lcl_GetOutputStringScientific( 1983 double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString) 1984 { 1985 bool bSign = ::rtl::math::isSignBitSet(fNumber); 1986 1987 // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7). 1988 sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0; 1989 if (nPrec && bSign) 1990 // Make room for the negative sign. 1991 --nPrec; 1992 1993 nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals. 1994 1995 rOutString = ::rtl::math::doubleToUString( 1996 fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0)); 1997 } 1998 1999 } 2000 2001 bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const 2002 { 2003 using namespace std; 2004 2005 if (eType != NUMBERFORMAT_NUMBER) 2006 return false; 2007 2008 double fTestNum = fNumber; 2009 bool bSign = ::rtl::math::isSignBitSet(fTestNum); 2010 if (bSign) 2011 fTestNum = -fTestNum; 2012 2013 if (fTestNum < EXP_LOWER_BOUND) 2014 { 2015 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2016 return true; 2017 } 2018 2019 double fExp = log10(fTestNum); 2020 // Values < 1.0 always have one digit before the decimal point. 2021 sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1; 2022 2023 if (nDigitPre > 15) 2024 { 2025 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2026 return true; 2027 } 2028 2029 sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0; 2030 if (nPrec && bSign) 2031 // Subtract the negative sign. 2032 --nPrec; 2033 if (nPrec) 2034 // Subtract the decimal point. 2035 --nPrec; 2036 2037 ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec); 2038 if (rOutString.Len() > nCharCount) 2039 // String still wider than desired. Switch to scientific notation. 2040 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2041 2042 return true; 2043 } 2044 2045 sal_Bool SvNumberformat::GetOutputString(double fNumber, 2046 String& OutString, 2047 Color** ppColor) 2048 { 2049 sal_Bool bRes = sal_False; 2050 OutString.Erase(); // alles loeschen 2051 *ppColor = NULL; // keine Farbaenderung 2052 if (eType & NUMBERFORMAT_LOGICAL) 2053 { 2054 if (fNumber) 2055 OutString = rScan.GetTrueString(); 2056 else 2057 OutString = rScan.GetFalseString(); 2058 return sal_False; 2059 } 2060 if (eType & NUMBERFORMAT_TEXT) 2061 { 2062 ImpGetOutputStandard(fNumber, OutString); 2063 return sal_False; 2064 } 2065 sal_Bool bHadStandard = sal_False; 2066 if (bStandard) // einzelne Standardformate 2067 { 2068 if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // alle Zahlformate InputLine 2069 { 2070 ImpGetOutputInputLine(fNumber, OutString); 2071 return false; 2072 } 2073 switch (eType) 2074 { 2075 case NUMBERFORMAT_NUMBER: // Standardzahlformat 2076 { 2077 if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION) 2078 { 2079 bool bSign = ::rtl::math::isSignBitSet(fNumber); 2080 if (bSign) 2081 fNumber = -fNumber; 2082 ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format. 2083 if (fNumber < EXP_LOWER_BOUND) 2084 { 2085 xub_StrLen nLen = OutString.Len(); 2086 if (!nLen) 2087 return false; 2088 2089 // #i112250# With the 10-decimal limit, small numbers are formatted as "0". 2090 // Switch to scientific in that case, too: 2091 if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0)) 2092 { 2093 sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); 2094 nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals 2095 OutString = ::rtl::math::doubleToUString( fNumber, 2096 rtl_math_StringFormat_E, nStandardPrec /*2*/, 2097 GetFormatter().GetNumDecimalSep().GetChar(0), true); 2098 } 2099 } 2100 if (bSign) 2101 OutString.Insert('-', 0); 2102 return false; 2103 } 2104 ImpGetOutputStandard(fNumber, OutString); 2105 bHadStandard = sal_True; 2106 } 2107 break; 2108 case NUMBERFORMAT_DATE: 2109 bRes |= ImpGetDateOutput(fNumber, 0, OutString); 2110 bHadStandard = sal_True; 2111 break; 2112 case NUMBERFORMAT_TIME: 2113 bRes |= ImpGetTimeOutput(fNumber, 0, OutString); 2114 bHadStandard = sal_True; 2115 break; 2116 case NUMBERFORMAT_DATETIME: 2117 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString); 2118 bHadStandard = sal_True; 2119 break; 2120 } 2121 } 2122 if ( !bHadStandard ) 2123 { 2124 sal_uInt16 nIx; // Index des Teilformats 2125 short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1); 2126 if (nCheck == -1 || nCheck == 1) // nur 1 String oder True 2127 nIx = 0; 2128 else 2129 { 2130 nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2); 2131 if (nCheck == -1 || nCheck == 1) 2132 nIx = 1; 2133 else 2134 nIx = 2; 2135 } 2136 if (nIx == 1 && fNumber < 0.0 && // negatives Format 2137 IsNegativeRealNegative() ) // ohne Vorzeichen 2138 fNumber = -fNumber; // Vorzeichen eliminieren 2139 *ppColor = NumFor[nIx].GetColor(); 2140 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2141 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2142 if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED) 2143 return sal_False; // leer => nichts 2144 else if (nAnz == 0) // sonst Standard-Format 2145 { 2146 ImpGetOutputStandard(fNumber, OutString); 2147 return sal_False; 2148 } 2149 switch (rInfo.eScannedType) 2150 { 2151 case NUMBERFORMAT_TEXT: 2152 case NUMBERFORMAT_DEFINED: 2153 { 2154 for (sal_uInt16 i = 0; i < nAnz; i++) 2155 { 2156 switch (rInfo.nTypeArray[i]) 2157 { 2158 case NF_SYMBOLTYPE_STAR: 2159 if( bStarFlag ) 2160 { 2161 OutString += (sal_Unicode) 0x1B; 2162 OutString += rInfo.sStrArray[i].GetChar(1); 2163 bRes = sal_True; 2164 } 2165 break; 2166 case NF_SYMBOLTYPE_BLANK: 2167 InsertBlanks( OutString, OutString.Len(), 2168 rInfo.sStrArray[i].GetChar(1) ); 2169 break; 2170 case NF_SYMBOLTYPE_STRING: 2171 case NF_SYMBOLTYPE_CURRENCY: 2172 OutString += rInfo.sStrArray[i]; 2173 break; 2174 case NF_SYMBOLTYPE_THSEP: 2175 if (rInfo.nThousand == 0) 2176 OutString += rInfo.sStrArray[i]; 2177 break; 2178 default: 2179 break; 2180 } 2181 } 2182 } 2183 break; 2184 case NUMBERFORMAT_DATE: 2185 bRes |= ImpGetDateOutput(fNumber, nIx, OutString); 2186 break; 2187 case NUMBERFORMAT_TIME: 2188 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString); 2189 break; 2190 case NUMBERFORMAT_DATETIME: 2191 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString); 2192 break; 2193 case NUMBERFORMAT_NUMBER: 2194 case NUMBERFORMAT_PERCENT: 2195 case NUMBERFORMAT_CURRENCY: 2196 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString); 2197 break; 2198 case NUMBERFORMAT_FRACTION: 2199 { 2200 String sStr, sFrac, sDiv; // Strings, Wert fuer 2201 sal_uLong nFrac, nDiv; // Vorkommaanteil 2202 // Zaehler und Nenner 2203 sal_Bool bSign = sal_False; 2204 if (fNumber < 0) 2205 { 2206 if (nIx == 0) // nicht in hinteren 2207 bSign = sal_True; // Formaten 2208 fNumber = -fNumber; 2209 } 2210 double fNum = floor(fNumber); // Vorkommateil 2211 fNumber -= fNum; // Nachkommateil 2212 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9) 2213 // zu gross 2214 { 2215 OutString = rScan.GetErrorString(); 2216 return sal_False; 2217 } 2218 if (rInfo.nCntExp == 0) 2219 { 2220 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0"); 2221 return sal_False; 2222 } 2223 sal_uLong nBasis = ((sal_uLong)floor( // 9, 99, 999 ,... 2224 pow(10.0,rInfo.nCntExp))) - 1; 2225 sal_uLong x0, y0, x1, y1; 2226 2227 if (rInfo.nCntExp <= _MAX_FRACTION_PREC) 2228 { 2229 sal_Bool bUpperHalf; 2230 if (fNumber > 0.5) 2231 { 2232 bUpperHalf = sal_True; 2233 fNumber -= (fNumber - 0.5) * 2.0; 2234 } 2235 else 2236 bUpperHalf = sal_False; 2237 // Einstieg in Farey-Serie 2238 // finden: 2239 x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9 2240 if (x0 == 0) // => x0 = 2 2241 { 2242 y0 = 1; 2243 x1 = 1; 2244 y1 = nBasis; 2245 } 2246 else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2 2247 { // geht (nBasis ungerade) 2248 y0 = nBasis; 2249 x1 = 1; 2250 y1 = 2; 2251 } 2252 else if (x0 == 1) 2253 { 2254 y0 = nBasis; // 1/n; 1/(n-1) 2255 x1 = 1; 2256 y1 = nBasis - 1; 2257 } 2258 else 2259 { 2260 y0 = nBasis; // z.B. 2/9 2/8 2261 x1 = x0; 2262 y1 = nBasis - 1; 2263 double fUg = (double) x0 / (double) y0; 2264 double fOg = (double) x1 / (double) y1; 2265 sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen 2266 x0 /= nGgt; 2267 y0 /= nGgt; // Einschachteln: 2268 sal_uLong x2 = 0; 2269 sal_uLong y2 = 0; 2270 sal_Bool bStop = sal_False; 2271 while (!bStop) 2272 { 2273 #ifdef GCC 2274 // #i21648# GCC over-optimizes something resulting 2275 // in wrong fTest values throughout the loops. 2276 volatile 2277 #endif 2278 double fTest = (double)x1/(double)y1; 2279 while (!bStop) 2280 { 2281 while (fTest > fOg) 2282 { 2283 x1--; 2284 fTest = (double)x1/(double)y1; 2285 } 2286 while (fTest < fUg && y1 > 1) 2287 { 2288 y1--; 2289 fTest = (double)x1/(double)y1; 2290 } 2291 if (fTest <= fOg) 2292 { 2293 fOg = fTest; 2294 bStop = sal_True; 2295 } 2296 else if (y1 == 1) 2297 bStop = sal_True; 2298 } // of while 2299 nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen 2300 x2 = x1 / nGgt; 2301 y2 = y1 / nGgt; 2302 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2 2303 bStop = sal_True; // naechste Farey-Zahl 2304 else 2305 { 2306 y1--; 2307 bStop = sal_False; 2308 } 2309 } // of while 2310 x1 = x2; 2311 y1 = y2; 2312 } // of else 2313 double fup, flow; 2314 flow = (double)x0/(double)y0; 2315 fup = (double)x1/(double)y1; 2316 while (fNumber > fup) 2317 { 2318 sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl 2319 sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0; 2320 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2); 2321 x0 = x1; 2322 y0 = y1; 2323 x1 = x2; 2324 y1 = y2; 2325 flow = fup; 2326 fup = (double)x1/(double)y1; 2327 } 2328 if (fNumber - flow < fup - fNumber) 2329 { 2330 nFrac = x0; 2331 nDiv = y0; 2332 } 2333 else 2334 { 2335 nFrac = x1; 2336 nDiv = y1; 2337 } 2338 if (bUpperHalf) // Original restaur. 2339 { 2340 if (nFrac == 0 && nDiv == 1) // 1/1 2341 fNum += 1.0; 2342 else 2343 nFrac = nDiv - nFrac; 2344 } 2345 } 2346 else // grosse Nenner 2347 { // 0,1234->123/1000 2348 sal_uLong nGgt; 2349 /* 2350 nDiv = nBasis+1; 2351 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2352 pow(10.0,rInfo.nCntExp))); 2353 */ 2354 nDiv = 10000000; 2355 nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0)); 2356 nGgt = ImpGGT(nDiv, nFrac); 2357 if (nGgt > 1) 2358 { 2359 nDiv /= nGgt; 2360 nFrac /= nGgt; 2361 } 2362 if (nDiv > nBasis) 2363 { 2364 nGgt = ImpGGTRound(nDiv, nFrac); 2365 if (nGgt > 1) 2366 { 2367 nDiv /= nGgt; 2368 nFrac /= nGgt; 2369 } 2370 } 2371 if (nDiv > nBasis) 2372 { 2373 nDiv = nBasis; 2374 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2375 pow(10.0,rInfo.nCntExp))); 2376 nGgt = ImpGGTRound(nDiv, nFrac); 2377 if (nGgt > 1) 2378 { 2379 nDiv /= nGgt; 2380 nFrac /= nGgt; 2381 } 2382 } 2383 } 2384 2385 if (rInfo.nCntPre == 0) // unechter Bruch 2386 { 2387 double fNum1 = fNum * (double)nDiv + (double)nFrac; 2388 if (fNum1 > _D_MAX_U_LONG_) 2389 { 2390 OutString = rScan.GetErrorString(); 2391 return sal_False; 2392 } 2393 nFrac = (sal_uLong) floor(fNum1); 2394 sStr.Erase(); 2395 } 2396 else if (fNum == 0.0 && nFrac != 0) 2397 sStr.Erase(); 2398 else 2399 { 2400 char aBuf[100]; 2401 sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked) 2402 sStr.AssignAscii( aBuf ); 2403 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 2404 } 2405 if (rInfo.nCntPre > 0 && nFrac == 0) 2406 { 2407 sFrac.Erase(); 2408 sDiv.Erase(); 2409 } 2410 else 2411 { 2412 sFrac = ImpIntToString( nIx, nFrac ); 2413 sDiv = ImpIntToString( nIx, nDiv ); 2414 } 2415 2416 sal_uInt16 j = nAnz-1; // letztes Symbol->rueckw. 2417 xub_StrLen k; // Nenner: 2418 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC); 2419 sal_Bool bCont = sal_True; 2420 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC) 2421 { 2422 if (rInfo.nCntPre > 0 && nFrac == 0) 2423 sDiv.Insert(' ',0); 2424 else 2425 sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 ); 2426 if ( j ) 2427 j--; 2428 else 2429 bCont = sal_False; 2430 } 2431 // weiter Zaehler: 2432 if ( !bCont ) 2433 sFrac.Erase(); 2434 else 2435 { 2436 bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK); 2437 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK) 2438 { 2439 sFrac.Insert(rInfo.sStrArray[j],0); 2440 if ( j ) 2441 j--; 2442 else 2443 bCont = sal_False; 2444 } 2445 } 2446 // weiter Hauptzahl 2447 if ( !bCont ) 2448 sStr.Erase(); 2449 else 2450 { 2451 k = sStr.Len(); // hinter letzter Ziffer 2452 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, 2453 rInfo.nCntPre); 2454 } 2455 if (bSign && !(nFrac == 0 && fNum == 0.0)) 2456 OutString.Insert('-',0); // nicht -0 2457 OutString += sStr; 2458 OutString += sFrac; 2459 OutString += sDiv; 2460 } 2461 break; 2462 case NUMBERFORMAT_SCIENTIFIC: 2463 { 2464 sal_Bool bSign = sal_False; 2465 if (fNumber < 0) 2466 { 2467 if (nIx == 0) // nicht in hinteren 2468 bSign = sal_True; // Formaten 2469 fNumber = -fNumber; 2470 } 2471 String sStr( ::rtl::math::doubleToUString( fNumber, 2472 rtl_math_StringFormat_E, 2473 rInfo.nCntPre + rInfo.nCntPost - 1, '.' )); 2474 2475 String ExpStr; 2476 short nExpSign = 1; 2477 xub_StrLen nExPos = sStr.Search('E'); 2478 if ( nExPos != STRING_NOTFOUND ) 2479 { 2480 // split into mantisse and exponent and get rid of "E+" or "E-" 2481 xub_StrLen nExpStart = nExPos + 1; 2482 switch ( sStr.GetChar( nExpStart ) ) 2483 { 2484 case '-' : 2485 nExpSign = -1; 2486 // fallthru 2487 case '+' : 2488 ++nExpStart; 2489 break; 2490 } 2491 ExpStr = sStr.Copy( nExpStart ); // part following the "E+" 2492 sStr.Erase( nExPos ); 2493 sStr.EraseAllChars('.'); // cut any decimal delimiter 2494 if ( rInfo.nCntPre != 1 ) // rescale Exp 2495 { 2496 sal_Int32 nExp = ExpStr.ToInt32() * nExpSign; 2497 nExp -= sal_Int32(rInfo.nCntPre)-1; 2498 if ( nExp < 0 ) 2499 { 2500 nExpSign = -1; 2501 nExp = -nExp; 2502 } 2503 else 2504 nExpSign = 1; 2505 ExpStr = String::CreateFromInt32( nExp ); 2506 } 2507 } 2508 sal_uInt16 j = nAnz-1; // last symbol 2509 xub_StrLen k; // position in ExpStr 2510 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP); 2511 2512 xub_StrLen nZeros = 0; // erase leading zeros 2513 while (nZeros < k && ExpStr.GetChar(nZeros) == '0') 2514 ++nZeros; 2515 if (nZeros) 2516 ExpStr.Erase( 0, nZeros); 2517 2518 sal_Bool bCont = sal_True; 2519 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP) 2520 { 2521 const String& rStr = rInfo.sStrArray[j]; 2522 if (nExpSign == -1) 2523 ExpStr.Insert('-',0); 2524 else if (rStr.Len() > 1 && rStr.GetChar(1) == '+') 2525 ExpStr.Insert('+',0); 2526 ExpStr.Insert(rStr.GetChar(0),0); 2527 if ( j ) 2528 j--; 2529 else 2530 bCont = sal_False; 2531 } 2532 // weiter Hauptzahl: 2533 if ( !bCont ) 2534 sStr.Erase(); 2535 else 2536 { 2537 k = sStr.Len(); // hinter letzter Ziffer 2538 bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx, 2539 rInfo.nCntPre + 2540 rInfo.nCntPost); 2541 } 2542 if (bSign) 2543 sStr.Insert('-',0); 2544 OutString = sStr; 2545 OutString += ExpStr; 2546 } 2547 break; 2548 } 2549 } 2550 return bRes; 2551 } 2552 2553 sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber, 2554 sal_uInt16 nIx, 2555 String& OutString) 2556 { 2557 using namespace ::com::sun::star::i18n; 2558 sal_Bool bCalendarSet = sal_False; 2559 double fNumberOrig = fNumber; 2560 sal_Bool bRes = sal_False; 2561 sal_Bool bSign = sal_False; 2562 if (fNumber < 0.0) 2563 { 2564 fNumber = -fNumber; 2565 if (nIx == 0) 2566 bSign = sal_True; 2567 } 2568 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2569 if (rInfo.bThousand) // []-Format 2570 { 2571 if (fNumber > 1.0E10) // zu gross 2572 { 2573 OutString = rScan.GetErrorString(); 2574 return sal_False; 2575 } 2576 } 2577 else 2578 fNumber -= floor(fNumber); // sonst Datum abtrennen 2579 sal_Bool bInputLine; 2580 xub_StrLen nCntPost; 2581 if ( rScan.GetStandardPrec() == 300 && 2582 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 2583 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 2584 bInputLine = sal_True; 2585 nCntPost = 7; 2586 } 2587 else 2588 { 2589 bInputLine = sal_False; 2590 nCntPost = xub_StrLen(rInfo.nCntPost); 2591 } 2592 if (bSign && !rInfo.bThousand) // kein []-Format 2593 fNumber = 1.0 - fNumber; // "Kehrwert" 2594 double fTime = fNumber * 86400.0; 2595 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 2596 if (bSign && fTime == 0.0) 2597 bSign = sal_False; // nicht -00:00:00 2598 2599 if( floor( fTime ) > _D_MAX_U_LONG_ ) 2600 { 2601 OutString = rScan.GetErrorString(); 2602 return sal_False; 2603 } 2604 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 2605 2606 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 2607 rtl_math_StringFormat_F, int(nCntPost), '.')); 2608 sSecStr.EraseLeadingChars('0'); 2609 sSecStr.EraseLeadingChars('.'); 2610 if ( bInputLine ) 2611 { 2612 sSecStr.EraseTrailingChars('0'); 2613 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 2614 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 2615 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2616 nCntPost = sSecStr.Len(); 2617 } 2618 else 2619 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2620 2621 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 2622 // abarbeiten 2623 sal_uLong nHour, nMin, nSec; 2624 if (!rInfo.bThousand) // kein [] Format 2625 { 2626 nHour = (nSeconds/3600) % 24; 2627 nMin = (nSeconds%3600) / 60; 2628 nSec = nSeconds%60; 2629 } 2630 else if (rInfo.nThousand == 3) // [ss] 2631 { 2632 nHour = 0; 2633 nMin = 0; 2634 nSec = nSeconds; 2635 } 2636 else if (rInfo.nThousand == 2) // [mm]:ss 2637 { 2638 nHour = 0; 2639 nMin = nSeconds / 60; 2640 nSec = nSeconds % 60; 2641 } 2642 else if (rInfo.nThousand == 1) // [hh]:mm:ss 2643 { 2644 nHour = nSeconds / 3600; 2645 nMin = (nSeconds%3600) / 60; 2646 nSec = nSeconds%60; 2647 } 2648 else { 2649 // TODO What should these be set to? 2650 nHour = 0; 2651 nMin = 0; 2652 nSec = 0; 2653 } 2654 2655 sal_Unicode cAmPm = ' '; // a oder p 2656 if (rInfo.nCntExp) // AM/PM 2657 { 2658 if (nHour == 0) 2659 { 2660 nHour = 12; 2661 cAmPm = 'a'; 2662 } 2663 else if (nHour < 12) 2664 cAmPm = 'a'; 2665 else 2666 { 2667 cAmPm = 'p'; 2668 if (nHour > 12) 2669 nHour -= 12; 2670 } 2671 } 2672 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2673 for (sal_uInt16 i = 0; i < nAnz; i++) 2674 { 2675 switch (rInfo.nTypeArray[i]) 2676 { 2677 case NF_SYMBOLTYPE_STAR: 2678 if( bStarFlag ) 2679 { 2680 OutString += (sal_Unicode) 0x1B; 2681 OutString += rInfo.sStrArray[i].GetChar(1); 2682 bRes = sal_True; 2683 } 2684 break; 2685 case NF_SYMBOLTYPE_BLANK: 2686 InsertBlanks( OutString, OutString.Len(), 2687 rInfo.sStrArray[i].GetChar(1) ); 2688 break; 2689 case NF_SYMBOLTYPE_STRING: 2690 case NF_SYMBOLTYPE_CURRENCY: 2691 case NF_SYMBOLTYPE_DATESEP: 2692 case NF_SYMBOLTYPE_TIMESEP: 2693 case NF_SYMBOLTYPE_TIME100SECSEP: 2694 OutString += rInfo.sStrArray[i]; 2695 break; 2696 case NF_SYMBOLTYPE_DIGIT: 2697 { 2698 xub_StrLen nLen = ( bInputLine && i > 0 && 2699 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 2700 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 2701 nCntPost : rInfo.sStrArray[i].Len() ); 2702 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 2703 { 2704 OutString += sSecStr.GetChar(nSecPos); 2705 nSecPos++; 2706 } 2707 } 2708 break; 2709 case NF_KEY_AMPM: // AM/PM 2710 { 2711 if ( !bCalendarSet ) 2712 { 2713 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart(); 2714 fDiff += fNumberOrig; 2715 GetCal().setLocalDateTime( fDiff ); 2716 bCalendarSet = sal_True; 2717 } 2718 if (cAmPm == 'a') 2719 OutString += GetCal().getDisplayName( 2720 CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 ); 2721 else 2722 OutString += GetCal().getDisplayName( 2723 CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 ); 2724 } 2725 break; 2726 case NF_KEY_AP: // A/P 2727 { 2728 if (cAmPm == 'a') 2729 OutString += 'a'; 2730 else 2731 OutString += 'p'; 2732 } 2733 break; 2734 case NF_KEY_MI: // M 2735 OutString += ImpIntToString( nIx, nMin ); 2736 break; 2737 case NF_KEY_MMI: // MM 2738 OutString += ImpIntToString( nIx, nMin, 2 ); 2739 break; 2740 case NF_KEY_H: // H 2741 OutString += ImpIntToString( nIx, nHour ); 2742 break; 2743 case NF_KEY_HH: // HH 2744 OutString += ImpIntToString( nIx, nHour, 2 ); 2745 break; 2746 case NF_KEY_S: // S 2747 OutString += ImpIntToString( nIx, nSec ); 2748 break; 2749 case NF_KEY_SS: // SS 2750 OutString += ImpIntToString( nIx, nSec, 2 ); 2751 break; 2752 default: 2753 break; 2754 } 2755 } 2756 if (bSign && rInfo.bThousand) 2757 OutString.Insert('-',0); 2758 return bRes; 2759 } 2760 2761 2762 sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const 2763 { 2764 if ( GetCal().getUniqueID() != Gregorian::get() ) 2765 return sal_False; 2766 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2767 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2768 sal_uInt16 i; 2769 for ( i = 0; i < nAnz; i++ ) 2770 { 2771 switch ( rInfo.nTypeArray[i] ) 2772 { 2773 case NF_SYMBOLTYPE_CALENDAR : 2774 return sal_False; 2775 case NF_KEY_EC : 2776 case NF_KEY_EEC : 2777 case NF_KEY_R : 2778 case NF_KEY_RR : 2779 case NF_KEY_AAA : 2780 case NF_KEY_AAAA : 2781 return sal_True; 2782 } 2783 } 2784 return sal_False; 2785 } 2786 2787 2788 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar, 2789 double& fOrgDateTime ) const 2790 { 2791 CalendarWrapper& rCal = GetCal(); 2792 const rtl::OUString &rGregorian = Gregorian::get(); 2793 if ( rCal.getUniqueID() == rGregorian ) 2794 { 2795 using namespace ::com::sun::star::i18n; 2796 ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals 2797 = rCal.getAllCalendars( rLoc().getLocale() ); 2798 sal_Int32 nCnt = xCals.getLength(); 2799 if ( nCnt > 1 ) 2800 { 2801 for ( sal_Int32 j=0; j < nCnt; j++ ) 2802 { 2803 if ( xCals[j] != rGregorian ) 2804 { 2805 if ( !rOrgCalendar.Len() ) 2806 { 2807 rOrgCalendar = rCal.getUniqueID(); 2808 fOrgDateTime = rCal.getDateTime(); 2809 } 2810 rCal.loadCalendar( xCals[j], rLoc().getLocale() ); 2811 rCal.setDateTime( fOrgDateTime ); 2812 break; // for 2813 } 2814 } 2815 } 2816 } 2817 } 2818 2819 2820 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar, 2821 double fOrgDateTime ) const 2822 { 2823 CalendarWrapper& rCal = GetCal(); 2824 const rtl::OUString &rGregorian = Gregorian::get(); 2825 if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian ) 2826 { 2827 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2828 rCal.setDateTime( fOrgDateTime ); 2829 } 2830 } 2831 2832 2833 sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime ) 2834 { 2835 using namespace ::com::sun::star::i18n; 2836 CalendarWrapper& rCal = GetCal(); 2837 const rtl::OUString &rGregorian = Gregorian::get(); 2838 if ( rCal.getUniqueID() != rGregorian ) 2839 { 2840 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2841 if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL( 2842 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) ) 2843 { 2844 if ( !rOrgCalendar.Len() ) 2845 { 2846 rOrgCalendar = rCal.getUniqueID(); 2847 fOrgDateTime = rCal.getDateTime(); 2848 } 2849 else if ( rOrgCalendar == String(rGregorian) ) 2850 rOrgCalendar.Erase(); 2851 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2852 rCal.setDateTime( fOrgDateTime ); 2853 return sal_True; 2854 } 2855 } 2856 return sal_False; 2857 } 2858 2859 2860 sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar, 2861 double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const 2862 { 2863 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2864 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2865 for ( sal_uInt16 i = 0; i < nAnz; i++ ) 2866 { 2867 if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR ) 2868 { 2869 CalendarWrapper& rCal = GetCal(); 2870 if ( !rOrgCalendar.Len() ) 2871 { 2872 rOrgCalendar = rCal.getUniqueID(); 2873 fOrgDateTime = rCal.getDateTime(); 2874 } 2875 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2876 rCal.setDateTime( fOrgDateTime ); 2877 return sal_True; 2878 } 2879 } 2880 return sal_False; 2881 } 2882 2883 2884 // static 2885 void SvNumberformat::ImpAppendEraG( String& OutString, 2886 const CalendarWrapper& rCal, sal_Int16 nNatNum ) 2887 { 2888 using namespace ::com::sun::star::i18n; 2889 if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) ) 2890 { 2891 sal_Unicode cEra; 2892 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2893 switch ( nVal ) 2894 { 2895 case 1 : cEra = 'M'; break; 2896 case 2 : cEra = 'T'; break; 2897 case 3 : cEra = 'S'; break; 2898 case 4 : cEra = 'H'; break; 2899 default: 2900 cEra = '?'; 2901 } 2902 OutString += cEra; 2903 } 2904 else 2905 OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ); 2906 } 2907 2908 2909 sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber, 2910 sal_uInt16 nIx, 2911 String& OutString) 2912 { 2913 using namespace ::com::sun::star::i18n; 2914 sal_Bool bRes = sal_False; 2915 CalendarWrapper& rCal = GetCal(); 2916 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 2917 fNumber += fDiff; 2918 rCal.setLocalDateTime( fNumber ); 2919 String aOrgCalendar; // empty => not changed yet 2920 double fOrgDateTime; 2921 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 2922 if ( bOtherCalendar ) 2923 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 2924 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 2925 bOtherCalendar = sal_False; 2926 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2927 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2928 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 2929 for (sal_uInt16 i = 0; i < nAnz; i++) 2930 { 2931 switch (rInfo.nTypeArray[i]) 2932 { 2933 case NF_SYMBOLTYPE_CALENDAR : 2934 if ( !aOrgCalendar.Len() ) 2935 { 2936 aOrgCalendar = rCal.getUniqueID(); 2937 fOrgDateTime = rCal.getDateTime(); 2938 } 2939 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2940 rCal.setDateTime( fOrgDateTime ); 2941 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 2942 break; 2943 case NF_SYMBOLTYPE_STAR: 2944 if( bStarFlag ) 2945 { 2946 OutString += (sal_Unicode) 0x1B; 2947 OutString += rInfo.sStrArray[i].GetChar(1); 2948 bRes = sal_True; 2949 } 2950 break; 2951 case NF_SYMBOLTYPE_BLANK: 2952 InsertBlanks( OutString, OutString.Len(), 2953 rInfo.sStrArray[i].GetChar(1) ); 2954 break; 2955 case NF_SYMBOLTYPE_STRING: 2956 case NF_SYMBOLTYPE_CURRENCY: 2957 case NF_SYMBOLTYPE_DATESEP: 2958 case NF_SYMBOLTYPE_TIMESEP: 2959 case NF_SYMBOLTYPE_TIME100SECSEP: 2960 OutString += rInfo.sStrArray[i]; 2961 break; 2962 case NF_KEY_M: // M 2963 OutString += rCal.getDisplayString( 2964 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 2965 break; 2966 case NF_KEY_MM: // MM 2967 OutString += rCal.getDisplayString( 2968 CalendarDisplayCode::LONG_MONTH, nNatNum ); 2969 break; 2970 case NF_KEY_MMM: // MMM 2971 OutString += rCal.getDisplayString( 2972 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 2973 break; 2974 case NF_KEY_MMMM: // MMMM 2975 OutString += rCal.getDisplayString( 2976 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 2977 break; 2978 case NF_KEY_MMMMM: // MMMMM 2979 OutString += rCal.getDisplayString( 2980 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 2981 break; 2982 case NF_KEY_Q: // Q 2983 OutString += rCal.getDisplayString( 2984 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 2985 break; 2986 case NF_KEY_QQ: // QQ 2987 OutString += rCal.getDisplayString( 2988 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 2989 break; 2990 case NF_KEY_D: // D 2991 OutString += rCal.getDisplayString( 2992 CalendarDisplayCode::SHORT_DAY, nNatNum ); 2993 break; 2994 case NF_KEY_DD: // DD 2995 OutString += rCal.getDisplayString( 2996 CalendarDisplayCode::LONG_DAY, nNatNum ); 2997 break; 2998 case NF_KEY_DDD: // DDD 2999 { 3000 if ( bOtherCalendar ) 3001 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3002 OutString += rCal.getDisplayString( 3003 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3004 if ( bOtherCalendar ) 3005 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3006 } 3007 break; 3008 case NF_KEY_DDDD: // DDDD 3009 { 3010 if ( bOtherCalendar ) 3011 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3012 OutString += rCal.getDisplayString( 3013 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3014 if ( bOtherCalendar ) 3015 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3016 } 3017 break; 3018 case NF_KEY_YY: // YY 3019 { 3020 if ( bOtherCalendar ) 3021 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3022 OutString += rCal.getDisplayString( 3023 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3024 if ( bOtherCalendar ) 3025 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3026 } 3027 break; 3028 case NF_KEY_YYYY: // YYYY 3029 { 3030 if ( bOtherCalendar ) 3031 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3032 OutString += rCal.getDisplayString( 3033 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3034 if ( bOtherCalendar ) 3035 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3036 } 3037 break; 3038 case NF_KEY_EC: // E 3039 OutString += rCal.getDisplayString( 3040 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3041 break; 3042 case NF_KEY_EEC: // EE 3043 case NF_KEY_R: // R 3044 OutString += rCal.getDisplayString( 3045 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3046 break; 3047 case NF_KEY_NN: // NN 3048 case NF_KEY_AAA: // AAA 3049 OutString += rCal.getDisplayString( 3050 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3051 break; 3052 case NF_KEY_NNN: // NNN 3053 case NF_KEY_AAAA: // AAAA 3054 OutString += rCal.getDisplayString( 3055 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3056 break; 3057 case NF_KEY_NNNN: // NNNN 3058 { 3059 OutString += rCal.getDisplayString( 3060 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3061 OutString += rLoc().getLongDateDayOfWeekSep(); 3062 } 3063 break; 3064 case NF_KEY_WW : // WW 3065 { 3066 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3067 OutString += ImpIntToString( nIx, nVal ); 3068 } 3069 break; 3070 case NF_KEY_G: // G 3071 ImpAppendEraG( OutString, rCal, nNatNum ); 3072 break; 3073 case NF_KEY_GG: // GG 3074 OutString += rCal.getDisplayString( 3075 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3076 break; 3077 case NF_KEY_GGG: // GGG 3078 OutString += rCal.getDisplayString( 3079 CalendarDisplayCode::LONG_ERA, nNatNum ); 3080 break; 3081 case NF_KEY_RR: // RR => GGGEE 3082 OutString += rCal.getDisplayString( 3083 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3084 break; 3085 } 3086 } 3087 if ( aOrgCalendar.Len() ) 3088 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3089 return bRes; 3090 } 3091 3092 sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, 3093 sal_uInt16 nIx, 3094 String& OutString) 3095 { 3096 using namespace ::com::sun::star::i18n; 3097 sal_Bool bRes = sal_False; 3098 3099 CalendarWrapper& rCal = GetCal(); 3100 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 3101 fNumber += fDiff; 3102 3103 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3104 sal_Bool bInputLine; 3105 xub_StrLen nCntPost; 3106 if ( rScan.GetStandardPrec() == 300 && 3107 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 3108 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 3109 bInputLine = sal_True; 3110 nCntPost = 7; 3111 } 3112 else 3113 { 3114 bInputLine = sal_False; 3115 nCntPost = xub_StrLen(rInfo.nCntPost); 3116 } 3117 double fTime = (fNumber - floor( fNumber )) * 86400.0; 3118 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 3119 if (fTime >= 86400.0) 3120 { 3121 // result of fNumber==x.999999999... rounded up, use correct date/time 3122 fTime -= 86400.0; 3123 fNumber = floor( fNumber + 0.5) + fTime; 3124 } 3125 rCal.setLocalDateTime( fNumber ); 3126 3127 String aOrgCalendar; // empty => not changed yet 3128 double fOrgDateTime; 3129 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 3130 if ( bOtherCalendar ) 3131 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3132 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 3133 bOtherCalendar = sal_False; 3134 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 3135 3136 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 3137 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 3138 rtl_math_StringFormat_F, int(nCntPost), '.')); 3139 sSecStr.EraseLeadingChars('0'); 3140 sSecStr.EraseLeadingChars('.'); 3141 if ( bInputLine ) 3142 { 3143 sSecStr.EraseTrailingChars('0'); 3144 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 3145 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 3146 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3147 nCntPost = sSecStr.Len(); 3148 } 3149 else 3150 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3151 3152 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 3153 // abarbeiten 3154 sal_uLong nHour, nMin, nSec; 3155 if (!rInfo.bThousand) // [] Format 3156 { 3157 nHour = (nSeconds/3600) % 24; 3158 nMin = (nSeconds%3600) / 60; 3159 nSec = nSeconds%60; 3160 } 3161 else if (rInfo.nThousand == 3) // [ss] 3162 { 3163 nHour = 0; 3164 nMin = 0; 3165 nSec = nSeconds; 3166 } 3167 else if (rInfo.nThousand == 2) // [mm]:ss 3168 { 3169 nHour = 0; 3170 nMin = nSeconds / 60; 3171 nSec = nSeconds % 60; 3172 } 3173 else if (rInfo.nThousand == 1) // [hh]:mm:ss 3174 { 3175 nHour = nSeconds / 3600; 3176 nMin = (nSeconds%3600) / 60; 3177 nSec = nSeconds%60; 3178 } 3179 else { 3180 nHour = 0; // TODO What should these values be? 3181 nMin = 0; 3182 nSec = 0; 3183 } 3184 sal_Unicode cAmPm = ' '; // a oder p 3185 if (rInfo.nCntExp) // AM/PM 3186 { 3187 if (nHour == 0) 3188 { 3189 nHour = 12; 3190 cAmPm = 'a'; 3191 } 3192 else if (nHour < 12) 3193 cAmPm = 'a'; 3194 else 3195 { 3196 cAmPm = 'p'; 3197 if (nHour > 12) 3198 nHour -= 12; 3199 } 3200 } 3201 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 3202 for (sal_uInt16 i = 0; i < nAnz; i++) 3203 { 3204 switch (rInfo.nTypeArray[i]) 3205 { 3206 case NF_SYMBOLTYPE_CALENDAR : 3207 if ( !aOrgCalendar.Len() ) 3208 { 3209 aOrgCalendar = rCal.getUniqueID(); 3210 fOrgDateTime = rCal.getDateTime(); 3211 } 3212 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 3213 rCal.setDateTime( fOrgDateTime ); 3214 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3215 break; 3216 case NF_SYMBOLTYPE_STAR: 3217 if( bStarFlag ) 3218 { 3219 OutString += (sal_Unicode) 0x1B; 3220 OutString += rInfo.sStrArray[i].GetChar(1); 3221 bRes = sal_True; 3222 } 3223 break; 3224 case NF_SYMBOLTYPE_BLANK: 3225 InsertBlanks( OutString, OutString.Len(), 3226 rInfo.sStrArray[i].GetChar(1) ); 3227 break; 3228 case NF_SYMBOLTYPE_STRING: 3229 case NF_SYMBOLTYPE_CURRENCY: 3230 case NF_SYMBOLTYPE_DATESEP: 3231 case NF_SYMBOLTYPE_TIMESEP: 3232 case NF_SYMBOLTYPE_TIME100SECSEP: 3233 OutString += rInfo.sStrArray[i]; 3234 break; 3235 case NF_SYMBOLTYPE_DIGIT: 3236 { 3237 xub_StrLen nLen = ( bInputLine && i > 0 && 3238 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 3239 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 3240 nCntPost : rInfo.sStrArray[i].Len() ); 3241 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 3242 { 3243 OutString += sSecStr.GetChar(nSecPos); 3244 nSecPos++; 3245 } 3246 } 3247 break; 3248 case NF_KEY_AMPM: // AM/PM 3249 { 3250 if (cAmPm == 'a') 3251 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3252 AmPmValue::AM, 0 ); 3253 else 3254 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3255 AmPmValue::PM, 0 ); 3256 } 3257 break; 3258 case NF_KEY_AP: // A/P 3259 { 3260 if (cAmPm == 'a') 3261 OutString += 'a'; 3262 else 3263 OutString += 'p'; 3264 } 3265 break; 3266 case NF_KEY_MI: // M 3267 OutString += ImpIntToString( nIx, nMin ); 3268 break; 3269 case NF_KEY_MMI: // MM 3270 OutString += ImpIntToString( nIx, nMin, 2 ); 3271 break; 3272 case NF_KEY_H: // H 3273 OutString += ImpIntToString( nIx, nHour ); 3274 break; 3275 case NF_KEY_HH: // HH 3276 OutString += ImpIntToString( nIx, nHour, 2 ); 3277 break; 3278 case NF_KEY_S: // S 3279 OutString += ImpIntToString( nIx, nSec ); 3280 break; 3281 case NF_KEY_SS: // SS 3282 OutString += ImpIntToString( nIx, nSec, 2 ); 3283 break; 3284 case NF_KEY_M: // M 3285 OutString += rCal.getDisplayString( 3286 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 3287 break; 3288 case NF_KEY_MM: // MM 3289 OutString += rCal.getDisplayString( 3290 CalendarDisplayCode::LONG_MONTH, nNatNum ); 3291 break; 3292 case NF_KEY_MMM: // MMM 3293 OutString += rCal.getDisplayString( 3294 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 3295 break; 3296 case NF_KEY_MMMM: // MMMM 3297 OutString += rCal.getDisplayString( 3298 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 3299 break; 3300 case NF_KEY_MMMMM: // MMMMM 3301 OutString += rCal.getDisplayString( 3302 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 3303 break; 3304 case NF_KEY_Q: // Q 3305 OutString += rCal.getDisplayString( 3306 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 3307 break; 3308 case NF_KEY_QQ: // QQ 3309 OutString += rCal.getDisplayString( 3310 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 3311 break; 3312 case NF_KEY_D: // D 3313 OutString += rCal.getDisplayString( 3314 CalendarDisplayCode::SHORT_DAY, nNatNum ); 3315 break; 3316 case NF_KEY_DD: // DD 3317 OutString += rCal.getDisplayString( 3318 CalendarDisplayCode::LONG_DAY, nNatNum ); 3319 break; 3320 case NF_KEY_DDD: // DDD 3321 { 3322 if ( bOtherCalendar ) 3323 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3324 OutString += rCal.getDisplayString( 3325 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3326 if ( bOtherCalendar ) 3327 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3328 } 3329 break; 3330 case NF_KEY_DDDD: // DDDD 3331 { 3332 if ( bOtherCalendar ) 3333 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3334 OutString += rCal.getDisplayString( 3335 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3336 if ( bOtherCalendar ) 3337 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3338 } 3339 break; 3340 case NF_KEY_YY: // YY 3341 { 3342 if ( bOtherCalendar ) 3343 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3344 OutString += rCal.getDisplayString( 3345 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3346 if ( bOtherCalendar ) 3347 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3348 } 3349 break; 3350 case NF_KEY_YYYY: // YYYY 3351 { 3352 if ( bOtherCalendar ) 3353 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3354 OutString += rCal.getDisplayString( 3355 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3356 if ( bOtherCalendar ) 3357 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3358 } 3359 break; 3360 case NF_KEY_EC: // E 3361 OutString += rCal.getDisplayString( 3362 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3363 break; 3364 case NF_KEY_EEC: // EE 3365 case NF_KEY_R: // R 3366 OutString += rCal.getDisplayString( 3367 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3368 break; 3369 case NF_KEY_NN: // NN 3370 case NF_KEY_AAA: // AAA 3371 OutString += rCal.getDisplayString( 3372 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3373 break; 3374 case NF_KEY_NNN: // NNN 3375 case NF_KEY_AAAA: // AAAA 3376 OutString += rCal.getDisplayString( 3377 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3378 break; 3379 case NF_KEY_NNNN: // NNNN 3380 { 3381 OutString += rCal.getDisplayString( 3382 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3383 OutString += rLoc().getLongDateDayOfWeekSep(); 3384 } 3385 break; 3386 case NF_KEY_WW : // WW 3387 { 3388 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3389 OutString += ImpIntToString( nIx, nVal ); 3390 } 3391 break; 3392 case NF_KEY_G: // G 3393 ImpAppendEraG( OutString, rCal, nNatNum ); 3394 break; 3395 case NF_KEY_GG: // GG 3396 OutString += rCal.getDisplayString( 3397 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3398 break; 3399 case NF_KEY_GGG: // GGG 3400 OutString += rCal.getDisplayString( 3401 CalendarDisplayCode::LONG_ERA, nNatNum ); 3402 break; 3403 case NF_KEY_RR: // RR => GGGEE 3404 OutString += rCal.getDisplayString( 3405 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3406 break; 3407 } 3408 } 3409 if ( aOrgCalendar.Len() ) 3410 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3411 return bRes; 3412 } 3413 3414 sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber, 3415 sal_uInt16 nIx, 3416 String& OutString) 3417 { 3418 sal_Bool bRes = sal_False; 3419 sal_Bool bSign; 3420 if (fNumber < 0.0) 3421 { 3422 if (nIx == 0) // nicht in hinteren 3423 bSign = sal_True; // Formaten 3424 else 3425 bSign = sal_False; 3426 fNumber = -fNumber; 3427 } 3428 else 3429 { 3430 bSign = sal_False; 3431 if ( ::rtl::math::isSignBitSet( fNumber ) ) 3432 fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-' 3433 } 3434 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3435 if (rInfo.eScannedType == NUMBERFORMAT_PERCENT) 3436 { 3437 if (fNumber < _D_MAX_D_BY_100) 3438 fNumber *= 100.0; 3439 else 3440 { 3441 OutString = rScan.GetErrorString(); 3442 return sal_False; 3443 } 3444 } 3445 sal_uInt16 i, j; 3446 xub_StrLen k; 3447 String sStr; 3448 long nPrecExp; 3449 sal_Bool bInteger = sal_False; 3450 if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT ) 3451 { // special formatting only if no GENERAL keyword in format code 3452 const sal_uInt16 nThousand = rInfo.nThousand; 3453 for (i = 0; i < nThousand; i++) 3454 { 3455 if (fNumber > _D_MIN_M_BY_1000) 3456 fNumber /= 1000.0; 3457 else 3458 fNumber = 0.0; 3459 } 3460 if (fNumber > 0.0) 3461 nPrecExp = GetPrecExp( fNumber ); 3462 else 3463 nPrecExp = 0; 3464 if (rInfo.nCntPost) // NachkommaStellen 3465 { 3466 if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15) 3467 { 3468 sStr = ::rtl::math::doubleToUString( fNumber, 3469 rtl_math_StringFormat_F, 15-nPrecExp, '.'); 3470 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++) 3471 sStr += '0'; 3472 } 3473 else 3474 sStr = ::rtl::math::doubleToUString( fNumber, 3475 rtl_math_StringFormat_F, rInfo.nCntPost, '.' ); 3476 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3477 } 3478 else if (fNumber == 0.0) // Null 3479 { 3480 // nothing to be done here, keep empty string sStr, 3481 // ImpNumberFillWithThousands does the rest 3482 } 3483 else // Integer 3484 { 3485 sStr = ::rtl::math::doubleToUString( fNumber, 3486 rtl_math_StringFormat_F, 0, '.'); 3487 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3488 } 3489 xub_StrLen nPoint = sStr.Search( '.' ); 3490 if ( nPoint != STRING_NOTFOUND ) 3491 { 3492 register const sal_Unicode* p = sStr.GetBuffer() + nPoint; 3493 while ( *++p == '0' ) 3494 ; 3495 if ( !*p ) 3496 bInteger = sal_True; 3497 sStr.Erase( nPoint, 1 ); // . herausnehmen 3498 } 3499 if (bSign && 3500 (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000 3501 bSign = sal_False; // nicht -0.00 3502 } // End of != FLAG_STANDARD_IN_FORMAT 3503 3504 // von hinten nach vorn 3505 // editieren: 3506 k = sStr.Len(); // hinter letzter Ziffer 3507 j = NumFor[nIx].GetnAnz()-1; // letztes Symbol 3508 // Nachkommastellen: 3509 if (rInfo.nCntPost > 0) 3510 { 3511 sal_Bool bTrailing = sal_True; // ob Endnullen? 3512 sal_Bool bFilled = sal_False; // ob aufgefuellt wurde ? 3513 short nType; 3514 while (j > 0 && // rueckwaerts 3515 (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP) 3516 { 3517 switch ( nType ) 3518 { 3519 case NF_SYMBOLTYPE_STAR: 3520 if( bStarFlag ) 3521 { 3522 sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ ); 3523 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3524 bRes = sal_True; 3525 } 3526 break; 3527 case NF_SYMBOLTYPE_BLANK: 3528 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3529 break; 3530 case NF_SYMBOLTYPE_STRING: 3531 case NF_SYMBOLTYPE_CURRENCY: 3532 case NF_SYMBOLTYPE_PERCENT: 3533 sStr.Insert(rInfo.sStrArray[j],k); 3534 break; 3535 case NF_SYMBOLTYPE_THSEP: 3536 if (rInfo.nThousand == 0) 3537 sStr.Insert(rInfo.sStrArray[j],k); 3538 break; 3539 case NF_SYMBOLTYPE_DIGIT: 3540 { 3541 const String& rStr = rInfo.sStrArray[j]; 3542 const sal_Unicode* p1 = rStr.GetBuffer(); 3543 register const sal_Unicode* p = p1 + rStr.Len(); 3544 while ( p1 < p-- ) 3545 { 3546 const sal_Unicode c = *p; 3547 k--; 3548 if ( sStr.GetChar(k) != '0' ) 3549 bTrailing = sal_False; 3550 if (bTrailing) 3551 { 3552 if ( c == '0' ) 3553 bFilled = sal_True; 3554 else if ( c == '-' ) 3555 { 3556 if ( bInteger ) 3557 sStr.SetChar( k, '-' ); 3558 bFilled = sal_True; 3559 } 3560 else if ( c == '?' ) 3561 { 3562 sStr.SetChar( k, ' ' ); 3563 bFilled = sal_True; 3564 } 3565 else if ( !bFilled ) // # 3566 sStr.Erase(k,1); 3567 } 3568 } // of for 3569 } // of case digi 3570 break; 3571 case NF_KEY_CCC: // CCC-Waehrung 3572 sStr.Insert(rScan.GetCurAbbrev(), k); 3573 break; 3574 case NF_KEY_GENERAL: // Standard im String 3575 { 3576 String sNum; 3577 ImpGetOutputStandard(fNumber, sNum); 3578 sNum.EraseLeadingChars('-'); 3579 sStr.Insert(sNum, k); 3580 } 3581 break; 3582 default: 3583 break; 3584 } // of switch 3585 j--; 3586 } // of while 3587 } // of Nachkomma 3588 3589 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit . 3590 rInfo.nCntPre); 3591 if ( rInfo.nCntPost > 0 ) 3592 { 3593 const String& rDecSep = GetFormatter().GetNumDecimalSep(); 3594 xub_StrLen nLen = rDecSep.Len(); 3595 if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) ) 3596 sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep 3597 } 3598 if (bSign) 3599 sStr.Insert('-',0); 3600 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 3601 OutString = sStr; 3602 return bRes; 3603 } 3604 3605 sal_Bool SvNumberformat::ImpNumberFillWithThousands( 3606 String& sStr, // number string 3607 double& rNumber, // number 3608 xub_StrLen k, // position within string 3609 sal_uInt16 j, // symbol index within format code 3610 sal_uInt16 nIx, // subformat index 3611 sal_uInt16 nDigCnt) // count of integer digits in format 3612 { 3613 sal_Bool bRes = sal_False; 3614 xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number 3615 xub_StrLen nDigitCount = 0; // count of integer digits from the right 3616 sal_Bool bStop = sal_False; 3617 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3618 // no normal thousands separators if number divided by thousands 3619 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3620 utl::DigitGroupingIterator aGrouping( 3621 GetFormatter().GetLocaleData()->getDigitGrouping()); 3622 while (!bStop) // backwards 3623 { 3624 if (j == 0) 3625 bStop = sal_True; 3626 switch (rInfo.nTypeArray[j]) 3627 { 3628 case NF_SYMBOLTYPE_DECSEP: 3629 aGrouping.reset(); 3630 // fall thru 3631 case NF_SYMBOLTYPE_STRING: 3632 case NF_SYMBOLTYPE_CURRENCY: 3633 case NF_SYMBOLTYPE_PERCENT: 3634 sStr.Insert(rInfo.sStrArray[j],k); 3635 if ( k == 0 ) 3636 nLeadingStringChars = 3637 nLeadingStringChars + rInfo.sStrArray[j].Len(); 3638 break; 3639 case NF_SYMBOLTYPE_STAR: 3640 if( bStarFlag ) 3641 { 3642 sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ ); 3643 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3644 bRes = sal_True; 3645 } 3646 break; 3647 case NF_SYMBOLTYPE_BLANK: 3648 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3649 break; 3650 case NF_SYMBOLTYPE_THSEP: 3651 { 3652 // #i7284# #102685# Insert separator also if number is divided 3653 // by thousands and the separator is specified somewhere in 3654 // between and not only at the end. 3655 // #i12596# But do not insert if it's a parenthesized negative 3656 // format like (#,) 3657 // In fact, do not insert if divided and regex [0#,],[^0#] and 3658 // no other digit symbol follows (which was already detected 3659 // during scan of format code, otherwise there would be no 3660 // division), else do insert. Same in ImpNumberFill() below. 3661 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3662 bDoThousands = ((j == 0) || 3663 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3664 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3665 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3666 if ( bDoThousands ) 3667 { 3668 if (k > 0) 3669 sStr.Insert(rInfo.sStrArray[j],k); 3670 else if (nDigitCount < nDigCnt) 3671 { 3672 // Leading '#' displays nothing (e.g. no leading 3673 // separator for numbers <1000 with #,##0 format). 3674 // Leading '?' displays blank. 3675 // Everything else, including nothing, displays the 3676 // separator. 3677 sal_Unicode cLeader = 0; 3678 if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT) 3679 { 3680 const String& rStr = rInfo.sStrArray[j-1]; 3681 xub_StrLen nLen = rStr.Len(); 3682 if (nLen) 3683 cLeader = rStr.GetChar(nLen-1); 3684 } 3685 switch (cLeader) 3686 { 3687 case '#': 3688 ; // nothing 3689 break; 3690 case '?': 3691 // erAck: 2008-04-03T16:24+0200 3692 // Actually this currently isn't executed 3693 // because the format scanner in the context of 3694 // "?," doesn't generate a group separator but 3695 // a literal ',' character instead that is 3696 // inserted unconditionally. Should be changed 3697 // on some occasion. 3698 sStr.Insert(' ',k); 3699 break; 3700 default: 3701 sStr.Insert(rInfo.sStrArray[j],k); 3702 } 3703 } 3704 aGrouping.advance(); 3705 } 3706 } 3707 break; 3708 case NF_SYMBOLTYPE_DIGIT: 3709 { 3710 const String& rStr = rInfo.sStrArray[j]; 3711 const sal_Unicode* p1 = rStr.GetBuffer(); 3712 register const sal_Unicode* p = p1 + rStr.Len(); 3713 while ( p1 < p-- ) 3714 { 3715 nDigitCount++; 3716 if (k > 0) 3717 k--; 3718 else 3719 { 3720 switch (*p) 3721 { 3722 case '0': 3723 sStr.Insert('0',0); 3724 break; 3725 case '?': 3726 sStr.Insert(' ',0); 3727 break; 3728 } 3729 } 3730 if (nDigitCount == nDigCnt && k > 0) 3731 { // more digits than specified 3732 ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping); 3733 } 3734 } 3735 } 3736 break; 3737 case NF_KEY_CCC: // CCC currency 3738 sStr.Insert(rScan.GetCurAbbrev(), k); 3739 break; 3740 case NF_KEY_GENERAL: // "General" in string 3741 { 3742 String sNum; 3743 ImpGetOutputStandard(rNumber, sNum); 3744 sNum.EraseLeadingChars('-'); 3745 sStr.Insert(sNum, k); 3746 } 3747 break; 3748 3749 default: 3750 break; 3751 } // switch 3752 j--; // next format code string 3753 } // while 3754 k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ... 3755 if (k > nLeadingStringChars) 3756 ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping); 3757 return bRes; 3758 } 3759 3760 void SvNumberformat::ImpDigitFill( 3761 String& sStr, // number string 3762 xub_StrLen nStart, // start of digits 3763 xub_StrLen& k, // position within string 3764 sal_uInt16 nIx, // subformat index 3765 xub_StrLen & nDigitCount, // count of integer digits from the right so far 3766 utl::DigitGroupingIterator & rGrouping ) // current grouping 3767 { 3768 if (NumFor[nIx].Info().bThousand) // only if grouping 3769 { // fill in separators 3770 const String& rThousandSep = GetFormatter().GetNumThousandSep(); 3771 while (k > nStart) 3772 { 3773 if (nDigitCount == rGrouping.getPos()) 3774 { 3775 sStr.Insert( rThousandSep, k ); 3776 rGrouping.advance(); 3777 } 3778 nDigitCount++; 3779 k--; 3780 } 3781 } 3782 else // simply skip 3783 k = nStart; 3784 } 3785 3786 sal_Bool SvNumberformat::ImpNumberFill( String& sStr, // number string 3787 double& rNumber, // number for "General" format 3788 xub_StrLen& k, // position within string 3789 sal_uInt16& j, // symbol index within format code 3790 sal_uInt16 nIx, // subformat index 3791 short eSymbolType ) // type of stop condition 3792 { 3793 sal_Bool bRes = sal_False; 3794 k = sStr.Len(); // behind last digit 3795 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3796 // no normal thousands separators if number divided by thousands 3797 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3798 short nType; 3799 while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType ) 3800 { // rueckwaerts: 3801 switch ( nType ) 3802 { 3803 case NF_SYMBOLTYPE_STAR: 3804 if( bStarFlag ) 3805 { 3806 sStr.Insert( sal_Unicode(0x1B), k++ ); 3807 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3808 bRes = sal_True; 3809 } 3810 break; 3811 case NF_SYMBOLTYPE_BLANK: 3812 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3813 break; 3814 case NF_SYMBOLTYPE_THSEP: 3815 { 3816 // Same as in ImpNumberFillWithThousands() above, do not insert 3817 // if divided and regex [0#,],[^0#] and no other digit symbol 3818 // follows (which was already detected during scan of format 3819 // code, otherwise there would be no division), else do insert. 3820 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3821 bDoThousands = ((j == 0) || 3822 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3823 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3824 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3825 if ( bDoThousands && k > 0 ) 3826 { 3827 sStr.Insert(rInfo.sStrArray[j],k); 3828 } 3829 } 3830 break; 3831 case NF_SYMBOLTYPE_DIGIT: 3832 { 3833 const String& rStr = rInfo.sStrArray[j]; 3834 const sal_Unicode* p1 = rStr.GetBuffer(); 3835 register const sal_Unicode* p = p1 + rStr.Len(); 3836 while ( p1 < p-- ) 3837 { 3838 if (k > 0) 3839 k--; 3840 else 3841 { 3842 switch (*p) 3843 { 3844 case '0': 3845 sStr.Insert('0',0); 3846 break; 3847 case '?': 3848 sStr.Insert(' ',0); 3849 break; 3850 } 3851 } 3852 } 3853 } 3854 break; 3855 case NF_KEY_CCC: // CCC-Waehrung 3856 sStr.Insert(rScan.GetCurAbbrev(), k); 3857 break; 3858 case NF_KEY_GENERAL: // Standard im String 3859 { 3860 String sNum; 3861 ImpGetOutputStandard(rNumber, sNum); 3862 sNum.EraseLeadingChars('-'); // Vorzeichen weg!! 3863 sStr.Insert(sNum, k); 3864 } 3865 break; 3866 3867 default: 3868 sStr.Insert(rInfo.sStrArray[j],k); 3869 break; 3870 } // of switch 3871 j--; // naechster String 3872 } // of while 3873 return bRes; 3874 } 3875 3876 void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand, 3877 sal_Bool& IsRed, 3878 sal_uInt16& nPrecision, 3879 sal_uInt16& nAnzLeading) const 3880 { 3881 // as before: take info from nNumFor=0 for whole format (for dialog etc.) 3882 3883 short nDummyType; 3884 GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading ); 3885 3886 // "negative in red" is only useful for the whole format 3887 3888 const Color* pColor = NumFor[1].GetColor(); 3889 if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor 3890 && (*pColor == rScan.GetRedColor())) 3891 IsRed = sal_True; 3892 else 3893 IsRed = sal_False; 3894 } 3895 3896 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType, 3897 sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const 3898 { 3899 // take info from a specified sub-format (for XML export) 3900 3901 if ( nNumFor > 3 ) 3902 return; // invalid 3903 3904 const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); 3905 rScannedType = rInfo.eScannedType; 3906 bThousand = rInfo.bThousand; 3907 nPrecision = rInfo.nCntPost; 3908 if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER) 3909 // StandardFormat 3910 nAnzLeading = 1; 3911 else 3912 { 3913 nAnzLeading = 0; 3914 sal_Bool bStop = sal_False; 3915 sal_uInt16 i = 0; 3916 const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3917 while (!bStop && i < nAnz) 3918 { 3919 short nType = rInfo.nTypeArray[i]; 3920 if ( nType == NF_SYMBOLTYPE_DIGIT) 3921 { 3922 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer(); 3923 while ( *p == '#' ) 3924 p++; 3925 while ( *p++ == '0' ) 3926 nAnzLeading++; 3927 } 3928 else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP) 3929 bStop = sal_True; 3930 i++; 3931 } 3932 } 3933 } 3934 3935 const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, 3936 sal_Bool bString /* = sal_False */ ) const 3937 { 3938 if ( nNumFor > 3 ) 3939 return NULL; 3940 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3941 if ( !nAnz ) 3942 return NULL; 3943 if ( nPos == 0xFFFF ) 3944 { 3945 nPos = nAnz - 1; 3946 if ( bString ) 3947 { // rueckwaerts 3948 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3949 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 3950 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3951 { 3952 pType--; 3953 nPos--; 3954 } 3955 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3956 return NULL; 3957 } 3958 } 3959 else if ( nPos > nAnz - 1 ) 3960 return NULL; 3961 else if ( bString ) 3962 { // vorwaerts 3963 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3964 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 3965 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3966 { 3967 pType++; 3968 nPos++; 3969 } 3970 if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) && 3971 (*pType != NF_SYMBOLTYPE_CURRENCY)) ) 3972 return NULL; 3973 } 3974 return &NumFor[nNumFor].Info().sStrArray[nPos]; 3975 } 3976 3977 3978 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos, 3979 sal_Bool bString /* = sal_False */ ) const 3980 { 3981 if ( nNumFor > 3 ) 3982 return 0; 3983 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3984 if ( !nAnz ) 3985 return 0; 3986 if ( nPos == 0xFFFF ) 3987 { 3988 nPos = nAnz - 1; 3989 if ( bString ) 3990 { // rueckwaerts 3991 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3992 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 3993 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3994 { 3995 pType--; 3996 nPos--; 3997 } 3998 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3999 return 0; 4000 } 4001 } 4002 else if ( nPos > nAnz - 1 ) 4003 return 0; 4004 else if ( bString ) 4005 { // vorwaerts 4006 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 4007 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 4008 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4009 { 4010 pType++; 4011 nPos++; 4012 } 4013 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4014 return 0; 4015 } 4016 return NumFor[nNumFor].Info().nTypeArray[nPos]; 4017 } 4018 4019 4020 sal_Bool SvNumberformat::IsNegativeWithoutSign() const 4021 { 4022 if ( IsNegativeRealNegative() ) 4023 { 4024 const String* pStr = GetNumForString( 1, 0, sal_True ); 4025 if ( pStr ) 4026 return !HasStringNegativeSign( *pStr ); 4027 } 4028 return sal_False; 4029 } 4030 4031 4032 DateFormat SvNumberformat::GetDateOrder() const 4033 { 4034 if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE ) 4035 { 4036 short const * const pType = NumFor[0].Info().nTypeArray; 4037 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4038 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4039 { 4040 switch ( pType[j] ) 4041 { 4042 case NF_KEY_D : 4043 case NF_KEY_DD : 4044 return DMY; 4045 case NF_KEY_M : 4046 case NF_KEY_MM : 4047 case NF_KEY_MMM : 4048 case NF_KEY_MMMM : 4049 case NF_KEY_MMMMM : 4050 return MDY; 4051 case NF_KEY_YY : 4052 case NF_KEY_YYYY : 4053 case NF_KEY_EC : 4054 case NF_KEY_EEC : 4055 case NF_KEY_R : 4056 case NF_KEY_RR : 4057 return YMD; 4058 } 4059 } 4060 } 4061 else 4062 { 4063 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" ); 4064 } 4065 return rLoc().getDateFormat(); 4066 } 4067 4068 4069 sal_uInt32 SvNumberformat::GetExactDateOrder() const 4070 { 4071 sal_uInt32 nRet = 0; 4072 if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE ) 4073 { 4074 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" ); 4075 return nRet; 4076 } 4077 short const * const pType = NumFor[0].Info().nTypeArray; 4078 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4079 int nShift = 0; 4080 for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ ) 4081 { 4082 switch ( pType[j] ) 4083 { 4084 case NF_KEY_D : 4085 case NF_KEY_DD : 4086 nRet = (nRet << 8) | 'D'; 4087 ++nShift; 4088 break; 4089 case NF_KEY_M : 4090 case NF_KEY_MM : 4091 case NF_KEY_MMM : 4092 case NF_KEY_MMMM : 4093 case NF_KEY_MMMMM : 4094 nRet = (nRet << 8) | 'M'; 4095 ++nShift; 4096 break; 4097 case NF_KEY_YY : 4098 case NF_KEY_YYYY : 4099 case NF_KEY_EC : 4100 case NF_KEY_EEC : 4101 case NF_KEY_R : 4102 case NF_KEY_RR : 4103 nRet = (nRet << 8) | 'Y'; 4104 ++nShift; 4105 break; 4106 } 4107 } 4108 return nRet; 4109 } 4110 4111 4112 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1, 4113 SvNumberformatLimitOps& rOper2, double& rVal2 ) const 4114 { 4115 rOper1 = eOp1; 4116 rOper2 = eOp2; 4117 rVal1 = fLimit1; 4118 rVal2 = fLimit2; 4119 } 4120 4121 4122 Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const 4123 { 4124 if ( nNumFor > 3 ) 4125 return NULL; 4126 4127 return NumFor[nNumFor].GetColor(); 4128 } 4129 4130 4131 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr, 4132 SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep ) 4133 { 4134 if ( eOp != NUMBERFORMAT_OP_NO ) 4135 { 4136 switch ( eOp ) 4137 { 4138 case NUMBERFORMAT_OP_EQ : 4139 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) ); 4140 break; 4141 case NUMBERFORMAT_OP_NE : 4142 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) ); 4143 break; 4144 case NUMBERFORMAT_OP_LT : 4145 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) ); 4146 break; 4147 case NUMBERFORMAT_OP_LE : 4148 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) ); 4149 break; 4150 case NUMBERFORMAT_OP_GT : 4151 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) ); 4152 break; 4153 case NUMBERFORMAT_OP_GE : 4154 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) ); 4155 break; 4156 default: 4157 OSL_ASSERT( "unsupported number format" ); 4158 break; 4159 } 4160 rStr += String( ::rtl::math::doubleToUString( fLimit, 4161 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 4162 rDecSep.GetChar(0), sal_True)); 4163 rStr += ']'; 4164 } 4165 } 4166 4167 4168 String SvNumberformat::GetMappedFormatstring( 4169 const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp, 4170 sal_Bool bDontQuote ) const 4171 { 4172 String aStr; 4173 sal_Bool bDefault[4]; 4174 // 1 subformat matches all if no condition specified, 4175 bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO ); 4176 // with 2 subformats [>=0];[<0] is implied if no condition specified 4177 bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 && 4178 eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 && 4179 eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 ); 4180 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified, 4181 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked. 4182 bDefault[2] = ( !bDefault[0] && !bDefault[1] && 4183 eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 && 4184 eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 ); 4185 sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2]; 4186 // from now on bDefault[] values are used to append empty subformats at the end 4187 bDefault[3] = sal_False; 4188 if ( !bDefaults ) 4189 { // conditions specified 4190 if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO ) 4191 bDefault[0] = bDefault[1] = sal_True; // [];x 4192 else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO && 4193 NumFor[2].GetnAnz() == 0 ) 4194 bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True; // [];[];; 4195 // nothing to do if conditions specified for every subformat 4196 } 4197 else if ( bDefault[0] ) 4198 bDefault[0] = sal_False; // a single unconditional subformat is never delimited 4199 else 4200 { 4201 if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 ) 4202 bDefault[3] = sal_True; // special cases x;x;; and ;x;; 4203 for ( int i=0; i<3 && !bDefault[i]; ++i ) 4204 bDefault[i] = sal_True; 4205 } 4206 int nSem = 0; // needed ';' delimiters 4207 int nSub = 0; // subformats delimited so far 4208 for ( int n=0; n<4; n++ ) 4209 { 4210 if ( n > 0 ) 4211 nSem++; 4212 4213 String aPrefix; 4214 4215 if ( !bDefaults ) 4216 { 4217 switch ( n ) 4218 { 4219 case 0 : 4220 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1, 4221 fLimit1, rLocWrp.getNumDecimalSep() ); 4222 break; 4223 case 1 : 4224 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2, 4225 fLimit2, rLocWrp.getNumDecimalSep() ); 4226 break; 4227 } 4228 } 4229 4230 const String& rColorName = NumFor[n].GetColorName(); 4231 if ( rColorName.Len() ) 4232 { 4233 const NfKeywordTable & rKey = rScan.GetKeywords(); 4234 for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ ) 4235 { 4236 if ( rKey[j] == rColorName ) 4237 { 4238 aPrefix += '['; 4239 aPrefix += rKeywords[j]; 4240 aPrefix += ']'; 4241 break; // for 4242 } 4243 } 4244 } 4245 4246 const SvNumberNatNum& rNum = NumFor[n].GetNatNum(); 4247 // The Thai T NatNum modifier during Xcl export. 4248 if (rNum.IsSet() && rNum.GetNatNum() == 1 && 4249 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") && 4250 MsLangId::getRealLanguage( rNum.GetLang()) == 4251 LANGUAGE_THAI) 4252 { 4253 aPrefix += 't'; // must be lowercase, otherwise taken as literal 4254 } 4255 4256 sal_uInt16 nAnz = NumFor[n].GetnAnz(); 4257 if ( nSem && (nAnz || aPrefix.Len()) ) 4258 { 4259 for ( ; nSem; --nSem ) 4260 aStr += ';'; 4261 for ( ; nSub <= n; ++nSub ) 4262 bDefault[nSub] = sal_False; 4263 } 4264 4265 if ( aPrefix.Len() ) 4266 aStr += aPrefix; 4267 4268 if ( nAnz ) 4269 { 4270 const short* pType = NumFor[n].Info().nTypeArray; 4271 const String* pStr = NumFor[n].Info().sStrArray; 4272 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4273 { 4274 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT ) 4275 { 4276 aStr += rKeywords[pType[j]]; 4277 if( NF_KEY_NNNN == pType[j] ) 4278 aStr += rLocWrp.getLongDateDayOfWeekSep(); 4279 } 4280 else 4281 { 4282 switch ( pType[j] ) 4283 { 4284 case NF_SYMBOLTYPE_DECSEP : 4285 aStr += rLocWrp.getNumDecimalSep(); 4286 break; 4287 case NF_SYMBOLTYPE_THSEP : 4288 aStr += rLocWrp.getNumThousandSep(); 4289 break; 4290 case NF_SYMBOLTYPE_DATESEP : 4291 aStr += rLocWrp.getDateSep(); 4292 break; 4293 case NF_SYMBOLTYPE_TIMESEP : 4294 aStr += rLocWrp.getTimeSep(); 4295 break; 4296 case NF_SYMBOLTYPE_TIME100SECSEP : 4297 aStr += rLocWrp.getTime100SecSep(); 4298 break; 4299 case NF_SYMBOLTYPE_STRING : 4300 if( bDontQuote ) 4301 aStr += pStr[j]; 4302 else if ( pStr[j].Len() == 1 ) 4303 { 4304 aStr += '\\'; 4305 aStr += pStr[j]; 4306 } 4307 else 4308 { 4309 aStr += '"'; 4310 aStr += pStr[j]; 4311 aStr += '"'; 4312 } 4313 break; 4314 default: 4315 aStr += pStr[j]; 4316 } 4317 4318 } 4319 } 4320 } 4321 } 4322 for ( ; nSub<4 && bDefault[nSub]; ++nSub ) 4323 { // append empty subformats 4324 aStr += ';'; 4325 } 4326 return aStr; 4327 } 4328 4329 4330 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum, 4331 sal_Int32 nVal, sal_uInt16 nMinDigits ) const 4332 { 4333 String aStr; 4334 if ( nMinDigits ) 4335 { 4336 if ( nMinDigits == 2 ) 4337 { // speed up the most common case 4338 if ( 0 <= nVal && nVal < 10 ) 4339 { 4340 sal_Unicode* p = aStr.AllocBuffer( 2 ); 4341 *p++ = '0'; 4342 *p = sal_Unicode( '0' + nVal ); 4343 } 4344 else 4345 aStr = String::CreateFromInt32( nVal ); 4346 } 4347 else 4348 { 4349 String aValStr( String::CreateFromInt32( nVal ) ); 4350 if ( aValStr.Len() >= nMinDigits ) 4351 aStr = aValStr; 4352 else 4353 { 4354 aStr.Fill( nMinDigits - aValStr.Len(), '0' ); 4355 aStr += aValStr; 4356 } 4357 } 4358 } 4359 else 4360 aStr = String::CreateFromInt32( nVal ); 4361 ImpTransliterate( aStr, rNum ); 4362 return aStr; 4363 } 4364 4365 4366 void SvNumberformat::ImpTransliterateImpl( String& rStr, 4367 const SvNumberNatNum& rNum ) const 4368 { 4369 com::sun::star::lang::Locale aLocale( 4370 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4371 rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr, 4372 aLocale, rNum.GetNatNum() ); 4373 } 4374 4375 4376 void SvNumberformat::GetNatNumXml( 4377 com::sun::star::i18n::NativeNumberXmlAttributes& rAttr, 4378 sal_uInt16 nNumFor ) const 4379 { 4380 if ( nNumFor <= 3 ) 4381 { 4382 const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum(); 4383 if ( rNum.IsSet() ) 4384 { 4385 com::sun::star::lang::Locale aLocale( 4386 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4387 rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes( 4388 aLocale, rNum.GetNatNum() ); 4389 } 4390 else 4391 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4392 } 4393 else 4394 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4395 } 4396 4397 // static 4398 sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr ) 4399 { 4400 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored) 4401 xub_StrLen nLen = rStr.Len(); 4402 if ( !nLen ) 4403 return sal_False; 4404 const sal_Unicode* const pBeg = rStr.GetBuffer(); 4405 const sal_Unicode* const pEnd = pBeg + nLen; 4406 register const sal_Unicode* p = pBeg; 4407 do 4408 { // Anfang 4409 if ( *p == '-' ) 4410 return sal_True; 4411 } while ( *p == ' ' && ++p < pEnd ); 4412 p = pEnd - 1; 4413 do 4414 { // Ende 4415 if ( *p == '-' ) 4416 return sal_True; 4417 } while ( *p == ' ' && pBeg < --p ); 4418 return sal_False; 4419 } 4420 4421 4422 // static 4423 void SvNumberformat::SetComment( const String& rStr, String& rFormat, 4424 String& rComment ) 4425 { 4426 if ( rComment.Len() ) 4427 { // alten Kommentar aus Formatstring loeschen 4428 //! nicht per EraseComment, der Kommentar muss matchen 4429 String aTmp( '{' ); 4430 aTmp += ' '; 4431 aTmp += rComment; 4432 aTmp += ' '; 4433 aTmp += '}'; 4434 xub_StrLen nCom = 0; 4435 do 4436 { 4437 nCom = rFormat.Search( aTmp, nCom ); 4438 } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) ); 4439 if ( nCom != STRING_NOTFOUND ) 4440 rFormat.Erase( nCom ); 4441 } 4442 if ( rStr.Len() ) 4443 { // neuen Kommentar setzen 4444 rFormat += '{'; 4445 rFormat += ' '; 4446 rFormat += rStr; 4447 rFormat += ' '; 4448 rFormat += '}'; 4449 rComment = rStr; 4450 } 4451 } 4452 4453 4454 // static 4455 void SvNumberformat::EraseCommentBraces( String& rStr ) 4456 { 4457 xub_StrLen nLen = rStr.Len(); 4458 if ( nLen && rStr.GetChar(0) == '{' ) 4459 { 4460 rStr.Erase( 0, 1 ); 4461 --nLen; 4462 } 4463 if ( nLen && rStr.GetChar(0) == ' ' ) 4464 { 4465 rStr.Erase( 0, 1 ); 4466 --nLen; 4467 } 4468 if ( nLen && rStr.GetChar( nLen-1 ) == '}' ) 4469 rStr.Erase( --nLen, 1 ); 4470 if ( nLen && rStr.GetChar( nLen-1 ) == ' ' ) 4471 rStr.Erase( --nLen, 1 ); 4472 } 4473 4474 4475 // static 4476 void SvNumberformat::EraseComment( String& rStr ) 4477 { 4478 register const sal_Unicode* p = rStr.GetBuffer(); 4479 sal_Bool bInString = sal_False; 4480 sal_Bool bEscaped = sal_False; 4481 sal_Bool bFound = sal_False; 4482 xub_StrLen nPos = 0; 4483 while ( !bFound && *p ) 4484 { 4485 switch ( *p ) 4486 { 4487 case '\\' : 4488 bEscaped = !bEscaped; 4489 break; 4490 case '\"' : 4491 if ( !bEscaped ) 4492 bInString = !bInString; 4493 break; 4494 case '{' : 4495 if ( !bEscaped && !bInString ) 4496 { 4497 bFound = sal_True; 4498 nPos = sal::static_int_cast< xub_StrLen >( 4499 p - rStr.GetBuffer()); 4500 } 4501 break; 4502 } 4503 if ( bEscaped && *p != '\\' ) 4504 bEscaped = sal_False; 4505 ++p; 4506 } 4507 if ( bFound ) 4508 rStr.Erase( nPos ); 4509 } 4510 4511 4512 // static 4513 sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos, 4514 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4515 { 4516 xub_StrLen nLen = rStr.Len(); 4517 if ( nPos >= nLen ) 4518 return sal_False; 4519 register const sal_Unicode* p0 = rStr.GetBuffer(); 4520 register const sal_Unicode* p = p0; 4521 register const sal_Unicode* p1 = p0 + nPos; 4522 sal_Bool bQuoted = sal_False; 4523 while ( p <= p1 ) 4524 { 4525 if ( *p == cQuote ) 4526 { 4527 if ( p == p0 ) 4528 bQuoted = sal_True; 4529 else if ( bQuoted ) 4530 { 4531 if ( *(p-1) != cEscIn ) 4532 bQuoted = sal_False; 4533 } 4534 else 4535 { 4536 if ( *(p-1) != cEscOut ) 4537 bQuoted = sal_True; 4538 } 4539 } 4540 p++; 4541 } 4542 return bQuoted; 4543 } 4544 4545 4546 // static 4547 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos, 4548 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4549 { 4550 xub_StrLen nLen = rStr.Len(); 4551 if ( nPos >= nLen ) 4552 return STRING_NOTFOUND; 4553 if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) ) 4554 { 4555 if ( rStr.GetChar( nPos ) == cQuote ) 4556 return nPos; // schliessendes cQuote 4557 return STRING_NOTFOUND; 4558 } 4559 register const sal_Unicode* p0 = rStr.GetBuffer(); 4560 register const sal_Unicode* p = p0 + nPos; 4561 register const sal_Unicode* p1 = p0 + nLen; 4562 while ( p < p1 ) 4563 { 4564 if ( *p == cQuote && p > p0 && *(p-1) != cEscIn ) 4565 return sal::static_int_cast< xub_StrLen >(p - p0); 4566 p++; 4567 } 4568 return nLen; // String Ende 4569 } 4570 4571 4572 sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const 4573 { 4574 sal_uInt16 nCnt = 0; 4575 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 4576 short const * const pType = NumFor[nNumFor].Info().nTypeArray; 4577 for ( sal_uInt16 j=0; j<nAnz; ++j ) 4578 { 4579 switch ( pType[j] ) 4580 { 4581 case NF_SYMBOLTYPE_STRING: 4582 case NF_SYMBOLTYPE_CURRENCY: 4583 case NF_SYMBOLTYPE_DATESEP: 4584 case NF_SYMBOLTYPE_TIMESEP: 4585 case NF_SYMBOLTYPE_TIME100SECSEP: 4586 case NF_SYMBOLTYPE_PERCENT: 4587 ++nCnt; 4588 break; 4589 } 4590 } 4591 return nCnt; 4592 } 4593 4594