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