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 && fNumber < 0.0 && // negatives Format 2133 IsNegativeRealNegative() ) // ohne Vorzeichen 2134 fNumber = -fNumber; // Vorzeichen eliminieren 2135 *ppColor = NumFor[nIx].GetColor(); 2136 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2137 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2138 if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED) 2139 return sal_False; // leer => nichts 2140 else if (nAnz == 0) // sonst Standard-Format 2141 { 2142 ImpGetOutputStandard(fNumber, OutString); 2143 return sal_False; 2144 } 2145 switch (rInfo.eScannedType) 2146 { 2147 case NUMBERFORMAT_TEXT: 2148 case NUMBERFORMAT_DEFINED: 2149 { 2150 for (sal_uInt16 i = 0; i < nAnz; i++) 2151 { 2152 switch (rInfo.nTypeArray[i]) 2153 { 2154 case NF_SYMBOLTYPE_STAR: 2155 if( bStarFlag ) 2156 { 2157 OutString += (sal_Unicode) 0x1B; 2158 OutString += rInfo.sStrArray[i].GetChar(1); 2159 bRes = sal_True; 2160 } 2161 break; 2162 case NF_SYMBOLTYPE_BLANK: 2163 InsertBlanks( OutString, OutString.Len(), 2164 rInfo.sStrArray[i].GetChar(1) ); 2165 break; 2166 case NF_SYMBOLTYPE_STRING: 2167 case NF_SYMBOLTYPE_CURRENCY: 2168 OutString += rInfo.sStrArray[i]; 2169 break; 2170 case NF_SYMBOLTYPE_THSEP: 2171 if (rInfo.nThousand == 0) 2172 OutString += rInfo.sStrArray[i]; 2173 break; 2174 default: 2175 break; 2176 } 2177 } 2178 } 2179 break; 2180 case NUMBERFORMAT_DATE: 2181 bRes |= ImpGetDateOutput(fNumber, nIx, OutString); 2182 break; 2183 case NUMBERFORMAT_TIME: 2184 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString); 2185 break; 2186 case NUMBERFORMAT_DATETIME: 2187 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString); 2188 break; 2189 case NUMBERFORMAT_NUMBER: 2190 case NUMBERFORMAT_PERCENT: 2191 case NUMBERFORMAT_CURRENCY: 2192 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString); 2193 break; 2194 case NUMBERFORMAT_FRACTION: 2195 { 2196 String sStr, sFrac, sDiv; // Strings, Wert fuer 2197 sal_uLong nFrac, nDiv; // Vorkommaanteil 2198 // Zaehler und Nenner 2199 sal_Bool bSign = sal_False; 2200 if (fNumber < 0) 2201 { 2202 if (nIx == 0) // nicht in hinteren 2203 bSign = sal_True; // Formaten 2204 fNumber = -fNumber; 2205 } 2206 double fNum = floor(fNumber); // Vorkommateil 2207 fNumber -= fNum; // Nachkommateil 2208 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9) 2209 // zu gross 2210 { 2211 OutString = rScan.GetErrorString(); 2212 return sal_False; 2213 } 2214 if (rInfo.nCntExp == 0) 2215 { 2216 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0"); 2217 return sal_False; 2218 } 2219 sal_uLong nBasis = ((sal_uLong)floor( // 9, 99, 999 ,... 2220 pow(10.0,rInfo.nCntExp))) - 1; 2221 sal_uLong x0, y0, x1, y1; 2222 2223 if (rInfo.nCntExp <= _MAX_FRACTION_PREC) 2224 { 2225 sal_Bool bUpperHalf; 2226 if (fNumber > 0.5) 2227 { 2228 bUpperHalf = sal_True; 2229 fNumber -= (fNumber - 0.5) * 2.0; 2230 } 2231 else 2232 bUpperHalf = sal_False; 2233 // Einstieg in Farey-Serie 2234 // finden: 2235 x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9 2236 if (x0 == 0) // => x0 = 2 2237 { 2238 y0 = 1; 2239 x1 = 1; 2240 y1 = nBasis; 2241 } 2242 else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2 2243 { // geht (nBasis ungerade) 2244 y0 = nBasis; 2245 x1 = 1; 2246 y1 = 2; 2247 } 2248 else if (x0 == 1) 2249 { 2250 y0 = nBasis; // 1/n; 1/(n-1) 2251 x1 = 1; 2252 y1 = nBasis - 1; 2253 } 2254 else 2255 { 2256 y0 = nBasis; // z.B. 2/9 2/8 2257 x1 = x0; 2258 y1 = nBasis - 1; 2259 double fUg = (double) x0 / (double) y0; 2260 double fOg = (double) x1 / (double) y1; 2261 sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen 2262 x0 /= nGgt; 2263 y0 /= nGgt; // Einschachteln: 2264 sal_uLong x2 = 0; 2265 sal_uLong y2 = 0; 2266 sal_Bool bStop = sal_False; 2267 while (!bStop) 2268 { 2269 #ifdef GCC 2270 // #i21648# GCC over-optimizes something resulting 2271 // in wrong fTest values throughout the loops. 2272 volatile 2273 #endif 2274 double fTest = (double)x1/(double)y1; 2275 while (!bStop) 2276 { 2277 while (fTest > fOg) 2278 { 2279 x1--; 2280 fTest = (double)x1/(double)y1; 2281 } 2282 while (fTest < fUg && y1 > 1) 2283 { 2284 y1--; 2285 fTest = (double)x1/(double)y1; 2286 } 2287 if (fTest <= fOg) 2288 { 2289 fOg = fTest; 2290 bStop = sal_True; 2291 } 2292 else if (y1 == 1) 2293 bStop = sal_True; 2294 } // of while 2295 nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen 2296 x2 = x1 / nGgt; 2297 y2 = y1 / nGgt; 2298 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2 2299 bStop = sal_True; // naechste Farey-Zahl 2300 else 2301 { 2302 y1--; 2303 bStop = sal_False; 2304 } 2305 } // of while 2306 x1 = x2; 2307 y1 = y2; 2308 } // of else 2309 double fup, flow; 2310 flow = (double)x0/(double)y0; 2311 fup = (double)x1/(double)y1; 2312 while (fNumber > fup) 2313 { 2314 sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl 2315 sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0; 2316 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2); 2317 x0 = x1; 2318 y0 = y1; 2319 x1 = x2; 2320 y1 = y2; 2321 flow = fup; 2322 fup = (double)x1/(double)y1; 2323 } 2324 if (fNumber - flow < fup - fNumber) 2325 { 2326 nFrac = x0; 2327 nDiv = y0; 2328 } 2329 else 2330 { 2331 nFrac = x1; 2332 nDiv = y1; 2333 } 2334 if (bUpperHalf) // Original restaur. 2335 { 2336 if (nFrac == 0 && nDiv == 1) // 1/1 2337 fNum += 1.0; 2338 else 2339 nFrac = nDiv - nFrac; 2340 } 2341 } 2342 else // grosse Nenner 2343 { // 0,1234->123/1000 2344 sal_uLong nGgt; 2345 /* 2346 nDiv = nBasis+1; 2347 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2348 pow(10.0,rInfo.nCntExp))); 2349 */ 2350 nDiv = 10000000; 2351 nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0)); 2352 nGgt = ImpGGT(nDiv, nFrac); 2353 if (nGgt > 1) 2354 { 2355 nDiv /= nGgt; 2356 nFrac /= nGgt; 2357 } 2358 if (nDiv > nBasis) 2359 { 2360 nGgt = ImpGGTRound(nDiv, nFrac); 2361 if (nGgt > 1) 2362 { 2363 nDiv /= nGgt; 2364 nFrac /= nGgt; 2365 } 2366 } 2367 if (nDiv > nBasis) 2368 { 2369 nDiv = nBasis; 2370 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2371 pow(10.0,rInfo.nCntExp))); 2372 nGgt = ImpGGTRound(nDiv, nFrac); 2373 if (nGgt > 1) 2374 { 2375 nDiv /= nGgt; 2376 nFrac /= nGgt; 2377 } 2378 } 2379 } 2380 2381 if (rInfo.nCntPre == 0) // unechter Bruch 2382 { 2383 double fNum1 = fNum * (double)nDiv + (double)nFrac; 2384 if (fNum1 > _D_MAX_U_LONG_) 2385 { 2386 OutString = rScan.GetErrorString(); 2387 return sal_False; 2388 } 2389 nFrac = (sal_uLong) floor(fNum1); 2390 sStr.Erase(); 2391 } 2392 else if (fNum == 0.0 && nFrac != 0) 2393 sStr.Erase(); 2394 else 2395 { 2396 char aBuf[100]; 2397 sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked) 2398 sStr.AssignAscii( aBuf ); 2399 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 2400 } 2401 if (rInfo.nCntPre > 0 && nFrac == 0) 2402 { 2403 sFrac.Erase(); 2404 sDiv.Erase(); 2405 } 2406 else 2407 { 2408 sFrac = ImpIntToString( nIx, nFrac ); 2409 sDiv = ImpIntToString( nIx, nDiv ); 2410 } 2411 2412 sal_uInt16 j = nAnz-1; // letztes Symbol->rueckw. 2413 xub_StrLen k; // Nenner: 2414 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC); 2415 sal_Bool bCont = sal_True; 2416 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC) 2417 { 2418 if (rInfo.nCntPre > 0 && nFrac == 0) 2419 sDiv.Insert(' ',0); 2420 else 2421 sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 ); 2422 if ( j ) 2423 j--; 2424 else 2425 bCont = sal_False; 2426 } 2427 // weiter Zaehler: 2428 if ( !bCont ) 2429 sFrac.Erase(); 2430 else 2431 { 2432 bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK); 2433 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK) 2434 { 2435 sFrac.Insert(rInfo.sStrArray[j],0); 2436 if ( j ) 2437 j--; 2438 else 2439 bCont = sal_False; 2440 } 2441 } 2442 // weiter Hauptzahl 2443 if ( !bCont ) 2444 sStr.Erase(); 2445 else 2446 { 2447 k = sStr.Len(); // hinter letzter Ziffer 2448 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, 2449 rInfo.nCntPre); 2450 } 2451 if (bSign && !(nFrac == 0 && fNum == 0.0)) 2452 OutString.Insert('-',0); // nicht -0 2453 OutString += sStr; 2454 OutString += sFrac; 2455 OutString += sDiv; 2456 } 2457 break; 2458 case NUMBERFORMAT_SCIENTIFIC: 2459 { 2460 sal_Bool bSign = sal_False; 2461 if (fNumber < 0) 2462 { 2463 if (nIx == 0) // nicht in hinteren 2464 bSign = sal_True; // Formaten 2465 fNumber = -fNumber; 2466 } 2467 String sStr( ::rtl::math::doubleToUString( fNumber, 2468 rtl_math_StringFormat_E, 2469 rInfo.nCntPre + rInfo.nCntPost - 1, '.' )); 2470 2471 String ExpStr; 2472 short nExpSign = 1; 2473 xub_StrLen nExPos = sStr.Search('E'); 2474 if ( nExPos != STRING_NOTFOUND ) 2475 { 2476 // split into mantisse and exponent and get rid of "E+" or "E-" 2477 xub_StrLen nExpStart = nExPos + 1; 2478 switch ( sStr.GetChar( nExpStart ) ) 2479 { 2480 case '-' : 2481 nExpSign = -1; 2482 // fallthru 2483 case '+' : 2484 ++nExpStart; 2485 break; 2486 } 2487 ExpStr = sStr.Copy( nExpStart ); // part following the "E+" 2488 sStr.Erase( nExPos ); 2489 sStr.EraseAllChars('.'); // cut any decimal delimiter 2490 if ( rInfo.nCntPre != 1 ) // rescale Exp 2491 { 2492 sal_Int32 nExp = ExpStr.ToInt32() * nExpSign; 2493 nExp -= sal_Int32(rInfo.nCntPre)-1; 2494 if ( nExp < 0 ) 2495 { 2496 nExpSign = -1; 2497 nExp = -nExp; 2498 } 2499 else 2500 nExpSign = 1; 2501 ExpStr = String::CreateFromInt32( nExp ); 2502 } 2503 } 2504 sal_uInt16 j = nAnz-1; // last symbol 2505 xub_StrLen k; // position in ExpStr 2506 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP); 2507 2508 xub_StrLen nZeros = 0; // erase leading zeros 2509 while (nZeros < k && ExpStr.GetChar(nZeros) == '0') 2510 ++nZeros; 2511 if (nZeros) 2512 ExpStr.Erase( 0, nZeros); 2513 2514 sal_Bool bCont = sal_True; 2515 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP) 2516 { 2517 const String& rStr = rInfo.sStrArray[j]; 2518 if (nExpSign == -1) 2519 ExpStr.Insert('-',0); 2520 else if (rStr.Len() > 1 && rStr.GetChar(1) == '+') 2521 ExpStr.Insert('+',0); 2522 ExpStr.Insert(rStr.GetChar(0),0); 2523 if ( j ) 2524 j--; 2525 else 2526 bCont = sal_False; 2527 } 2528 // weiter Hauptzahl: 2529 if ( !bCont ) 2530 sStr.Erase(); 2531 else 2532 { 2533 k = sStr.Len(); // hinter letzter Ziffer 2534 bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx, 2535 rInfo.nCntPre + 2536 rInfo.nCntPost); 2537 } 2538 if (bSign) 2539 sStr.Insert('-',0); 2540 OutString = sStr; 2541 OutString += ExpStr; 2542 } 2543 break; 2544 } 2545 } 2546 return bRes; 2547 } 2548 2549 sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber, 2550 sal_uInt16 nIx, 2551 String& OutString) 2552 { 2553 using namespace ::com::sun::star::i18n; 2554 sal_Bool bCalendarSet = sal_False; 2555 double fNumberOrig = fNumber; 2556 sal_Bool bRes = sal_False; 2557 sal_Bool bSign = sal_False; 2558 if (fNumber < 0.0) 2559 { 2560 fNumber = -fNumber; 2561 if (nIx == 0) 2562 bSign = sal_True; 2563 } 2564 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2565 if (rInfo.bThousand) // []-Format 2566 { 2567 if (fNumber > 1.0E10) // zu gross 2568 { 2569 OutString = rScan.GetErrorString(); 2570 return sal_False; 2571 } 2572 } 2573 else 2574 fNumber -= floor(fNumber); // sonst Datum abtrennen 2575 sal_Bool bInputLine; 2576 xub_StrLen nCntPost; 2577 if ( rScan.GetStandardPrec() == 300 && 2578 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 2579 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 2580 bInputLine = sal_True; 2581 nCntPost = 7; 2582 } 2583 else 2584 { 2585 bInputLine = sal_False; 2586 nCntPost = xub_StrLen(rInfo.nCntPost); 2587 } 2588 if (bSign && !rInfo.bThousand) // kein []-Format 2589 fNumber = 1.0 - fNumber; // "Kehrwert" 2590 double fTime = fNumber * 86400.0; 2591 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 2592 if (bSign && fTime == 0.0) 2593 bSign = sal_False; // nicht -00:00:00 2594 2595 if( floor( fTime ) > _D_MAX_U_LONG_ ) 2596 { 2597 OutString = rScan.GetErrorString(); 2598 return sal_False; 2599 } 2600 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 2601 2602 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 2603 rtl_math_StringFormat_F, int(nCntPost), '.')); 2604 sSecStr.EraseLeadingChars('0'); 2605 sSecStr.EraseLeadingChars('.'); 2606 if ( bInputLine ) 2607 { 2608 sSecStr.EraseTrailingChars('0'); 2609 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 2610 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 2611 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2612 nCntPost = sSecStr.Len(); 2613 } 2614 else 2615 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2616 2617 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 2618 // abarbeiten 2619 sal_uLong nHour, nMin, nSec; 2620 if (!rInfo.bThousand) // kein [] Format 2621 { 2622 nHour = (nSeconds/3600) % 24; 2623 nMin = (nSeconds%3600) / 60; 2624 nSec = nSeconds%60; 2625 } 2626 else if (rInfo.nThousand == 3) // [ss] 2627 { 2628 nHour = 0; 2629 nMin = 0; 2630 nSec = nSeconds; 2631 } 2632 else if (rInfo.nThousand == 2) // [mm]:ss 2633 { 2634 nHour = 0; 2635 nMin = nSeconds / 60; 2636 nSec = nSeconds % 60; 2637 } 2638 else if (rInfo.nThousand == 1) // [hh]:mm:ss 2639 { 2640 nHour = nSeconds / 3600; 2641 nMin = (nSeconds%3600) / 60; 2642 nSec = nSeconds%60; 2643 } 2644 else { 2645 // TODO What should these be set to? 2646 nHour = 0; 2647 nMin = 0; 2648 nSec = 0; 2649 } 2650 2651 sal_Unicode cAmPm = ' '; // a oder p 2652 if (rInfo.nCntExp) // AM/PM 2653 { 2654 if (nHour == 0) 2655 { 2656 nHour = 12; 2657 cAmPm = 'a'; 2658 } 2659 else if (nHour < 12) 2660 cAmPm = 'a'; 2661 else 2662 { 2663 cAmPm = 'p'; 2664 if (nHour > 12) 2665 nHour -= 12; 2666 } 2667 } 2668 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2669 for (sal_uInt16 i = 0; i < nAnz; i++) 2670 { 2671 switch (rInfo.nTypeArray[i]) 2672 { 2673 case NF_SYMBOLTYPE_STAR: 2674 if( bStarFlag ) 2675 { 2676 OutString += (sal_Unicode) 0x1B; 2677 OutString += rInfo.sStrArray[i].GetChar(1); 2678 bRes = sal_True; 2679 } 2680 break; 2681 case NF_SYMBOLTYPE_BLANK: 2682 InsertBlanks( OutString, OutString.Len(), 2683 rInfo.sStrArray[i].GetChar(1) ); 2684 break; 2685 case NF_SYMBOLTYPE_STRING: 2686 case NF_SYMBOLTYPE_CURRENCY: 2687 case NF_SYMBOLTYPE_DATESEP: 2688 case NF_SYMBOLTYPE_TIMESEP: 2689 case NF_SYMBOLTYPE_TIME100SECSEP: 2690 OutString += rInfo.sStrArray[i]; 2691 break; 2692 case NF_SYMBOLTYPE_DIGIT: 2693 { 2694 xub_StrLen nLen = ( bInputLine && i > 0 && 2695 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 2696 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 2697 nCntPost : rInfo.sStrArray[i].Len() ); 2698 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 2699 { 2700 OutString += sSecStr.GetChar(nSecPos); 2701 nSecPos++; 2702 } 2703 } 2704 break; 2705 case NF_KEY_AMPM: // AM/PM 2706 { 2707 if ( !bCalendarSet ) 2708 { 2709 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart(); 2710 fDiff += fNumberOrig; 2711 GetCal().setLocalDateTime( fDiff ); 2712 bCalendarSet = sal_True; 2713 } 2714 if (cAmPm == 'a') 2715 OutString += GetCal().getDisplayName( 2716 CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 ); 2717 else 2718 OutString += GetCal().getDisplayName( 2719 CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 ); 2720 } 2721 break; 2722 case NF_KEY_AP: // A/P 2723 { 2724 if (cAmPm == 'a') 2725 OutString += 'a'; 2726 else 2727 OutString += 'p'; 2728 } 2729 break; 2730 case NF_KEY_MI: // M 2731 OutString += ImpIntToString( nIx, nMin ); 2732 break; 2733 case NF_KEY_MMI: // MM 2734 OutString += ImpIntToString( nIx, nMin, 2 ); 2735 break; 2736 case NF_KEY_H: // H 2737 OutString += ImpIntToString( nIx, nHour ); 2738 break; 2739 case NF_KEY_HH: // HH 2740 OutString += ImpIntToString( nIx, nHour, 2 ); 2741 break; 2742 case NF_KEY_S: // S 2743 OutString += ImpIntToString( nIx, nSec ); 2744 break; 2745 case NF_KEY_SS: // SS 2746 OutString += ImpIntToString( nIx, nSec, 2 ); 2747 break; 2748 default: 2749 break; 2750 } 2751 } 2752 if (bSign && rInfo.bThousand) 2753 OutString.Insert('-',0); 2754 return bRes; 2755 } 2756 2757 2758 sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const 2759 { 2760 if ( GetCal().getUniqueID() != Gregorian::get() ) 2761 return sal_False; 2762 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2763 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2764 sal_uInt16 i; 2765 for ( i = 0; i < nAnz; i++ ) 2766 { 2767 switch ( rInfo.nTypeArray[i] ) 2768 { 2769 case NF_SYMBOLTYPE_CALENDAR : 2770 return sal_False; 2771 case NF_KEY_EC : 2772 case NF_KEY_EEC : 2773 case NF_KEY_R : 2774 case NF_KEY_RR : 2775 case NF_KEY_AAA : 2776 case NF_KEY_AAAA : 2777 return sal_True; 2778 } 2779 } 2780 return sal_False; 2781 } 2782 2783 2784 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar, 2785 double& fOrgDateTime ) const 2786 { 2787 CalendarWrapper& rCal = GetCal(); 2788 const rtl::OUString &rGregorian = Gregorian::get(); 2789 if ( rCal.getUniqueID() == rGregorian ) 2790 { 2791 using namespace ::com::sun::star::i18n; 2792 ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals 2793 = rCal.getAllCalendars( rLoc().getLocale() ); 2794 sal_Int32 nCnt = xCals.getLength(); 2795 if ( nCnt > 1 ) 2796 { 2797 for ( sal_Int32 j=0; j < nCnt; j++ ) 2798 { 2799 if ( xCals[j] != rGregorian ) 2800 { 2801 if ( !rOrgCalendar.Len() ) 2802 { 2803 rOrgCalendar = rCal.getUniqueID(); 2804 fOrgDateTime = rCal.getDateTime(); 2805 } 2806 rCal.loadCalendar( xCals[j], rLoc().getLocale() ); 2807 rCal.setDateTime( fOrgDateTime ); 2808 break; // for 2809 } 2810 } 2811 } 2812 } 2813 } 2814 2815 2816 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar, 2817 double fOrgDateTime ) const 2818 { 2819 CalendarWrapper& rCal = GetCal(); 2820 const rtl::OUString &rGregorian = Gregorian::get(); 2821 if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian ) 2822 { 2823 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2824 rCal.setDateTime( fOrgDateTime ); 2825 } 2826 } 2827 2828 2829 sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime ) 2830 { 2831 using namespace ::com::sun::star::i18n; 2832 CalendarWrapper& rCal = GetCal(); 2833 const rtl::OUString &rGregorian = Gregorian::get(); 2834 if ( rCal.getUniqueID() != rGregorian ) 2835 { 2836 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2837 if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL( 2838 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) ) 2839 { 2840 if ( !rOrgCalendar.Len() ) 2841 { 2842 rOrgCalendar = rCal.getUniqueID(); 2843 fOrgDateTime = rCal.getDateTime(); 2844 } 2845 else if ( rOrgCalendar == String(rGregorian) ) 2846 rOrgCalendar.Erase(); 2847 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2848 rCal.setDateTime( fOrgDateTime ); 2849 return sal_True; 2850 } 2851 } 2852 return sal_False; 2853 } 2854 2855 2856 sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar, 2857 double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const 2858 { 2859 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2860 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2861 for ( sal_uInt16 i = 0; i < nAnz; i++ ) 2862 { 2863 if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR ) 2864 { 2865 CalendarWrapper& rCal = GetCal(); 2866 if ( !rOrgCalendar.Len() ) 2867 { 2868 rOrgCalendar = rCal.getUniqueID(); 2869 fOrgDateTime = rCal.getDateTime(); 2870 } 2871 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2872 rCal.setDateTime( fOrgDateTime ); 2873 return sal_True; 2874 } 2875 } 2876 return sal_False; 2877 } 2878 2879 2880 // static 2881 void SvNumberformat::ImpAppendEraG( String& OutString, 2882 const CalendarWrapper& rCal, sal_Int16 nNatNum ) 2883 { 2884 using namespace ::com::sun::star::i18n; 2885 if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) ) 2886 { 2887 sal_Unicode cEra; 2888 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2889 switch ( nVal ) 2890 { 2891 case 1 : cEra = 'M'; break; 2892 case 2 : cEra = 'T'; break; 2893 case 3 : cEra = 'S'; break; 2894 case 4 : cEra = 'H'; break; 2895 default: 2896 cEra = '?'; 2897 } 2898 OutString += cEra; 2899 } 2900 else 2901 OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ); 2902 } 2903 2904 2905 sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber, 2906 sal_uInt16 nIx, 2907 String& OutString) 2908 { 2909 using namespace ::com::sun::star::i18n; 2910 sal_Bool bRes = sal_False; 2911 CalendarWrapper& rCal = GetCal(); 2912 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 2913 fNumber += fDiff; 2914 rCal.setLocalDateTime( fNumber ); 2915 String aOrgCalendar; // empty => not changed yet 2916 double fOrgDateTime; 2917 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 2918 if ( bOtherCalendar ) 2919 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 2920 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 2921 bOtherCalendar = sal_False; 2922 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2923 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2924 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 2925 for (sal_uInt16 i = 0; i < nAnz; i++) 2926 { 2927 switch (rInfo.nTypeArray[i]) 2928 { 2929 case NF_SYMBOLTYPE_CALENDAR : 2930 if ( !aOrgCalendar.Len() ) 2931 { 2932 aOrgCalendar = rCal.getUniqueID(); 2933 fOrgDateTime = rCal.getDateTime(); 2934 } 2935 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2936 rCal.setDateTime( fOrgDateTime ); 2937 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 2938 break; 2939 case NF_SYMBOLTYPE_STAR: 2940 if( bStarFlag ) 2941 { 2942 OutString += (sal_Unicode) 0x1B; 2943 OutString += rInfo.sStrArray[i].GetChar(1); 2944 bRes = sal_True; 2945 } 2946 break; 2947 case NF_SYMBOLTYPE_BLANK: 2948 InsertBlanks( OutString, OutString.Len(), 2949 rInfo.sStrArray[i].GetChar(1) ); 2950 break; 2951 case NF_SYMBOLTYPE_STRING: 2952 case NF_SYMBOLTYPE_CURRENCY: 2953 case NF_SYMBOLTYPE_DATESEP: 2954 case NF_SYMBOLTYPE_TIMESEP: 2955 case NF_SYMBOLTYPE_TIME100SECSEP: 2956 OutString += rInfo.sStrArray[i]; 2957 break; 2958 case NF_KEY_M: // M 2959 OutString += rCal.getDisplayString( 2960 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 2961 break; 2962 case NF_KEY_MM: // MM 2963 OutString += rCal.getDisplayString( 2964 CalendarDisplayCode::LONG_MONTH, nNatNum ); 2965 break; 2966 case NF_KEY_MMM: // MMM 2967 OutString += rCal.getDisplayString( 2968 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 2969 break; 2970 case NF_KEY_MMMM: // MMMM 2971 OutString += rCal.getDisplayString( 2972 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 2973 break; 2974 case NF_KEY_MMMMM: // MMMMM 2975 OutString += rCal.getDisplayString( 2976 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 2977 break; 2978 case NF_KEY_Q: // Q 2979 OutString += rCal.getDisplayString( 2980 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 2981 break; 2982 case NF_KEY_QQ: // QQ 2983 OutString += rCal.getDisplayString( 2984 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 2985 break; 2986 case NF_KEY_D: // D 2987 OutString += rCal.getDisplayString( 2988 CalendarDisplayCode::SHORT_DAY, nNatNum ); 2989 break; 2990 case NF_KEY_DD: // DD 2991 OutString += rCal.getDisplayString( 2992 CalendarDisplayCode::LONG_DAY, nNatNum ); 2993 break; 2994 case NF_KEY_DDD: // DDD 2995 { 2996 if ( bOtherCalendar ) 2997 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 2998 OutString += rCal.getDisplayString( 2999 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3000 if ( bOtherCalendar ) 3001 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3002 } 3003 break; 3004 case NF_KEY_DDDD: // DDDD 3005 { 3006 if ( bOtherCalendar ) 3007 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3008 OutString += rCal.getDisplayString( 3009 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3010 if ( bOtherCalendar ) 3011 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3012 } 3013 break; 3014 case NF_KEY_YY: // YY 3015 { 3016 if ( bOtherCalendar ) 3017 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3018 OutString += rCal.getDisplayString( 3019 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3020 if ( bOtherCalendar ) 3021 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3022 } 3023 break; 3024 case NF_KEY_YYYY: // YYYY 3025 { 3026 if ( bOtherCalendar ) 3027 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3028 OutString += rCal.getDisplayString( 3029 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3030 if ( bOtherCalendar ) 3031 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3032 } 3033 break; 3034 case NF_KEY_EC: // E 3035 OutString += rCal.getDisplayString( 3036 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3037 break; 3038 case NF_KEY_EEC: // EE 3039 case NF_KEY_R: // R 3040 OutString += rCal.getDisplayString( 3041 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3042 break; 3043 case NF_KEY_NN: // NN 3044 case NF_KEY_AAA: // AAA 3045 OutString += rCal.getDisplayString( 3046 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3047 break; 3048 case NF_KEY_NNN: // NNN 3049 case NF_KEY_AAAA: // AAAA 3050 OutString += rCal.getDisplayString( 3051 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3052 break; 3053 case NF_KEY_NNNN: // NNNN 3054 { 3055 OutString += rCal.getDisplayString( 3056 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3057 OutString += rLoc().getLongDateDayOfWeekSep(); 3058 } 3059 break; 3060 case NF_KEY_WW : // WW 3061 { 3062 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3063 OutString += ImpIntToString( nIx, nVal ); 3064 } 3065 break; 3066 case NF_KEY_G: // G 3067 ImpAppendEraG( OutString, rCal, nNatNum ); 3068 break; 3069 case NF_KEY_GG: // GG 3070 OutString += rCal.getDisplayString( 3071 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3072 break; 3073 case NF_KEY_GGG: // GGG 3074 OutString += rCal.getDisplayString( 3075 CalendarDisplayCode::LONG_ERA, nNatNum ); 3076 break; 3077 case NF_KEY_RR: // RR => GGGEE 3078 OutString += rCal.getDisplayString( 3079 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3080 break; 3081 } 3082 } 3083 if ( aOrgCalendar.Len() ) 3084 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3085 return bRes; 3086 } 3087 3088 sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, 3089 sal_uInt16 nIx, 3090 String& OutString) 3091 { 3092 using namespace ::com::sun::star::i18n; 3093 sal_Bool bRes = sal_False; 3094 3095 CalendarWrapper& rCal = GetCal(); 3096 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 3097 fNumber += fDiff; 3098 3099 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3100 sal_Bool bInputLine; 3101 xub_StrLen nCntPost; 3102 if ( rScan.GetStandardPrec() == 300 && 3103 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 3104 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 3105 bInputLine = sal_True; 3106 nCntPost = 7; 3107 } 3108 else 3109 { 3110 bInputLine = sal_False; 3111 nCntPost = xub_StrLen(rInfo.nCntPost); 3112 } 3113 double fTime = (fNumber - floor( fNumber )) * 86400.0; 3114 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 3115 if (fTime >= 86400.0) 3116 { 3117 // result of fNumber==x.999999999... rounded up, use correct date/time 3118 fTime -= 86400.0; 3119 fNumber = floor( fNumber + 0.5) + fTime; 3120 } 3121 rCal.setLocalDateTime( fNumber ); 3122 3123 String aOrgCalendar; // empty => not changed yet 3124 double fOrgDateTime; 3125 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 3126 if ( bOtherCalendar ) 3127 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3128 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 3129 bOtherCalendar = sal_False; 3130 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 3131 3132 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 3133 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 3134 rtl_math_StringFormat_F, int(nCntPost), '.')); 3135 sSecStr.EraseLeadingChars('0'); 3136 sSecStr.EraseLeadingChars('.'); 3137 if ( bInputLine ) 3138 { 3139 sSecStr.EraseTrailingChars('0'); 3140 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 3141 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 3142 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3143 nCntPost = sSecStr.Len(); 3144 } 3145 else 3146 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3147 3148 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 3149 // abarbeiten 3150 sal_uLong nHour, nMin, nSec; 3151 if (!rInfo.bThousand) // [] Format 3152 { 3153 nHour = (nSeconds/3600) % 24; 3154 nMin = (nSeconds%3600) / 60; 3155 nSec = nSeconds%60; 3156 } 3157 else if (rInfo.nThousand == 3) // [ss] 3158 { 3159 nHour = 0; 3160 nMin = 0; 3161 nSec = nSeconds; 3162 } 3163 else if (rInfo.nThousand == 2) // [mm]:ss 3164 { 3165 nHour = 0; 3166 nMin = nSeconds / 60; 3167 nSec = nSeconds % 60; 3168 } 3169 else if (rInfo.nThousand == 1) // [hh]:mm:ss 3170 { 3171 nHour = nSeconds / 3600; 3172 nMin = (nSeconds%3600) / 60; 3173 nSec = nSeconds%60; 3174 } 3175 else { 3176 nHour = 0; // TODO What should these values be? 3177 nMin = 0; 3178 nSec = 0; 3179 } 3180 sal_Unicode cAmPm = ' '; // a oder p 3181 if (rInfo.nCntExp) // AM/PM 3182 { 3183 if (nHour == 0) 3184 { 3185 nHour = 12; 3186 cAmPm = 'a'; 3187 } 3188 else if (nHour < 12) 3189 cAmPm = 'a'; 3190 else 3191 { 3192 cAmPm = 'p'; 3193 if (nHour > 12) 3194 nHour -= 12; 3195 } 3196 } 3197 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 3198 for (sal_uInt16 i = 0; i < nAnz; i++) 3199 { 3200 switch (rInfo.nTypeArray[i]) 3201 { 3202 case NF_SYMBOLTYPE_CALENDAR : 3203 if ( !aOrgCalendar.Len() ) 3204 { 3205 aOrgCalendar = rCal.getUniqueID(); 3206 fOrgDateTime = rCal.getDateTime(); 3207 } 3208 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 3209 rCal.setDateTime( fOrgDateTime ); 3210 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3211 break; 3212 case NF_SYMBOLTYPE_STAR: 3213 if( bStarFlag ) 3214 { 3215 OutString += (sal_Unicode) 0x1B; 3216 OutString += rInfo.sStrArray[i].GetChar(1); 3217 bRes = sal_True; 3218 } 3219 break; 3220 case NF_SYMBOLTYPE_BLANK: 3221 InsertBlanks( OutString, OutString.Len(), 3222 rInfo.sStrArray[i].GetChar(1) ); 3223 break; 3224 case NF_SYMBOLTYPE_STRING: 3225 case NF_SYMBOLTYPE_CURRENCY: 3226 case NF_SYMBOLTYPE_DATESEP: 3227 case NF_SYMBOLTYPE_TIMESEP: 3228 case NF_SYMBOLTYPE_TIME100SECSEP: 3229 OutString += rInfo.sStrArray[i]; 3230 break; 3231 case NF_SYMBOLTYPE_DIGIT: 3232 { 3233 xub_StrLen nLen = ( bInputLine && i > 0 && 3234 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 3235 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 3236 nCntPost : rInfo.sStrArray[i].Len() ); 3237 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 3238 { 3239 OutString += sSecStr.GetChar(nSecPos); 3240 nSecPos++; 3241 } 3242 } 3243 break; 3244 case NF_KEY_AMPM: // AM/PM 3245 { 3246 if (cAmPm == 'a') 3247 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3248 AmPmValue::AM, 0 ); 3249 else 3250 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3251 AmPmValue::PM, 0 ); 3252 } 3253 break; 3254 case NF_KEY_AP: // A/P 3255 { 3256 if (cAmPm == 'a') 3257 OutString += 'a'; 3258 else 3259 OutString += 'p'; 3260 } 3261 break; 3262 case NF_KEY_MI: // M 3263 OutString += ImpIntToString( nIx, nMin ); 3264 break; 3265 case NF_KEY_MMI: // MM 3266 OutString += ImpIntToString( nIx, nMin, 2 ); 3267 break; 3268 case NF_KEY_H: // H 3269 OutString += ImpIntToString( nIx, nHour ); 3270 break; 3271 case NF_KEY_HH: // HH 3272 OutString += ImpIntToString( nIx, nHour, 2 ); 3273 break; 3274 case NF_KEY_S: // S 3275 OutString += ImpIntToString( nIx, nSec ); 3276 break; 3277 case NF_KEY_SS: // SS 3278 OutString += ImpIntToString( nIx, nSec, 2 ); 3279 break; 3280 case NF_KEY_M: // M 3281 OutString += rCal.getDisplayString( 3282 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 3283 break; 3284 case NF_KEY_MM: // MM 3285 OutString += rCal.getDisplayString( 3286 CalendarDisplayCode::LONG_MONTH, nNatNum ); 3287 break; 3288 case NF_KEY_MMM: // MMM 3289 OutString += rCal.getDisplayString( 3290 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 3291 break; 3292 case NF_KEY_MMMM: // MMMM 3293 OutString += rCal.getDisplayString( 3294 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 3295 break; 3296 case NF_KEY_MMMMM: // MMMMM 3297 OutString += rCal.getDisplayString( 3298 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 3299 break; 3300 case NF_KEY_Q: // Q 3301 OutString += rCal.getDisplayString( 3302 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 3303 break; 3304 case NF_KEY_QQ: // QQ 3305 OutString += rCal.getDisplayString( 3306 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 3307 break; 3308 case NF_KEY_D: // D 3309 OutString += rCal.getDisplayString( 3310 CalendarDisplayCode::SHORT_DAY, nNatNum ); 3311 break; 3312 case NF_KEY_DD: // DD 3313 OutString += rCal.getDisplayString( 3314 CalendarDisplayCode::LONG_DAY, nNatNum ); 3315 break; 3316 case NF_KEY_DDD: // DDD 3317 { 3318 if ( bOtherCalendar ) 3319 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3320 OutString += rCal.getDisplayString( 3321 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3322 if ( bOtherCalendar ) 3323 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3324 } 3325 break; 3326 case NF_KEY_DDDD: // DDDD 3327 { 3328 if ( bOtherCalendar ) 3329 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3330 OutString += rCal.getDisplayString( 3331 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3332 if ( bOtherCalendar ) 3333 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3334 } 3335 break; 3336 case NF_KEY_YY: // YY 3337 { 3338 if ( bOtherCalendar ) 3339 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3340 OutString += rCal.getDisplayString( 3341 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3342 if ( bOtherCalendar ) 3343 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3344 } 3345 break; 3346 case NF_KEY_YYYY: // YYYY 3347 { 3348 if ( bOtherCalendar ) 3349 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3350 OutString += rCal.getDisplayString( 3351 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3352 if ( bOtherCalendar ) 3353 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3354 } 3355 break; 3356 case NF_KEY_EC: // E 3357 OutString += rCal.getDisplayString( 3358 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3359 break; 3360 case NF_KEY_EEC: // EE 3361 case NF_KEY_R: // R 3362 OutString += rCal.getDisplayString( 3363 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3364 break; 3365 case NF_KEY_NN: // NN 3366 case NF_KEY_AAA: // AAA 3367 OutString += rCal.getDisplayString( 3368 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3369 break; 3370 case NF_KEY_NNN: // NNN 3371 case NF_KEY_AAAA: // AAAA 3372 OutString += rCal.getDisplayString( 3373 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3374 break; 3375 case NF_KEY_NNNN: // NNNN 3376 { 3377 OutString += rCal.getDisplayString( 3378 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3379 OutString += rLoc().getLongDateDayOfWeekSep(); 3380 } 3381 break; 3382 case NF_KEY_WW : // WW 3383 { 3384 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3385 OutString += ImpIntToString( nIx, nVal ); 3386 } 3387 break; 3388 case NF_KEY_G: // G 3389 ImpAppendEraG( OutString, rCal, nNatNum ); 3390 break; 3391 case NF_KEY_GG: // GG 3392 OutString += rCal.getDisplayString( 3393 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3394 break; 3395 case NF_KEY_GGG: // GGG 3396 OutString += rCal.getDisplayString( 3397 CalendarDisplayCode::LONG_ERA, nNatNum ); 3398 break; 3399 case NF_KEY_RR: // RR => GGGEE 3400 OutString += rCal.getDisplayString( 3401 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3402 break; 3403 } 3404 } 3405 if ( aOrgCalendar.Len() ) 3406 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3407 return bRes; 3408 } 3409 3410 sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber, 3411 sal_uInt16 nIx, 3412 String& OutString) 3413 { 3414 sal_Bool bRes = sal_False; 3415 sal_Bool bSign; 3416 if (fNumber < 0.0) 3417 { 3418 if (nIx == 0) // nicht in hinteren 3419 bSign = sal_True; // Formaten 3420 else 3421 bSign = sal_False; 3422 fNumber = -fNumber; 3423 } 3424 else 3425 { 3426 bSign = sal_False; 3427 if ( ::rtl::math::isSignBitSet( fNumber ) ) 3428 fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-' 3429 } 3430 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3431 if (rInfo.eScannedType == NUMBERFORMAT_PERCENT) 3432 { 3433 if (fNumber < _D_MAX_D_BY_100) 3434 fNumber *= 100.0; 3435 else 3436 { 3437 OutString = rScan.GetErrorString(); 3438 return sal_False; 3439 } 3440 } 3441 sal_uInt16 i, j; 3442 xub_StrLen k; 3443 String sStr; 3444 long nPrecExp; 3445 sal_Bool bInteger = sal_False; 3446 if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT ) 3447 { // special formatting only if no GENERAL keyword in format code 3448 const sal_uInt16 nThousand = rInfo.nThousand; 3449 for (i = 0; i < nThousand; i++) 3450 { 3451 if (fNumber > _D_MIN_M_BY_1000) 3452 fNumber /= 1000.0; 3453 else 3454 fNumber = 0.0; 3455 } 3456 if (fNumber > 0.0) 3457 nPrecExp = GetPrecExp( fNumber ); 3458 else 3459 nPrecExp = 0; 3460 if (rInfo.nCntPost) // NachkommaStellen 3461 { 3462 if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15) 3463 { 3464 sStr = ::rtl::math::doubleToUString( fNumber, 3465 rtl_math_StringFormat_F, 15-nPrecExp, '.'); 3466 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++) 3467 sStr += '0'; 3468 } 3469 else 3470 sStr = ::rtl::math::doubleToUString( fNumber, 3471 rtl_math_StringFormat_F, rInfo.nCntPost, '.' ); 3472 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3473 } 3474 else if (fNumber == 0.0) // Null 3475 { 3476 // nothing to be done here, keep empty string sStr, 3477 // ImpNumberFillWithThousands does the rest 3478 } 3479 else // Integer 3480 { 3481 sStr = ::rtl::math::doubleToUString( fNumber, 3482 rtl_math_StringFormat_F, 0, '.'); 3483 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3484 } 3485 xub_StrLen nPoint = sStr.Search( '.' ); 3486 if ( nPoint != STRING_NOTFOUND ) 3487 { 3488 register const sal_Unicode* p = sStr.GetBuffer() + nPoint; 3489 while ( *++p == '0' ) 3490 ; 3491 if ( !*p ) 3492 bInteger = sal_True; 3493 sStr.Erase( nPoint, 1 ); // . herausnehmen 3494 } 3495 if (bSign && 3496 (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000 3497 bSign = sal_False; // nicht -0.00 3498 } // End of != FLAG_STANDARD_IN_FORMAT 3499 3500 // von hinten nach vorn 3501 // editieren: 3502 k = sStr.Len(); // hinter letzter Ziffer 3503 j = NumFor[nIx].GetnAnz()-1; // letztes Symbol 3504 // Nachkommastellen: 3505 if (rInfo.nCntPost > 0) 3506 { 3507 sal_Bool bTrailing = sal_True; // ob Endnullen? 3508 sal_Bool bFilled = sal_False; // ob aufgefuellt wurde ? 3509 short nType; 3510 while (j > 0 && // rueckwaerts 3511 (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP) 3512 { 3513 switch ( nType ) 3514 { 3515 case NF_SYMBOLTYPE_STAR: 3516 if( bStarFlag ) 3517 { 3518 sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ ); 3519 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3520 bRes = sal_True; 3521 } 3522 break; 3523 case NF_SYMBOLTYPE_BLANK: 3524 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3525 break; 3526 case NF_SYMBOLTYPE_STRING: 3527 case NF_SYMBOLTYPE_CURRENCY: 3528 case NF_SYMBOLTYPE_PERCENT: 3529 sStr.Insert(rInfo.sStrArray[j],k); 3530 break; 3531 case NF_SYMBOLTYPE_THSEP: 3532 if (rInfo.nThousand == 0) 3533 sStr.Insert(rInfo.sStrArray[j],k); 3534 break; 3535 case NF_SYMBOLTYPE_DIGIT: 3536 { 3537 const String& rStr = rInfo.sStrArray[j]; 3538 const sal_Unicode* p1 = rStr.GetBuffer(); 3539 register const sal_Unicode* p = p1 + rStr.Len(); 3540 while ( p1 < p-- ) 3541 { 3542 const sal_Unicode c = *p; 3543 k--; 3544 if ( sStr.GetChar(k) != '0' ) 3545 bTrailing = sal_False; 3546 if (bTrailing) 3547 { 3548 if ( c == '0' ) 3549 bFilled = sal_True; 3550 else if ( c == '-' ) 3551 { 3552 if ( bInteger ) 3553 sStr.SetChar( k, '-' ); 3554 bFilled = sal_True; 3555 } 3556 else if ( c == '?' ) 3557 { 3558 sStr.SetChar( k, ' ' ); 3559 bFilled = sal_True; 3560 } 3561 else if ( !bFilled ) // # 3562 sStr.Erase(k,1); 3563 } 3564 } // of for 3565 } // of case digi 3566 break; 3567 case NF_KEY_CCC: // CCC-Waehrung 3568 sStr.Insert(rScan.GetCurAbbrev(), k); 3569 break; 3570 case NF_KEY_GENERAL: // Standard im String 3571 { 3572 String sNum; 3573 ImpGetOutputStandard(fNumber, sNum); 3574 sNum.EraseLeadingChars('-'); 3575 sStr.Insert(sNum, k); 3576 } 3577 break; 3578 default: 3579 break; 3580 } // of switch 3581 j--; 3582 } // of while 3583 } // of Nachkomma 3584 3585 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit . 3586 rInfo.nCntPre); 3587 if ( rInfo.nCntPost > 0 ) 3588 { 3589 const String& rDecSep = GetFormatter().GetNumDecimalSep(); 3590 xub_StrLen nLen = rDecSep.Len(); 3591 if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) ) 3592 sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep 3593 } 3594 if (bSign) 3595 sStr.Insert('-',0); 3596 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 3597 OutString = sStr; 3598 return bRes; 3599 } 3600 3601 sal_Bool SvNumberformat::ImpNumberFillWithThousands( 3602 String& sStr, // number string 3603 double& rNumber, // number 3604 xub_StrLen k, // position within string 3605 sal_uInt16 j, // symbol index within format code 3606 sal_uInt16 nIx, // subformat index 3607 sal_uInt16 nDigCnt) // count of integer digits in format 3608 { 3609 sal_Bool bRes = sal_False; 3610 xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number 3611 xub_StrLen nDigitCount = 0; // count of integer digits from the right 3612 sal_Bool bStop = sal_False; 3613 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3614 // no normal thousands separators if number divided by thousands 3615 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3616 utl::DigitGroupingIterator aGrouping( 3617 GetFormatter().GetLocaleData()->getDigitGrouping()); 3618 while (!bStop) // backwards 3619 { 3620 if (j == 0) 3621 bStop = sal_True; 3622 switch (rInfo.nTypeArray[j]) 3623 { 3624 case NF_SYMBOLTYPE_DECSEP: 3625 aGrouping.reset(); 3626 // fall thru 3627 case NF_SYMBOLTYPE_STRING: 3628 case NF_SYMBOLTYPE_CURRENCY: 3629 case NF_SYMBOLTYPE_PERCENT: 3630 sStr.Insert(rInfo.sStrArray[j],k); 3631 if ( k == 0 ) 3632 nLeadingStringChars = 3633 nLeadingStringChars + rInfo.sStrArray[j].Len(); 3634 break; 3635 case NF_SYMBOLTYPE_STAR: 3636 if( bStarFlag ) 3637 { 3638 sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ ); 3639 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3640 bRes = sal_True; 3641 } 3642 break; 3643 case NF_SYMBOLTYPE_BLANK: 3644 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3645 break; 3646 case NF_SYMBOLTYPE_THSEP: 3647 { 3648 // #i7284# #102685# Insert separator also if number is divided 3649 // by thousands and the separator is specified somewhere in 3650 // between and not only at the end. 3651 // #i12596# But do not insert if it's a parenthesized negative 3652 // format like (#,) 3653 // In fact, do not insert if divided and regex [0#,],[^0#] and 3654 // no other digit symbol follows (which was already detected 3655 // during scan of format code, otherwise there would be no 3656 // division), else do insert. Same in ImpNumberFill() below. 3657 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3658 bDoThousands = ((j == 0) || 3659 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3660 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3661 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3662 if ( bDoThousands ) 3663 { 3664 if (k > 0) 3665 sStr.Insert(rInfo.sStrArray[j],k); 3666 else if (nDigitCount < nDigCnt) 3667 { 3668 // Leading '#' displays nothing (e.g. no leading 3669 // separator for numbers <1000 with #,##0 format). 3670 // Leading '?' displays blank. 3671 // Everything else, including nothing, displays the 3672 // separator. 3673 sal_Unicode cLeader = 0; 3674 if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT) 3675 { 3676 const String& rStr = rInfo.sStrArray[j-1]; 3677 xub_StrLen nLen = rStr.Len(); 3678 if (nLen) 3679 cLeader = rStr.GetChar(nLen-1); 3680 } 3681 switch (cLeader) 3682 { 3683 case '#': 3684 ; // nothing 3685 break; 3686 case '?': 3687 // erAck: 2008-04-03T16:24+0200 3688 // Actually this currently isn't executed 3689 // because the format scanner in the context of 3690 // "?," doesn't generate a group separator but 3691 // a literal ',' character instead that is 3692 // inserted unconditionally. Should be changed 3693 // on some occasion. 3694 sStr.Insert(' ',k); 3695 break; 3696 default: 3697 sStr.Insert(rInfo.sStrArray[j],k); 3698 } 3699 } 3700 aGrouping.advance(); 3701 } 3702 } 3703 break; 3704 case NF_SYMBOLTYPE_DIGIT: 3705 { 3706 const String& rStr = rInfo.sStrArray[j]; 3707 const sal_Unicode* p1 = rStr.GetBuffer(); 3708 register const sal_Unicode* p = p1 + rStr.Len(); 3709 while ( p1 < p-- ) 3710 { 3711 nDigitCount++; 3712 if (k > 0) 3713 k--; 3714 else 3715 { 3716 switch (*p) 3717 { 3718 case '0': 3719 sStr.Insert('0',0); 3720 break; 3721 case '?': 3722 sStr.Insert(' ',0); 3723 break; 3724 } 3725 } 3726 if (nDigitCount == nDigCnt && k > 0) 3727 { // more digits than specified 3728 ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping); 3729 } 3730 } 3731 } 3732 break; 3733 case NF_KEY_CCC: // CCC currency 3734 sStr.Insert(rScan.GetCurAbbrev(), k); 3735 break; 3736 case NF_KEY_GENERAL: // "General" in string 3737 { 3738 String sNum; 3739 ImpGetOutputStandard(rNumber, sNum); 3740 sNum.EraseLeadingChars('-'); 3741 sStr.Insert(sNum, k); 3742 } 3743 break; 3744 3745 default: 3746 break; 3747 } // switch 3748 j--; // next format code string 3749 } // while 3750 k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ... 3751 if (k > nLeadingStringChars) 3752 ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping); 3753 return bRes; 3754 } 3755 3756 void SvNumberformat::ImpDigitFill( 3757 String& sStr, // number string 3758 xub_StrLen nStart, // start of digits 3759 xub_StrLen& k, // position within string 3760 sal_uInt16 nIx, // subformat index 3761 xub_StrLen & nDigitCount, // count of integer digits from the right so far 3762 utl::DigitGroupingIterator & rGrouping ) // current grouping 3763 { 3764 if (NumFor[nIx].Info().bThousand) // only if grouping 3765 { // fill in separators 3766 const String& rThousandSep = GetFormatter().GetNumThousandSep(); 3767 while (k > nStart) 3768 { 3769 if (nDigitCount == rGrouping.getPos()) 3770 { 3771 sStr.Insert( rThousandSep, k ); 3772 rGrouping.advance(); 3773 } 3774 nDigitCount++; 3775 k--; 3776 } 3777 } 3778 else // simply skip 3779 k = nStart; 3780 } 3781 3782 sal_Bool SvNumberformat::ImpNumberFill( String& sStr, // number string 3783 double& rNumber, // number for "General" format 3784 xub_StrLen& k, // position within string 3785 sal_uInt16& j, // symbol index within format code 3786 sal_uInt16 nIx, // subformat index 3787 short eSymbolType ) // type of stop condition 3788 { 3789 sal_Bool bRes = sal_False; 3790 k = sStr.Len(); // behind last digit 3791 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3792 // no normal thousands separators if number divided by thousands 3793 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3794 short nType; 3795 while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType ) 3796 { // rueckwaerts: 3797 switch ( nType ) 3798 { 3799 case NF_SYMBOLTYPE_STAR: 3800 if( bStarFlag ) 3801 { 3802 sStr.Insert( sal_Unicode(0x1B), k++ ); 3803 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3804 bRes = sal_True; 3805 } 3806 break; 3807 case NF_SYMBOLTYPE_BLANK: 3808 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3809 break; 3810 case NF_SYMBOLTYPE_THSEP: 3811 { 3812 // Same as in ImpNumberFillWithThousands() above, do not insert 3813 // if divided and regex [0#,],[^0#] and no other digit symbol 3814 // follows (which was already detected during scan of format 3815 // code, otherwise there would be no division), else do insert. 3816 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3817 bDoThousands = ((j == 0) || 3818 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3819 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3820 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3821 if ( bDoThousands && k > 0 ) 3822 { 3823 sStr.Insert(rInfo.sStrArray[j],k); 3824 } 3825 } 3826 break; 3827 case NF_SYMBOLTYPE_DIGIT: 3828 { 3829 const String& rStr = rInfo.sStrArray[j]; 3830 const sal_Unicode* p1 = rStr.GetBuffer(); 3831 register const sal_Unicode* p = p1 + rStr.Len(); 3832 while ( p1 < p-- ) 3833 { 3834 if (k > 0) 3835 k--; 3836 else 3837 { 3838 switch (*p) 3839 { 3840 case '0': 3841 sStr.Insert('0',0); 3842 break; 3843 case '?': 3844 sStr.Insert(' ',0); 3845 break; 3846 } 3847 } 3848 } 3849 } 3850 break; 3851 case NF_KEY_CCC: // CCC-Waehrung 3852 sStr.Insert(rScan.GetCurAbbrev(), k); 3853 break; 3854 case NF_KEY_GENERAL: // Standard im String 3855 { 3856 String sNum; 3857 ImpGetOutputStandard(rNumber, sNum); 3858 sNum.EraseLeadingChars('-'); // Vorzeichen weg!! 3859 sStr.Insert(sNum, k); 3860 } 3861 break; 3862 3863 default: 3864 sStr.Insert(rInfo.sStrArray[j],k); 3865 break; 3866 } // of switch 3867 j--; // naechster String 3868 } // of while 3869 return bRes; 3870 } 3871 3872 void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand, 3873 sal_Bool& IsRed, 3874 sal_uInt16& nPrecision, 3875 sal_uInt16& nAnzLeading) const 3876 { 3877 // as before: take info from nNumFor=0 for whole format (for dialog etc.) 3878 3879 short nDummyType; 3880 GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading ); 3881 3882 // "negative in red" is only useful for the whole format 3883 3884 const Color* pColor = NumFor[1].GetColor(); 3885 if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor 3886 && (*pColor == rScan.GetRedColor())) 3887 IsRed = sal_True; 3888 else 3889 IsRed = sal_False; 3890 } 3891 3892 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType, 3893 sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const 3894 { 3895 // take info from a specified sub-format (for XML export) 3896 3897 if ( nNumFor > 3 ) 3898 return; // invalid 3899 3900 const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); 3901 rScannedType = rInfo.eScannedType; 3902 bThousand = rInfo.bThousand; 3903 nPrecision = rInfo.nCntPost; 3904 if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER) 3905 // StandardFormat 3906 nAnzLeading = 1; 3907 else 3908 { 3909 nAnzLeading = 0; 3910 sal_Bool bStop = sal_False; 3911 sal_uInt16 i = 0; 3912 const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3913 while (!bStop && i < nAnz) 3914 { 3915 short nType = rInfo.nTypeArray[i]; 3916 if ( nType == NF_SYMBOLTYPE_DIGIT) 3917 { 3918 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer(); 3919 while ( *p == '#' ) 3920 p++; 3921 while ( *p++ == '0' ) 3922 nAnzLeading++; 3923 } 3924 else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP) 3925 bStop = sal_True; 3926 i++; 3927 } 3928 } 3929 } 3930 3931 const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, 3932 sal_Bool bString /* = sal_False */ ) const 3933 { 3934 if ( nNumFor > 3 ) 3935 return NULL; 3936 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3937 if ( !nAnz ) 3938 return NULL; 3939 if ( nPos == 0xFFFF ) 3940 { 3941 nPos = nAnz - 1; 3942 if ( bString ) 3943 { // rueckwaerts 3944 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3945 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 3946 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3947 { 3948 pType--; 3949 nPos--; 3950 } 3951 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3952 return NULL; 3953 } 3954 } 3955 else if ( nPos > nAnz - 1 ) 3956 return NULL; 3957 else if ( bString ) 3958 { // vorwaerts 3959 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3960 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 3961 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3962 { 3963 pType++; 3964 nPos++; 3965 } 3966 if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) && 3967 (*pType != NF_SYMBOLTYPE_CURRENCY)) ) 3968 return NULL; 3969 } 3970 return &NumFor[nNumFor].Info().sStrArray[nPos]; 3971 } 3972 3973 3974 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos, 3975 sal_Bool bString /* = sal_False */ ) const 3976 { 3977 if ( nNumFor > 3 ) 3978 return 0; 3979 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3980 if ( !nAnz ) 3981 return 0; 3982 if ( nPos == 0xFFFF ) 3983 { 3984 nPos = nAnz - 1; 3985 if ( bString ) 3986 { // rueckwaerts 3987 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3988 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 3989 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3990 { 3991 pType--; 3992 nPos--; 3993 } 3994 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3995 return 0; 3996 } 3997 } 3998 else if ( nPos > nAnz - 1 ) 3999 return 0; 4000 else if ( bString ) 4001 { // vorwaerts 4002 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 4003 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 4004 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4005 { 4006 pType++; 4007 nPos++; 4008 } 4009 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4010 return 0; 4011 } 4012 return NumFor[nNumFor].Info().nTypeArray[nPos]; 4013 } 4014 4015 4016 sal_Bool SvNumberformat::IsNegativeWithoutSign() const 4017 { 4018 if ( IsNegativeRealNegative() ) 4019 { 4020 const String* pStr = GetNumForString( 1, 0, sal_True ); 4021 if ( pStr ) 4022 return !HasStringNegativeSign( *pStr ); 4023 } 4024 return sal_False; 4025 } 4026 4027 4028 DateFormat SvNumberformat::GetDateOrder() const 4029 { 4030 if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE ) 4031 { 4032 short const * const pType = NumFor[0].Info().nTypeArray; 4033 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4034 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4035 { 4036 switch ( pType[j] ) 4037 { 4038 case NF_KEY_D : 4039 case NF_KEY_DD : 4040 return DMY; 4041 case NF_KEY_M : 4042 case NF_KEY_MM : 4043 case NF_KEY_MMM : 4044 case NF_KEY_MMMM : 4045 case NF_KEY_MMMMM : 4046 return MDY; 4047 case NF_KEY_YY : 4048 case NF_KEY_YYYY : 4049 case NF_KEY_EC : 4050 case NF_KEY_EEC : 4051 case NF_KEY_R : 4052 case NF_KEY_RR : 4053 return YMD; 4054 } 4055 } 4056 } 4057 else 4058 { 4059 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" ); 4060 } 4061 return rLoc().getDateFormat(); 4062 } 4063 4064 4065 sal_uInt32 SvNumberformat::GetExactDateOrder() const 4066 { 4067 sal_uInt32 nRet = 0; 4068 if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE ) 4069 { 4070 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" ); 4071 return nRet; 4072 } 4073 short const * const pType = NumFor[0].Info().nTypeArray; 4074 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4075 int nShift = 0; 4076 for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ ) 4077 { 4078 switch ( pType[j] ) 4079 { 4080 case NF_KEY_D : 4081 case NF_KEY_DD : 4082 nRet = (nRet << 8) | 'D'; 4083 ++nShift; 4084 break; 4085 case NF_KEY_M : 4086 case NF_KEY_MM : 4087 case NF_KEY_MMM : 4088 case NF_KEY_MMMM : 4089 case NF_KEY_MMMMM : 4090 nRet = (nRet << 8) | 'M'; 4091 ++nShift; 4092 break; 4093 case NF_KEY_YY : 4094 case NF_KEY_YYYY : 4095 case NF_KEY_EC : 4096 case NF_KEY_EEC : 4097 case NF_KEY_R : 4098 case NF_KEY_RR : 4099 nRet = (nRet << 8) | 'Y'; 4100 ++nShift; 4101 break; 4102 } 4103 } 4104 return nRet; 4105 } 4106 4107 4108 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1, 4109 SvNumberformatLimitOps& rOper2, double& rVal2 ) const 4110 { 4111 rOper1 = eOp1; 4112 rOper2 = eOp2; 4113 rVal1 = fLimit1; 4114 rVal2 = fLimit2; 4115 } 4116 4117 4118 Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const 4119 { 4120 if ( nNumFor > 3 ) 4121 return NULL; 4122 4123 return NumFor[nNumFor].GetColor(); 4124 } 4125 4126 4127 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr, 4128 SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep ) 4129 { 4130 if ( eOp != NUMBERFORMAT_OP_NO ) 4131 { 4132 switch ( eOp ) 4133 { 4134 case NUMBERFORMAT_OP_EQ : 4135 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) ); 4136 break; 4137 case NUMBERFORMAT_OP_NE : 4138 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) ); 4139 break; 4140 case NUMBERFORMAT_OP_LT : 4141 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) ); 4142 break; 4143 case NUMBERFORMAT_OP_LE : 4144 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) ); 4145 break; 4146 case NUMBERFORMAT_OP_GT : 4147 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) ); 4148 break; 4149 case NUMBERFORMAT_OP_GE : 4150 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) ); 4151 break; 4152 default: 4153 OSL_ASSERT( "unsupported number format" ); 4154 break; 4155 } 4156 rStr += String( ::rtl::math::doubleToUString( fLimit, 4157 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 4158 rDecSep.GetChar(0), sal_True)); 4159 rStr += ']'; 4160 } 4161 } 4162 4163 4164 String SvNumberformat::GetMappedFormatstring( 4165 const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp, 4166 sal_Bool bDontQuote ) const 4167 { 4168 String aStr; 4169 sal_Bool bDefault[4]; 4170 // 1 subformat matches all if no condition specified, 4171 bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO ); 4172 // with 2 subformats [>=0];[<0] is implied if no condition specified 4173 bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 && 4174 eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 && 4175 eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 ); 4176 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified, 4177 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked. 4178 bDefault[2] = ( !bDefault[0] && !bDefault[1] && 4179 eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 && 4180 eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 ); 4181 sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2]; 4182 // from now on bDefault[] values are used to append empty subformats at the end 4183 bDefault[3] = sal_False; 4184 if ( !bDefaults ) 4185 { // conditions specified 4186 if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO ) 4187 bDefault[0] = bDefault[1] = sal_True; // [];x 4188 else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO && 4189 NumFor[2].GetnAnz() == 0 ) 4190 bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True; // [];[];; 4191 // nothing to do if conditions specified for every subformat 4192 } 4193 else if ( bDefault[0] ) 4194 bDefault[0] = sal_False; // a single unconditional subformat is never delimited 4195 else 4196 { 4197 if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 ) 4198 bDefault[3] = sal_True; // special cases x;x;; and ;x;; 4199 for ( int i=0; i<3 && !bDefault[i]; ++i ) 4200 bDefault[i] = sal_True; 4201 } 4202 int nSem = 0; // needed ';' delimiters 4203 int nSub = 0; // subformats delimited so far 4204 for ( int n=0; n<4; n++ ) 4205 { 4206 if ( n > 0 ) 4207 nSem++; 4208 4209 String aPrefix; 4210 4211 if ( !bDefaults ) 4212 { 4213 switch ( n ) 4214 { 4215 case 0 : 4216 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1, 4217 fLimit1, rLocWrp.getNumDecimalSep() ); 4218 break; 4219 case 1 : 4220 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2, 4221 fLimit2, rLocWrp.getNumDecimalSep() ); 4222 break; 4223 } 4224 } 4225 4226 const String& rColorName = NumFor[n].GetColorName(); 4227 if ( rColorName.Len() ) 4228 { 4229 const NfKeywordTable & rKey = rScan.GetKeywords(); 4230 for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ ) 4231 { 4232 if ( rKey[j] == rColorName ) 4233 { 4234 aPrefix += '['; 4235 aPrefix += rKeywords[j]; 4236 aPrefix += ']'; 4237 break; // for 4238 } 4239 } 4240 } 4241 4242 const SvNumberNatNum& rNum = NumFor[n].GetNatNum(); 4243 // The Thai T NatNum modifier during Xcl export. 4244 if (rNum.IsSet() && rNum.GetNatNum() == 1 && 4245 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") && 4246 MsLangId::getRealLanguage( rNum.GetLang()) == 4247 LANGUAGE_THAI) 4248 { 4249 aPrefix += 't'; // must be lowercase, otherwise taken as literal 4250 } 4251 4252 sal_uInt16 nAnz = NumFor[n].GetnAnz(); 4253 if ( nSem && (nAnz || aPrefix.Len()) ) 4254 { 4255 for ( ; nSem; --nSem ) 4256 aStr += ';'; 4257 for ( ; nSub <= n; ++nSub ) 4258 bDefault[nSub] = sal_False; 4259 } 4260 4261 if ( aPrefix.Len() ) 4262 aStr += aPrefix; 4263 4264 if ( nAnz ) 4265 { 4266 const short* pType = NumFor[n].Info().nTypeArray; 4267 const String* pStr = NumFor[n].Info().sStrArray; 4268 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4269 { 4270 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT ) 4271 { 4272 aStr += rKeywords[pType[j]]; 4273 if( NF_KEY_NNNN == pType[j] ) 4274 aStr += rLocWrp.getLongDateDayOfWeekSep(); 4275 } 4276 else 4277 { 4278 switch ( pType[j] ) 4279 { 4280 case NF_SYMBOLTYPE_DECSEP : 4281 aStr += rLocWrp.getNumDecimalSep(); 4282 break; 4283 case NF_SYMBOLTYPE_THSEP : 4284 aStr += rLocWrp.getNumThousandSep(); 4285 break; 4286 case NF_SYMBOLTYPE_DATESEP : 4287 aStr += rLocWrp.getDateSep(); 4288 break; 4289 case NF_SYMBOLTYPE_TIMESEP : 4290 aStr += rLocWrp.getTimeSep(); 4291 break; 4292 case NF_SYMBOLTYPE_TIME100SECSEP : 4293 aStr += rLocWrp.getTime100SecSep(); 4294 break; 4295 case NF_SYMBOLTYPE_STRING : 4296 if( bDontQuote ) 4297 aStr += pStr[j]; 4298 else if ( pStr[j].Len() == 1 ) 4299 { 4300 aStr += '\\'; 4301 aStr += pStr[j]; 4302 } 4303 else 4304 { 4305 aStr += '"'; 4306 aStr += pStr[j]; 4307 aStr += '"'; 4308 } 4309 break; 4310 default: 4311 aStr += pStr[j]; 4312 } 4313 4314 } 4315 } 4316 } 4317 } 4318 for ( ; nSub<4 && bDefault[nSub]; ++nSub ) 4319 { // append empty subformats 4320 aStr += ';'; 4321 } 4322 return aStr; 4323 } 4324 4325 4326 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum, 4327 sal_Int32 nVal, sal_uInt16 nMinDigits ) const 4328 { 4329 String aStr; 4330 if ( nMinDigits ) 4331 { 4332 if ( nMinDigits == 2 ) 4333 { // speed up the most common case 4334 if ( 0 <= nVal && nVal < 10 ) 4335 { 4336 sal_Unicode* p = aStr.AllocBuffer( 2 ); 4337 *p++ = '0'; 4338 *p = sal_Unicode( '0' + nVal ); 4339 } 4340 else 4341 aStr = String::CreateFromInt32( nVal ); 4342 } 4343 else 4344 { 4345 String aValStr( String::CreateFromInt32( nVal ) ); 4346 if ( aValStr.Len() >= nMinDigits ) 4347 aStr = aValStr; 4348 else 4349 { 4350 aStr.Fill( nMinDigits - aValStr.Len(), '0' ); 4351 aStr += aValStr; 4352 } 4353 } 4354 } 4355 else 4356 aStr = String::CreateFromInt32( nVal ); 4357 ImpTransliterate( aStr, rNum ); 4358 return aStr; 4359 } 4360 4361 4362 void SvNumberformat::ImpTransliterateImpl( String& rStr, 4363 const SvNumberNatNum& rNum ) const 4364 { 4365 com::sun::star::lang::Locale aLocale( 4366 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4367 rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr, 4368 aLocale, rNum.GetNatNum() ); 4369 } 4370 4371 4372 void SvNumberformat::GetNatNumXml( 4373 com::sun::star::i18n::NativeNumberXmlAttributes& rAttr, 4374 sal_uInt16 nNumFor ) const 4375 { 4376 if ( nNumFor <= 3 ) 4377 { 4378 const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum(); 4379 if ( rNum.IsSet() ) 4380 { 4381 com::sun::star::lang::Locale aLocale( 4382 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4383 rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes( 4384 aLocale, rNum.GetNatNum() ); 4385 } 4386 else 4387 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4388 } 4389 else 4390 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4391 } 4392 4393 // static 4394 sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr ) 4395 { 4396 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored) 4397 xub_StrLen nLen = rStr.Len(); 4398 if ( !nLen ) 4399 return sal_False; 4400 const sal_Unicode* const pBeg = rStr.GetBuffer(); 4401 const sal_Unicode* const pEnd = pBeg + nLen; 4402 register const sal_Unicode* p = pBeg; 4403 do 4404 { // Anfang 4405 if ( *p == '-' ) 4406 return sal_True; 4407 } while ( *p == ' ' && ++p < pEnd ); 4408 p = pEnd - 1; 4409 do 4410 { // Ende 4411 if ( *p == '-' ) 4412 return sal_True; 4413 } while ( *p == ' ' && pBeg < --p ); 4414 return sal_False; 4415 } 4416 4417 4418 // static 4419 void SvNumberformat::SetComment( const String& rStr, String& rFormat, 4420 String& rComment ) 4421 { 4422 if ( rComment.Len() ) 4423 { // alten Kommentar aus Formatstring loeschen 4424 //! nicht per EraseComment, der Kommentar muss matchen 4425 String aTmp( '{' ); 4426 aTmp += ' '; 4427 aTmp += rComment; 4428 aTmp += ' '; 4429 aTmp += '}'; 4430 xub_StrLen nCom = 0; 4431 do 4432 { 4433 nCom = rFormat.Search( aTmp, nCom ); 4434 } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) ); 4435 if ( nCom != STRING_NOTFOUND ) 4436 rFormat.Erase( nCom ); 4437 } 4438 if ( rStr.Len() ) 4439 { // neuen Kommentar setzen 4440 rFormat += '{'; 4441 rFormat += ' '; 4442 rFormat += rStr; 4443 rFormat += ' '; 4444 rFormat += '}'; 4445 rComment = rStr; 4446 } 4447 } 4448 4449 4450 // static 4451 void SvNumberformat::EraseCommentBraces( String& rStr ) 4452 { 4453 xub_StrLen nLen = rStr.Len(); 4454 if ( nLen && rStr.GetChar(0) == '{' ) 4455 { 4456 rStr.Erase( 0, 1 ); 4457 --nLen; 4458 } 4459 if ( nLen && rStr.GetChar(0) == ' ' ) 4460 { 4461 rStr.Erase( 0, 1 ); 4462 --nLen; 4463 } 4464 if ( nLen && rStr.GetChar( nLen-1 ) == '}' ) 4465 rStr.Erase( --nLen, 1 ); 4466 if ( nLen && rStr.GetChar( nLen-1 ) == ' ' ) 4467 rStr.Erase( --nLen, 1 ); 4468 } 4469 4470 4471 // static 4472 void SvNumberformat::EraseComment( String& rStr ) 4473 { 4474 register const sal_Unicode* p = rStr.GetBuffer(); 4475 sal_Bool bInString = sal_False; 4476 sal_Bool bEscaped = sal_False; 4477 sal_Bool bFound = sal_False; 4478 xub_StrLen nPos = 0; 4479 while ( !bFound && *p ) 4480 { 4481 switch ( *p ) 4482 { 4483 case '\\' : 4484 bEscaped = !bEscaped; 4485 break; 4486 case '\"' : 4487 if ( !bEscaped ) 4488 bInString = !bInString; 4489 break; 4490 case '{' : 4491 if ( !bEscaped && !bInString ) 4492 { 4493 bFound = sal_True; 4494 nPos = sal::static_int_cast< xub_StrLen >( 4495 p - rStr.GetBuffer()); 4496 } 4497 break; 4498 } 4499 if ( bEscaped && *p != '\\' ) 4500 bEscaped = sal_False; 4501 ++p; 4502 } 4503 if ( bFound ) 4504 rStr.Erase( nPos ); 4505 } 4506 4507 4508 // static 4509 sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos, 4510 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4511 { 4512 xub_StrLen nLen = rStr.Len(); 4513 if ( nPos >= nLen ) 4514 return sal_False; 4515 register const sal_Unicode* p0 = rStr.GetBuffer(); 4516 register const sal_Unicode* p = p0; 4517 register const sal_Unicode* p1 = p0 + nPos; 4518 sal_Bool bQuoted = sal_False; 4519 while ( p <= p1 ) 4520 { 4521 if ( *p == cQuote ) 4522 { 4523 if ( p == p0 ) 4524 bQuoted = sal_True; 4525 else if ( bQuoted ) 4526 { 4527 if ( *(p-1) != cEscIn ) 4528 bQuoted = sal_False; 4529 } 4530 else 4531 { 4532 if ( *(p-1) != cEscOut ) 4533 bQuoted = sal_True; 4534 } 4535 } 4536 p++; 4537 } 4538 return bQuoted; 4539 } 4540 4541 4542 // static 4543 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos, 4544 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4545 { 4546 xub_StrLen nLen = rStr.Len(); 4547 if ( nPos >= nLen ) 4548 return STRING_NOTFOUND; 4549 if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) ) 4550 { 4551 if ( rStr.GetChar( nPos ) == cQuote ) 4552 return nPos; // schliessendes cQuote 4553 return STRING_NOTFOUND; 4554 } 4555 register const sal_Unicode* p0 = rStr.GetBuffer(); 4556 register const sal_Unicode* p = p0 + nPos; 4557 register const sal_Unicode* p1 = p0 + nLen; 4558 while ( p < p1 ) 4559 { 4560 if ( *p == cQuote && p > p0 && *(p-1) != cEscIn ) 4561 return sal::static_int_cast< xub_StrLen >(p - p0); 4562 p++; 4563 } 4564 return nLen; // String Ende 4565 } 4566 4567 4568 sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const 4569 { 4570 sal_uInt16 nCnt = 0; 4571 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 4572 short const * const pType = NumFor[nNumFor].Info().nTypeArray; 4573 for ( sal_uInt16 j=0; j<nAnz; ++j ) 4574 { 4575 switch ( pType[j] ) 4576 { 4577 case NF_SYMBOLTYPE_STRING: 4578 case NF_SYMBOLTYPE_CURRENCY: 4579 case NF_SYMBOLTYPE_DATESEP: 4580 case NF_SYMBOLTYPE_TIMESEP: 4581 case NF_SYMBOLTYPE_TIME100SECSEP: 4582 case NF_SYMBOLTYPE_PERCENT: 4583 ++nCnt; 4584 break; 4585 } 4586 } 4587 return nCnt; 4588 } 4589 4590