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 sal_Bool IsSingleSymbol(String& rString, xub_StrLen nPos){ 1138 sal_Bool ret = sal_False; 1139 while(nPos > 0){ 1140 if(rString.GetChar(nPos) == '*' || rString.GetChar(nPos) == '\\' || rString.GetChar(nPos) == '_'){ 1141 ret = !ret; 1142 nPos--; 1143 } 1144 else 1145 return ret; 1146 } 1147 return ret; 1148 } 1149 1150 short SvNumberformat::ImpNextSymbol(String& rString, 1151 xub_StrLen& nPos, 1152 String& sSymbol) 1153 { 1154 short eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1155 sal_Unicode cToken; 1156 sal_Unicode cLetter = ' '; // Zwischenergebnis 1157 xub_StrLen nLen = rString.Len(); 1158 ScanState eState = SsStart; 1159 sSymbol.Erase(); 1160 const NfKeywordTable & rKeywords = rScan.GetKeywords(); 1161 while (nPos < nLen && eState != SsStop) 1162 { 1163 cToken = rString.GetChar(nPos); 1164 nPos++; 1165 switch (eState) 1166 { 1167 case SsStart: 1168 { 1169 if (cToken == '[') 1170 { 1171 eState = SsGetBracketed; 1172 sSymbol += cToken; 1173 } 1174 else if (cToken == ';') 1175 { 1176 eState = SsGetString; 1177 nPos--; 1178 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1179 } 1180 else if (cToken == ']') 1181 { 1182 eState = SsStop; 1183 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1184 } 1185 else if (cToken == ' ') // Skip Blanks 1186 { 1187 rString.Erase(nPos-1,1); 1188 nPos--; 1189 nLen--; 1190 } 1191 else 1192 { 1193 sSymbol += cToken; 1194 eState = SsGetString; 1195 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1196 } 1197 } 1198 break; 1199 case SsGetBracketed: 1200 { 1201 switch (cToken) 1202 { 1203 case '<': 1204 case '>': 1205 case '=': 1206 { 1207 sSymbol.EraseAllChars('['); 1208 sSymbol += cToken; 1209 cLetter = cToken; 1210 eState = SsGetCon; 1211 switch (cToken) 1212 { 1213 case '<': eSymbolType = NUMBERFORMAT_OP_LT; break; 1214 case '>': eSymbolType = NUMBERFORMAT_OP_GT; break; 1215 case '=': eSymbolType = NUMBERFORMAT_OP_EQ; break; 1216 default: break; 1217 } 1218 } 1219 break; 1220 case ' ': 1221 { 1222 rString.Erase(nPos-1,1); 1223 nPos--; 1224 nLen--; 1225 } 1226 break; 1227 case '$' : 1228 { 1229 if ( rString.GetChar(nPos) == '-' ) 1230 { // [$-xxx] locale 1231 sSymbol.EraseAllChars('['); 1232 eSymbolType = BRACKET_SYMBOLTYPE_LOCALE; 1233 eState = SsGetPrefix; 1234 } 1235 else 1236 { // currency as of SV_NUMBERFORMATTER_VERSION_NEW_CURR 1237 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1238 eState = SsGetString; 1239 } 1240 sSymbol += cToken; 1241 } 1242 break; 1243 case '~' : 1244 { // calendarID as of SV_NUMBERFORMATTER_VERSION_CALENDAR 1245 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1246 sSymbol += cToken; 1247 eState = SsGetString; 1248 } 1249 break; 1250 default: 1251 { 1252 static const String aNatNum( RTL_CONSTASCII_USTRINGPARAM( "NATNUM" ) ); 1253 static const String aDBNum( RTL_CONSTASCII_USTRINGPARAM( "DBNUM" ) ); 1254 String aUpperNatNum( rChrCls().toUpper( rString, nPos-1, aNatNum.Len() ) ); 1255 String aUpperDBNum( rChrCls().toUpper( rString, nPos-1, aDBNum.Len() ) ); 1256 sal_Unicode cUpper = aUpperNatNum.GetChar(0); 1257 sal_Int32 nNatNumNum = rString.Copy( nPos-1+aNatNum.Len() ).ToInt32(); 1258 sal_Unicode cDBNum = rString.GetChar( nPos-1+aDBNum.Len() ); 1259 if ( aUpperNatNum == aNatNum && 0 <= nNatNumNum && nNatNumNum <= 19 ) 1260 { 1261 sSymbol.EraseAllChars('['); 1262 sSymbol += rString.Copy( --nPos, aNatNum.Len()+1 ); 1263 nPos += aNatNum.Len()+1; 1264 //! SymbolType is negative 1265 eSymbolType = (short) (BRACKET_SYMBOLTYPE_NATNUM0 - nNatNumNum); 1266 eState = SsGetPrefix; 1267 } 1268 else if ( aUpperDBNum == aDBNum && '1' <= cDBNum && cDBNum <= '9' ) 1269 { 1270 sSymbol.EraseAllChars('['); 1271 sSymbol += rString.Copy( --nPos, aDBNum.Len()+1 ); 1272 nPos += aDBNum.Len()+1; 1273 //! SymbolType is negative 1274 eSymbolType = sal::static_int_cast< short >( 1275 BRACKET_SYMBOLTYPE_DBNUM1 - (cDBNum - '1')); 1276 eState = SsGetPrefix; 1277 } 1278 else if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H 1279 cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M 1280 cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S 1281 { 1282 sSymbol += cToken; 1283 eState = SsGetTime; 1284 cLetter = cToken; 1285 } 1286 else 1287 { 1288 sSymbol.EraseAllChars('['); 1289 sSymbol += cToken; 1290 eSymbolType = BRACKET_SYMBOLTYPE_COLOR; 1291 eState = SsGetPrefix; 1292 } 1293 } 1294 break; 1295 } 1296 } 1297 break; 1298 case SsGetString: 1299 { 1300 if (cToken == ';' && (nPos>=2) &&!IsSingleSymbol(rString, nPos-2)) 1301 { 1302 eState = SsStop; 1303 } 1304 else 1305 sSymbol += cToken; 1306 } 1307 break; 1308 case SsGetTime: 1309 { 1310 if (cToken == ']') 1311 { 1312 sSymbol += cToken; 1313 eState = SsGetString; 1314 eSymbolType = BRACKET_SYMBOLTYPE_FORMAT; 1315 } 1316 else 1317 { 1318 sal_Unicode cUpper = rChrCls().toUpper( rString, nPos-1, 1 ).GetChar(0); 1319 if (cUpper == rKeywords[NF_KEY_H].GetChar(0) || // H 1320 cUpper == rKeywords[NF_KEY_MI].GetChar(0) || // M 1321 cUpper == rKeywords[NF_KEY_S].GetChar(0) ) // S 1322 { 1323 if (cLetter == cToken) 1324 { 1325 sSymbol += cToken; 1326 cLetter = ' '; 1327 } 1328 else 1329 { 1330 sSymbol.EraseAllChars('['); 1331 sSymbol += cToken; 1332 eState = SsGetPrefix; 1333 } 1334 } 1335 else 1336 { 1337 sSymbol.EraseAllChars('['); 1338 sSymbol += cToken; 1339 eSymbolType = BRACKET_SYMBOLTYPE_COLOR; 1340 eState = SsGetPrefix; 1341 } 1342 } 1343 } 1344 break; 1345 case SsGetCon: 1346 { 1347 switch (cToken) 1348 { 1349 case '<': 1350 { 1351 eState = SsStop; 1352 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1353 } 1354 break; 1355 case '>': 1356 { 1357 if (cLetter == '<') 1358 { 1359 sSymbol += cToken; 1360 cLetter = ' '; 1361 eState = SsStop; 1362 eSymbolType = NUMBERFORMAT_OP_NE; 1363 } 1364 else 1365 { 1366 eState = SsStop; 1367 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1368 } 1369 } 1370 break; 1371 case '=': 1372 { 1373 if (cLetter == '<') 1374 { 1375 sSymbol += cToken; 1376 cLetter = ' '; 1377 eSymbolType = NUMBERFORMAT_OP_LE; 1378 } 1379 else if (cLetter == '>') 1380 { 1381 sSymbol += cToken; 1382 cLetter = ' '; 1383 eSymbolType = NUMBERFORMAT_OP_GE; 1384 } 1385 else 1386 { 1387 eState = SsStop; 1388 eSymbolType = BRACKET_SYMBOLTYPE_ERROR; 1389 } 1390 } 1391 break; 1392 case ' ': 1393 { 1394 rString.Erase(nPos-1,1); 1395 nPos--; 1396 nLen--; 1397 } 1398 break; 1399 default: 1400 { 1401 eState = SsStop; 1402 nPos--; 1403 } 1404 break; 1405 } 1406 } 1407 break; 1408 case SsGetPrefix: 1409 { 1410 if (cToken == ']') 1411 eState = SsStop; 1412 else 1413 sSymbol += cToken; 1414 } 1415 break; 1416 default: 1417 break; 1418 } // of switch 1419 } // of while 1420 1421 return eSymbolType; 1422 } 1423 1424 NfHackConversion SvNumberformat::Load( SvStream& rStream, 1425 ImpSvNumMultipleReadHeader& rHdr, SvNumberFormatter* pHackConverter, 1426 ImpSvNumberInputScan& rISc ) 1427 { 1428 rHdr.StartEntry(); 1429 sal_uInt16 nOp1, nOp2; 1430 SvNumberformat::LoadString( rStream, sFormatstring ); 1431 rStream >> eType >> fLimit1 >> fLimit2 1432 >> nOp1 >> nOp2 >> bStandard >> bIsUsed; 1433 NfHackConversion eHackConversion = NF_CONVERT_NONE; 1434 sal_Bool bOldConvert = sal_False; 1435 LanguageType eOldTmpLang = 0; 1436 LanguageType eOldNewLang = 0; 1437 if ( pHackConverter ) 1438 { // werden nur hierbei gebraucht 1439 bOldConvert = rScan.GetConvertMode(); 1440 eOldTmpLang = rScan.GetTmpLnge(); 1441 eOldNewLang = rScan.GetNewLnge(); 1442 } 1443 String aLoadedColorName; 1444 for (sal_uInt16 i = 0; i < 4; i++) 1445 { 1446 NumFor[i].Load( rStream, rScan, aLoadedColorName ); 1447 if ( pHackConverter && eHackConversion == NF_CONVERT_NONE ) 1448 { 1449 //! HACK! ER 29.07.97 13:52 1450 // leider wurde nicht gespeichert, was SYSTEM on Save wirklich war :-/ 1451 // aber immerhin wird manchmal fuer einen Entry FARBE oder COLOR gespeichert.. 1452 // System-German FARBE nach System-xxx COLOR umsetzen und vice versa, 1453 //! geht davon aus, dass onSave nur GERMAN und ENGLISH KeyWords in 1454 //! ImpSvNumberformatScan existierten 1455 if ( aLoadedColorName.Len() && !NumFor[i].GetColor() 1456 && aLoadedColorName != rScan.GetColorString() ) 1457 { 1458 if ( rScan.GetColorString().EqualsAscii( "FARBE" ) ) 1459 { // English -> German 1460 eHackConversion = NF_CONVERT_ENGLISH_GERMAN; 1461 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_ENGLISH_US ); 1462 rScan.SetConvertMode( LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN ); 1463 } 1464 else 1465 { // German -> English 1466 eHackConversion = NF_CONVERT_GERMAN_ENGLISH; 1467 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_GERMAN ); 1468 rScan.SetConvertMode( LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US ); 1469 } 1470 String aColorName = NumFor[i].GetColorName(); 1471 const Color* pColor = rScan.GetColor( aColorName ); 1472 if ( !pColor && aLoadedColorName == aColorName ) 1473 eHackConversion = NF_CONVERT_NONE; 1474 rScan.GetNumberformatter()->ChangeIntl( LANGUAGE_SYSTEM ); 1475 rScan.SetConvertMode( eOldTmpLang, eOldNewLang ); 1476 rScan.SetConvertMode( bOldConvert ); 1477 } 1478 } 1479 } 1480 eOp1 = (SvNumberformatLimitOps) nOp1; 1481 eOp2 = (SvNumberformatLimitOps) nOp2; 1482 String aComment; // wird nach dem NewCurrency-Geraffel richtig gesetzt 1483 if ( rHdr.BytesLeft() ) 1484 { // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD 1485 SvNumberformat::LoadString( rStream, aComment ); 1486 rStream >> nNewStandardDefined; 1487 } 1488 1489 xub_StrLen nNewCurrencyEnd = STRING_NOTFOUND; 1490 sal_Bool bNewCurrencyComment = ( aComment.GetChar(0) == cNewCurrencyMagic && 1491 (nNewCurrencyEnd = aComment.Search( cNewCurrencyMagic, 1 )) != STRING_NOTFOUND ); 1492 sal_Bool bNewCurrencyLoaded = sal_False; 1493 sal_Bool bNewCurrency = sal_False; 1494 1495 sal_Bool bGoOn = sal_True; 1496 while ( rHdr.BytesLeft() && bGoOn ) 1497 { // as of SV_NUMBERFORMATTER_VERSION_NEW_CURR 1498 sal_uInt16 nId; 1499 rStream >> nId; 1500 switch ( nId ) 1501 { 1502 case nNewCurrencyVersionId : 1503 { 1504 bNewCurrencyLoaded = sal_True; 1505 rStream >> bNewCurrency; 1506 if ( bNewCurrency ) 1507 { 1508 for ( sal_uInt16 j=0; j<4; j++ ) 1509 { 1510 NumFor[j].LoadNewCurrencyMap( rStream ); 1511 } 1512 } 1513 } 1514 break; 1515 case nNewStandardFlagVersionId : 1516 rStream >> bStandard; // the real standard flag 1517 break; 1518 default: 1519 DBG_ERRORFILE( "SvNumberformat::Load: unknown header bytes left nId" ); 1520 bGoOn = sal_False; // stop reading unknown stream left over of newer versions 1521 // Would be nice to have multiple read/write headers instead 1522 // but old versions wouldn't know it, TLOT. 1523 } 1524 } 1525 rHdr.EndEntry(); 1526 1527 if ( bNewCurrencyLoaded ) 1528 { 1529 if ( bNewCurrency && bNewCurrencyComment ) 1530 { // original Formatstring und Kommentar wiederherstellen 1531 sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 ); 1532 aComment.Erase( 0, nNewCurrencyEnd+1 ); 1533 } 1534 } 1535 else if ( bNewCurrencyComment ) 1536 { // neu, aber mit Version vor SV_NUMBERFORMATTER_VERSION_NEW_CURR gespeichert 1537 // original Formatstring und Kommentar wiederherstellen 1538 sFormatstring = aComment.Copy( 1, nNewCurrencyEnd-1 ); 1539 aComment.Erase( 0, nNewCurrencyEnd+1 ); 1540 // Zustaende merken 1541 short nDefined = ( eType & NUMBERFORMAT_DEFINED ); 1542 sal_uInt16 nNewStandard = nNewStandardDefined; 1543 // neu parsen etc. 1544 String aStr( sFormatstring ); 1545 xub_StrLen nCheckPos = 0; 1546 SvNumberformat* pFormat = new SvNumberformat( aStr, &rScan, &rISc, 1547 nCheckPos, eLnge, bStandard ); 1548 DBG_ASSERT( !nCheckPos, "SvNumberformat::Load: NewCurrencyRescan nCheckPos" ); 1549 ImpCopyNumberformat( *pFormat ); 1550 delete pFormat; 1551 // Zustaende wiederherstellen 1552 eType |= nDefined; 1553 if ( nNewStandard ) 1554 SetNewStandardDefined( nNewStandard ); 1555 } 1556 SetComment( aComment ); 1557 1558 if ( eHackConversion != NF_CONVERT_NONE ) 1559 { //! und weiter mit dem HACK! 1560 switch ( eHackConversion ) 1561 { 1562 case NF_CONVERT_ENGLISH_GERMAN : 1563 ConvertLanguage( *pHackConverter, 1564 LANGUAGE_ENGLISH_US, LANGUAGE_GERMAN, sal_True ); 1565 break; 1566 case NF_CONVERT_GERMAN_ENGLISH : 1567 ConvertLanguage( *pHackConverter, 1568 LANGUAGE_GERMAN, LANGUAGE_ENGLISH_US, sal_True ); 1569 break; 1570 default: 1571 DBG_ERRORFILE( "SvNumberformat::Load: eHackConversion unknown" ); 1572 } 1573 } 1574 return eHackConversion; 1575 } 1576 1577 void SvNumberformat::ConvertLanguage( SvNumberFormatter& rConverter, 1578 LanguageType eConvertFrom, LanguageType eConvertTo, sal_Bool bSystem ) 1579 { 1580 xub_StrLen nCheckPos; 1581 sal_uInt32 nKey; 1582 short nType = eType; 1583 String aFormatString( sFormatstring ); 1584 if ( bSystem ) 1585 rConverter.PutandConvertEntrySystem( aFormatString, nCheckPos, nType, 1586 nKey, eConvertFrom, eConvertTo ); 1587 else 1588 rConverter.PutandConvertEntry( aFormatString, nCheckPos, nType, 1589 nKey, eConvertFrom, eConvertTo ); 1590 const SvNumberformat* pFormat = rConverter.GetEntry( nKey ); 1591 DBG_ASSERT( pFormat, "SvNumberformat::ConvertLanguage: Conversion ohne Format" ); 1592 if ( pFormat ) 1593 { 1594 ImpCopyNumberformat( *pFormat ); 1595 // aus Formatter/Scanner uebernommene Werte zuruecksetzen 1596 if ( bSystem ) 1597 eLnge = LANGUAGE_SYSTEM; 1598 // pColor zeigt noch auf Tabelle in temporaerem Formatter/Scanner 1599 for ( sal_uInt16 i = 0; i < 4; i++ ) 1600 { 1601 String aColorName = NumFor[i].GetColorName(); 1602 Color* pColor = rScan.GetColor( aColorName ); 1603 NumFor[i].SetColor( pColor, aColorName ); 1604 } 1605 } 1606 } 1607 1608 1609 // static 1610 void SvNumberformat::LoadString( SvStream& rStream, String& rStr ) 1611 { 1612 CharSet eStream = rStream.GetStreamCharSet(); 1613 ByteString aStr; 1614 rStream.ReadByteString( aStr ); 1615 sal_Char cStream = NfCurrencyEntry::GetEuroSymbol( eStream ); 1616 if ( aStr.Search( cStream ) == STRING_NOTFOUND ) 1617 { // simple conversion to unicode 1618 rStr = UniString( aStr, eStream ); 1619 } 1620 else 1621 { 1622 sal_Unicode cTarget = NfCurrencyEntry::GetEuroSymbol(); 1623 register const sal_Char* p = aStr.GetBuffer(); 1624 register const sal_Char* const pEnd = p + aStr.Len(); 1625 register sal_Unicode* pUni = rStr.AllocBuffer( aStr.Len() ); 1626 while ( p < pEnd ) 1627 { 1628 if ( *p == cStream ) 1629 *pUni = cTarget; 1630 else 1631 *pUni = ByteString::ConvertToUnicode( *p, eStream ); 1632 p++; 1633 pUni++; 1634 } 1635 *pUni = 0; 1636 } 1637 } 1638 1639 1640 void SvNumberformat::Save( SvStream& rStream, ImpSvNumMultipleWriteHeader& rHdr ) const 1641 { 1642 String aFormatstring( sFormatstring ); 1643 String aComment( sComment ); 1644 #if NF_COMMENT_IN_FORMATSTRING 1645 // der Kommentar im Formatstring wird nicht gespeichert, um in alten Versionen 1646 // nicht ins schleudern zu kommen und spaeter getrennte Verarbeitung 1647 // (z.B. im Dialog) zu ermoeglichen 1648 SetComment( "", aFormatstring, aComment ); 1649 #endif 1650 1651 sal_Bool bNewCurrency = HasNewCurrency(); 1652 if ( bNewCurrency ) 1653 { // SV_NUMBERFORMATTER_VERSION_NEW_CURR im Kommentar speichern 1654 aComment.Insert( cNewCurrencyMagic, 0 ); 1655 aComment.Insert( cNewCurrencyMagic, 0 ); 1656 aComment.Insert( aFormatstring, 1 ); 1657 Build50Formatstring( aFormatstring ); // alten Formatstring generieren 1658 } 1659 1660 // old SO5 versions do behave strange (no output) if standard flag is set 1661 // on formats not prepared for it (not having the following exact types) 1662 sal_Bool bOldStandard = bStandard; 1663 if ( bOldStandard ) 1664 { 1665 switch ( eType ) 1666 { 1667 case NUMBERFORMAT_NUMBER : 1668 case NUMBERFORMAT_DATE : 1669 case NUMBERFORMAT_TIME : 1670 case NUMBERFORMAT_DATETIME : 1671 case NUMBERFORMAT_PERCENT : 1672 case NUMBERFORMAT_SCIENTIFIC : 1673 // ok to save 1674 break; 1675 default: 1676 bOldStandard = sal_False; 1677 } 1678 } 1679 1680 rHdr.StartEntry(); 1681 rStream.WriteByteString( aFormatstring, rStream.GetStreamCharSet() ); 1682 rStream << eType << fLimit1 << fLimit2 << (sal_uInt16) eOp1 << (sal_uInt16) eOp2 1683 << bOldStandard << bIsUsed; 1684 for (sal_uInt16 i = 0; i < 4; i++) 1685 NumFor[i].Save(rStream); 1686 // ab SV_NUMBERFORMATTER_VERSION_NEWSTANDARD 1687 rStream.WriteByteString( aComment, rStream.GetStreamCharSet() ); 1688 rStream << nNewStandardDefined; 1689 // ab SV_NUMBERFORMATTER_VERSION_NEW_CURR 1690 rStream << nNewCurrencyVersionId; 1691 rStream << bNewCurrency; 1692 if ( bNewCurrency ) 1693 { 1694 for ( sal_uInt16 j=0; j<4; j++ ) 1695 { 1696 NumFor[j].SaveNewCurrencyMap( rStream ); 1697 } 1698 } 1699 1700 // the real standard flag to load with versions >638 if different 1701 if ( bStandard != bOldStandard ) 1702 { 1703 rStream << nNewStandardFlagVersionId; 1704 rStream << bStandard; 1705 } 1706 1707 rHdr.EndEntry(); 1708 } 1709 1710 1711 sal_Bool SvNumberformat::HasNewCurrency() const 1712 { 1713 for ( sal_uInt16 j=0; j<4; j++ ) 1714 { 1715 if ( NumFor[j].HasNewCurrency() ) 1716 return sal_True; 1717 } 1718 return sal_False; 1719 } 1720 1721 1722 sal_Bool SvNumberformat::GetNewCurrencySymbol( String& rSymbol, 1723 String& rExtension ) const 1724 { 1725 for ( sal_uInt16 j=0; j<4; j++ ) 1726 { 1727 if ( NumFor[j].GetNewCurrencySymbol( rSymbol, rExtension ) ) 1728 return sal_True; 1729 } 1730 rSymbol.Erase(); 1731 rExtension.Erase(); 1732 return sal_False; 1733 } 1734 1735 1736 // static 1737 String SvNumberformat::StripNewCurrencyDelimiters( const String& rStr, 1738 sal_Bool bQuoteSymbol ) 1739 { 1740 String aTmp; 1741 xub_StrLen nStartPos, nPos, nLen; 1742 nLen = rStr.Len(); 1743 nStartPos = 0; 1744 while ( (nPos = rStr.SearchAscii( "[$", nStartPos )) != STRING_NOTFOUND ) 1745 { 1746 xub_StrLen nEnd; 1747 if ( (nEnd = GetQuoteEnd( rStr, nPos )) < nLen ) 1748 { 1749 aTmp += rStr.Copy( nStartPos, ++nEnd - nStartPos ); 1750 nStartPos = nEnd; 1751 } 1752 else 1753 { 1754 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1755 nStartPos = nPos + 2; 1756 xub_StrLen nDash; 1757 nEnd = nStartPos - 1; 1758 do 1759 { 1760 nDash = rStr.Search( '-', ++nEnd ); 1761 } while ( (nEnd = GetQuoteEnd( rStr, nDash )) < nLen ); 1762 xub_StrLen nClose; 1763 nEnd = nStartPos - 1; 1764 do 1765 { 1766 nClose = rStr.Search( ']', ++nEnd ); 1767 } while ( (nEnd = GetQuoteEnd( rStr, nClose )) < nLen ); 1768 nPos = ( nDash < nClose ? nDash : nClose ); 1769 if ( !bQuoteSymbol || rStr.GetChar( nStartPos ) == '"' ) 1770 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1771 else 1772 { 1773 aTmp += '"'; 1774 aTmp += rStr.Copy( nStartPos, nPos - nStartPos ); 1775 aTmp += '"'; 1776 } 1777 nStartPos = nClose + 1; 1778 } 1779 } 1780 if ( nLen > nStartPos ) 1781 aTmp += rStr.Copy( nStartPos, nLen - nStartPos ); 1782 return aTmp; 1783 } 1784 1785 1786 void SvNumberformat::Build50Formatstring( String& rStr ) const 1787 { 1788 rStr = StripNewCurrencyDelimiters( sFormatstring, sal_True ); 1789 } 1790 1791 1792 void SvNumberformat::ImpGetOutputStandard(double& fNumber, String& OutString) 1793 { 1794 sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); 1795 1796 if ( fabs(fNumber) > 1.0E15 ) // #58531# war E16 1797 { 1798 nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals 1799 OutString = ::rtl::math::doubleToUString( fNumber, 1800 rtl_math_StringFormat_E, nStandardPrec /*2*/, 1801 GetFormatter().GetNumDecimalSep().GetChar(0)); 1802 } 1803 else 1804 ImpGetOutputStdToPrecision(fNumber, OutString, nStandardPrec); 1805 } 1806 1807 void SvNumberformat::ImpGetOutputStdToPrecision(double& rNumber, String& rOutString, sal_uInt16 nPrecision) const 1808 { 1809 // Make sure the precision doesn't go over the maximum allowable precision. 1810 nPrecision = ::std::min(UPPER_PRECISION, nPrecision); 1811 1812 #if 0 1813 { 1814 // debugger test case for ANSI standard correctness 1815 ::rtl::OUString aTest; 1816 // expect 0.00123 OK 1817 aTest = ::rtl::math::doubleToUString( 0.001234567, 1818 rtl_math_StringFormat_G, 3, '.', sal_True ); 1819 // expect 123 OK 1820 aTest = ::rtl::math::doubleToUString( 123.4567, 1821 rtl_math_StringFormat_G, 3, '.', sal_True ); 1822 // expect 123.5 OK 1823 aTest = ::rtl::math::doubleToUString( 123.4567, 1824 rtl_math_StringFormat_G, 4, '.', sal_True ); 1825 // expect 1e+03 (as 999.6 rounded to 3 significant digits results in 1826 // 1000 with an exponent equal to significant digits) 1827 // Currently (24-Jan-2003) we do fail in this case and output 1000 1828 // instead, negligible. 1829 aTest = ::rtl::math::doubleToUString( 999.6, 1830 rtl_math_StringFormat_G, 3, '.', sal_True ); 1831 // expect what? result is 1.2e+004 1832 aTest = ::rtl::math::doubleToUString( 12345.6789, 1833 rtl_math_StringFormat_G, -3, '.', sal_True ); 1834 } 1835 #endif 1836 1837 // We decided to strip trailing zeros unconditionally, since binary 1838 // double-precision rounding error makes it impossible to determine e.g. 1839 // whether 844.10000000000002273737 is what the user has typed, or the 1840 // user has typed 844.1 but IEEE 754 represents it that way internally. 1841 1842 rOutString = ::rtl::math::doubleToUString( rNumber, 1843 rtl_math_StringFormat_F, nPrecision /*2*/, 1844 GetFormatter().GetNumDecimalSep().GetChar(0), true ); 1845 if (rOutString.GetChar(0) == '-' && 1846 rOutString.GetTokenCount('0') == rOutString.Len()) 1847 rOutString.EraseLeadingChars('-'); // nicht -0 1848 1849 ImpTransliterate( rOutString, NumFor[0].GetNatNum() ); 1850 } 1851 1852 void SvNumberformat::ImpGetOutputInputLine(double fNumber, String& OutString) 1853 { 1854 sal_Bool bModified = sal_False; 1855 if ( (eType & NUMBERFORMAT_PERCENT) && (fabs(fNumber) < _D_MAX_D_BY_100)) 1856 { 1857 if (fNumber == 0.0) 1858 { 1859 OutString.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "0%" ) ); 1860 return; 1861 } 1862 fNumber *= 100; 1863 bModified = sal_True; 1864 } 1865 1866 if (fNumber == 0.0) 1867 { 1868 OutString = '0'; 1869 return; 1870 } 1871 1872 OutString = ::rtl::math::doubleToUString( fNumber, 1873 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 1874 GetFormatter().GetNumDecimalSep().GetChar(0), sal_True ); 1875 1876 if ( eType & NUMBERFORMAT_PERCENT && bModified) 1877 OutString += '%'; 1878 return; 1879 } 1880 1881 short SvNumberformat::ImpCheckCondition(double& fNumber, 1882 double& fLimit, 1883 SvNumberformatLimitOps eOp) 1884 { 1885 switch(eOp) 1886 { 1887 case NUMBERFORMAT_OP_NO: return -1; 1888 case NUMBERFORMAT_OP_EQ: return (short) (fNumber == fLimit); 1889 case NUMBERFORMAT_OP_NE: return (short) (fNumber != fLimit); 1890 case NUMBERFORMAT_OP_LT: return (short) (fNumber < fLimit); 1891 case NUMBERFORMAT_OP_LE: return (short) (fNumber <= fLimit); 1892 case NUMBERFORMAT_OP_GT: return (short) (fNumber > fLimit); 1893 case NUMBERFORMAT_OP_GE: return (short) (fNumber >= fLimit); 1894 default: return -1; 1895 } 1896 } 1897 1898 sal_Bool SvNumberformat::GetOutputString(String& sString, 1899 String& OutString, 1900 Color** ppColor) 1901 { 1902 OutString.Erase(); 1903 sal_uInt16 nIx; 1904 if (eType & NUMBERFORMAT_TEXT) 1905 nIx = 0; 1906 else if (NumFor[3].GetnAnz() > 0) 1907 nIx = 3; 1908 else 1909 { 1910 *ppColor = NULL; // no change of color 1911 return sal_False; 1912 } 1913 *ppColor = NumFor[nIx].GetColor(); 1914 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 1915 if (rInfo.eScannedType == NUMBERFORMAT_TEXT) 1916 { 1917 sal_Bool bRes = sal_False; 1918 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 1919 for (sal_uInt16 i = 0; i < nAnz; i++) 1920 { 1921 switch (rInfo.nTypeArray[i]) 1922 { 1923 case NF_SYMBOLTYPE_STAR: 1924 if( bStarFlag ) 1925 { 1926 OutString += (sal_Unicode) 0x1B; 1927 OutString += rInfo.sStrArray[i].GetChar(1); 1928 bRes = sal_True; 1929 } 1930 break; 1931 case NF_SYMBOLTYPE_BLANK: 1932 InsertBlanks( OutString, OutString.Len(), 1933 rInfo.sStrArray[i].GetChar(1) ); 1934 break; 1935 case NF_KEY_GENERAL : // #77026# "General" is the same as "@" 1936 case NF_SYMBOLTYPE_DEL : 1937 OutString += sString; 1938 break; 1939 default: 1940 OutString += rInfo.sStrArray[i]; 1941 } 1942 } 1943 return bRes; 1944 } 1945 return sal_False; 1946 } 1947 /* 1948 void SvNumberformat::GetNextFareyNumber(sal_uLong nPrec, sal_uLong x0, sal_uLong x1, 1949 sal_uLong y0, sal_uLong y1, 1950 sal_uLong& x2,sal_uLong& y2) 1951 { 1952 x2 = ((y0+nPrec)/y1)*x1 - x0; 1953 y2 = ((y0+nPrec)/y1)*y1 - y0; 1954 } 1955 */ 1956 sal_uLong SvNumberformat::ImpGGT(sal_uLong x, sal_uLong y) 1957 { 1958 if (y == 0) 1959 return x; 1960 else 1961 { 1962 sal_uLong z = x%y; 1963 while (z) 1964 { 1965 x = y; 1966 y = z; 1967 z = x%y; 1968 } 1969 return y; 1970 } 1971 } 1972 1973 sal_uLong SvNumberformat::ImpGGTRound(sal_uLong x, sal_uLong y) 1974 { 1975 if (y == 0) 1976 return x; 1977 else 1978 { 1979 sal_uLong z = x%y; 1980 while ((double)z/(double)y > D_EPS) 1981 { 1982 x = y; 1983 y = z; 1984 z = x%y; 1985 } 1986 return y; 1987 } 1988 } 1989 1990 namespace { 1991 1992 void lcl_GetOutputStringScientific( 1993 double fNumber, sal_uInt16 nCharCount, const SvNumberFormatter& rFormatter, String& rOutString) 1994 { 1995 bool bSign = ::rtl::math::isSignBitSet(fNumber); 1996 1997 // 1.000E+015 (one digit and the decimal point, and the five chars for the exponential part, totalling 7). 1998 sal_uInt16 nPrec = nCharCount > 7 ? nCharCount - 7 : 0; 1999 if (nPrec && bSign) 2000 // Make room for the negative sign. 2001 --nPrec; 2002 2003 nPrec = ::std::min(nPrec, static_cast<sal_uInt16>(14)); // limit to 14 decimals. 2004 2005 rOutString = ::rtl::math::doubleToUString( 2006 fNumber, rtl_math_StringFormat_E, nPrec, rFormatter.GetNumDecimalSep().GetChar(0)); 2007 } 2008 2009 } 2010 2011 bool SvNumberformat::GetOutputString(double fNumber, sal_uInt16 nCharCount, String& rOutString) const 2012 { 2013 using namespace std; 2014 2015 if (eType != NUMBERFORMAT_NUMBER) 2016 return false; 2017 2018 double fTestNum = fNumber; 2019 bool bSign = ::rtl::math::isSignBitSet(fTestNum); 2020 if (bSign) 2021 fTestNum = -fTestNum; 2022 2023 if (fTestNum < EXP_LOWER_BOUND) 2024 { 2025 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2026 return true; 2027 } 2028 2029 double fExp = log10(fTestNum); 2030 // Values < 1.0 always have one digit before the decimal point. 2031 sal_uInt16 nDigitPre = fExp >= 0.0 ? static_cast<sal_uInt16>(ceil(fExp)) : 1; 2032 2033 if (nDigitPre > 15) 2034 { 2035 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2036 return true; 2037 } 2038 2039 sal_uInt16 nPrec = nCharCount >= nDigitPre ? nCharCount - nDigitPre : 0; 2040 if (nPrec && bSign) 2041 // Subtract the negative sign. 2042 --nPrec; 2043 if (nPrec) 2044 // Subtract the decimal point. 2045 --nPrec; 2046 2047 ImpGetOutputStdToPrecision(fNumber, rOutString, nPrec); 2048 if (rOutString.Len() > nCharCount) 2049 // String still wider than desired. Switch to scientific notation. 2050 lcl_GetOutputStringScientific(fNumber, nCharCount, GetFormatter(), rOutString); 2051 2052 return true; 2053 } 2054 2055 sal_Bool SvNumberformat::GetOutputString(double fNumber, 2056 String& OutString, 2057 Color** ppColor) 2058 { 2059 sal_Bool bRes = sal_False; 2060 OutString.Erase(); // alles loeschen 2061 *ppColor = NULL; // keine Farbaenderung 2062 if (eType & NUMBERFORMAT_LOGICAL) 2063 { 2064 if (fNumber) 2065 OutString = rScan.GetTrueString(); 2066 else 2067 OutString = rScan.GetFalseString(); 2068 return sal_False; 2069 } 2070 if (eType & NUMBERFORMAT_TEXT) 2071 { 2072 ImpGetOutputStandard(fNumber, OutString); 2073 return sal_False; 2074 } 2075 sal_Bool bHadStandard = sal_False; 2076 if (bStandard) // einzelne Standardformate 2077 { 2078 if (rScan.GetStandardPrec() == SvNumberFormatter::INPUTSTRING_PRECISION) // alle Zahlformate InputLine 2079 { 2080 ImpGetOutputInputLine(fNumber, OutString); 2081 return false; 2082 } 2083 switch (eType) 2084 { 2085 case NUMBERFORMAT_NUMBER: // Standardzahlformat 2086 { 2087 if (rScan.GetStandardPrec() == SvNumberFormatter::UNLIMITED_PRECISION) 2088 { 2089 bool bSign = ::rtl::math::isSignBitSet(fNumber); 2090 if (bSign) 2091 fNumber = -fNumber; 2092 ImpGetOutputStdToPrecision(fNumber, OutString, 10); // Use 10 decimals for general 'unlimited' format. 2093 if (fNumber < EXP_LOWER_BOUND) 2094 { 2095 xub_StrLen nLen = OutString.Len(); 2096 if (!nLen) 2097 return false; 2098 2099 // #i112250# With the 10-decimal limit, small numbers are formatted as "0". 2100 // Switch to scientific in that case, too: 2101 if (nLen > 11 || (OutString.EqualsAscii("0") && fNumber != 0.0)) 2102 { 2103 sal_uInt16 nStandardPrec = rScan.GetStandardPrec(); 2104 nStandardPrec = ::std::min(nStandardPrec, static_cast<sal_uInt16>(14)); // limits to 14 decimals 2105 OutString = ::rtl::math::doubleToUString( fNumber, 2106 rtl_math_StringFormat_E, nStandardPrec /*2*/, 2107 GetFormatter().GetNumDecimalSep().GetChar(0), true); 2108 } 2109 } 2110 if (bSign) 2111 OutString.Insert('-', 0); 2112 return false; 2113 } 2114 ImpGetOutputStandard(fNumber, OutString); 2115 bHadStandard = sal_True; 2116 } 2117 break; 2118 case NUMBERFORMAT_DATE: 2119 bRes |= ImpGetDateOutput(fNumber, 0, OutString); 2120 bHadStandard = sal_True; 2121 break; 2122 case NUMBERFORMAT_TIME: 2123 bRes |= ImpGetTimeOutput(fNumber, 0, OutString); 2124 bHadStandard = sal_True; 2125 break; 2126 case NUMBERFORMAT_DATETIME: 2127 bRes |= ImpGetDateTimeOutput(fNumber, 0, OutString); 2128 bHadStandard = sal_True; 2129 break; 2130 } 2131 } 2132 if ( !bHadStandard ) 2133 { 2134 sal_uInt16 nIx; // Index des Teilformats 2135 short nCheck = ImpCheckCondition(fNumber, fLimit1, eOp1); 2136 if (nCheck == -1 || nCheck == 1) // nur 1 String oder True 2137 nIx = 0; 2138 else 2139 { 2140 nCheck = ImpCheckCondition(fNumber, fLimit2, eOp2); 2141 if (nCheck == -1 || nCheck == 1) 2142 nIx = 1; 2143 else 2144 nIx = 2; 2145 } 2146 if (nIx == 1 && // negatives Format 2147 IsNegativeRealNegative() && fNumber < 0.0) // ohne Vorzeichen 2148 fNumber = -fNumber; // Vorzeichen eliminieren 2149 if(nIx == 0 && 2150 IsNegativeRealNegative2() && fNumber < 0.0) 2151 fNumber = -fNumber; 2152 *ppColor = NumFor[nIx].GetColor(); 2153 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2154 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2155 if (nAnz == 0 && rInfo.eScannedType == NUMBERFORMAT_UNDEFINED) 2156 return sal_False; // leer => nichts 2157 else if (nAnz == 0) // sonst Standard-Format 2158 { 2159 ImpGetOutputStandard(fNumber, OutString); 2160 return sal_False; 2161 } 2162 switch (rInfo.eScannedType) 2163 { 2164 case NUMBERFORMAT_TEXT: 2165 case NUMBERFORMAT_DEFINED: 2166 { 2167 for (sal_uInt16 i = 0; i < nAnz; i++) 2168 { 2169 switch (rInfo.nTypeArray[i]) 2170 { 2171 case NF_SYMBOLTYPE_STAR: 2172 if( bStarFlag ) 2173 { 2174 OutString += (sal_Unicode) 0x1B; 2175 OutString += rInfo.sStrArray[i].GetChar(1); 2176 bRes = sal_True; 2177 } 2178 break; 2179 case NF_SYMBOLTYPE_BLANK: 2180 InsertBlanks( OutString, OutString.Len(), 2181 rInfo.sStrArray[i].GetChar(1) ); 2182 break; 2183 case NF_SYMBOLTYPE_STRING: 2184 case NF_SYMBOLTYPE_CURRENCY: 2185 OutString += rInfo.sStrArray[i]; 2186 break; 2187 case NF_SYMBOLTYPE_THSEP: 2188 if (rInfo.nThousand == 0) 2189 OutString += rInfo.sStrArray[i]; 2190 break; 2191 default: 2192 break; 2193 } 2194 } 2195 } 2196 break; 2197 case NUMBERFORMAT_DATE: 2198 bRes |= ImpGetDateOutput(fNumber, nIx, OutString); 2199 break; 2200 case NUMBERFORMAT_TIME: 2201 bRes |= ImpGetTimeOutput(fNumber, nIx, OutString); 2202 break; 2203 case NUMBERFORMAT_DATETIME: 2204 bRes |= ImpGetDateTimeOutput(fNumber, nIx, OutString); 2205 break; 2206 case NUMBERFORMAT_NUMBER: 2207 case NUMBERFORMAT_PERCENT: 2208 case NUMBERFORMAT_CURRENCY: 2209 bRes |= ImpGetNumberOutput(fNumber, nIx, OutString); 2210 break; 2211 case NUMBERFORMAT_FRACTION: 2212 { 2213 String sStr, sFrac, sDiv; // Strings, Wert fuer 2214 sal_uLong nFrac, nDiv; // Vorkommaanteil 2215 // Zaehler und Nenner 2216 sal_Bool bSign = sal_False; 2217 if (fNumber < 0) 2218 { 2219 if (nIx == 0) // nicht in hinteren 2220 bSign = sal_True; // Formaten 2221 fNumber = -fNumber; 2222 } 2223 double fNum = floor(fNumber); // Vorkommateil 2224 fNumber -= fNum; // Nachkommateil 2225 if (fNum > _D_MAX_U_LONG_ || rInfo.nCntExp > 9) 2226 // zu gross 2227 { 2228 OutString = rScan.GetErrorString(); 2229 return sal_False; 2230 } 2231 if (rInfo.nCntExp == 0) 2232 { 2233 DBG_ERROR("SvNumberformat:: Bruch, nCntExp == 0"); 2234 return sal_False; 2235 } 2236 sal_uLong nBasis = ((sal_uLong)floor( // 9, 99, 999 ,... 2237 pow(10.0,rInfo.nCntExp))) - 1; 2238 sal_uLong x0, y0, x1, y1; 2239 2240 if (rInfo.nCntExp <= _MAX_FRACTION_PREC) 2241 { 2242 sal_Bool bUpperHalf; 2243 if (fNumber > 0.5) 2244 { 2245 bUpperHalf = sal_True; 2246 fNumber -= (fNumber - 0.5) * 2.0; 2247 } 2248 else 2249 bUpperHalf = sal_False; 2250 // Einstieg in Farey-Serie 2251 // finden: 2252 x0 = (sal_uLong) floor(fNumber*nBasis); // z.B. 2/9 <= x < 3/9 2253 if (x0 == 0) // => x0 = 2 2254 { 2255 y0 = 1; 2256 x1 = 1; 2257 y1 = nBasis; 2258 } 2259 else if (x0 == (nBasis-1)/2) // (b-1)/2, 1/2 2260 { // geht (nBasis ungerade) 2261 y0 = nBasis; 2262 x1 = 1; 2263 y1 = 2; 2264 } 2265 else if (x0 == 1) 2266 { 2267 y0 = nBasis; // 1/n; 1/(n-1) 2268 x1 = 1; 2269 y1 = nBasis - 1; 2270 } 2271 else 2272 { 2273 y0 = nBasis; // z.B. 2/9 2/8 2274 x1 = x0; 2275 y1 = nBasis - 1; 2276 double fUg = (double) x0 / (double) y0; 2277 double fOg = (double) x1 / (double) y1; 2278 sal_uLong nGgt = ImpGGT(y0, x0); // x0/y0 kuerzen 2279 x0 /= nGgt; 2280 y0 /= nGgt; // Einschachteln: 2281 sal_uLong x2 = 0; 2282 sal_uLong y2 = 0; 2283 sal_Bool bStop = sal_False; 2284 while (!bStop) 2285 { 2286 #ifdef GCC 2287 // #i21648# GCC over-optimizes something resulting 2288 // in wrong fTest values throughout the loops. 2289 volatile 2290 #endif 2291 double fTest = (double)x1/(double)y1; 2292 while (!bStop) 2293 { 2294 while (fTest > fOg) 2295 { 2296 x1--; 2297 fTest = (double)x1/(double)y1; 2298 } 2299 while (fTest < fUg && y1 > 1) 2300 { 2301 y1--; 2302 fTest = (double)x1/(double)y1; 2303 } 2304 if (fTest <= fOg) 2305 { 2306 fOg = fTest; 2307 bStop = sal_True; 2308 } 2309 else if (y1 == 1) 2310 bStop = sal_True; 2311 } // of while 2312 nGgt = ImpGGT(y1, x1); // x1/y1 kuerzen 2313 x2 = x1 / nGgt; 2314 y2 = y1 / nGgt; 2315 if (x2*y0 - x0*y2 == 1 || y1 <= 1) // Test, ob x2/y2 2316 bStop = sal_True; // naechste Farey-Zahl 2317 else 2318 { 2319 y1--; 2320 bStop = sal_False; 2321 } 2322 } // of while 2323 x1 = x2; 2324 y1 = y2; 2325 } // of else 2326 double fup, flow; 2327 flow = (double)x0/(double)y0; 2328 fup = (double)x1/(double)y1; 2329 while (fNumber > fup) 2330 { 2331 sal_uLong x2 = ((y0+nBasis)/y1)*x1 - x0; // naechste Farey-Zahl 2332 sal_uLong y2 = ((y0+nBasis)/y1)*y1 - y0; 2333 // GetNextFareyNumber(nBasis, x0, x1, y0, y1, x2, y2); 2334 x0 = x1; 2335 y0 = y1; 2336 x1 = x2; 2337 y1 = y2; 2338 flow = fup; 2339 fup = (double)x1/(double)y1; 2340 } 2341 if (fNumber - flow < fup - fNumber) 2342 { 2343 nFrac = x0; 2344 nDiv = y0; 2345 } 2346 else 2347 { 2348 nFrac = x1; 2349 nDiv = y1; 2350 } 2351 if (bUpperHalf) // Original restaur. 2352 { 2353 if (nFrac == 0 && nDiv == 1) // 1/1 2354 fNum += 1.0; 2355 else 2356 nFrac = nDiv - nFrac; 2357 } 2358 } 2359 else // grosse Nenner 2360 { // 0,1234->123/1000 2361 sal_uLong nGgt; 2362 /* 2363 nDiv = nBasis+1; 2364 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2365 pow(10.0,rInfo.nCntExp))); 2366 */ 2367 nDiv = 10000000; 2368 nFrac = ((sal_uLong)floor(0.5 + fNumber * 10000000.0)); 2369 nGgt = ImpGGT(nDiv, nFrac); 2370 if (nGgt > 1) 2371 { 2372 nDiv /= nGgt; 2373 nFrac /= nGgt; 2374 } 2375 if (nDiv > nBasis) 2376 { 2377 nGgt = ImpGGTRound(nDiv, nFrac); 2378 if (nGgt > 1) 2379 { 2380 nDiv /= nGgt; 2381 nFrac /= nGgt; 2382 } 2383 } 2384 if (nDiv > nBasis) 2385 { 2386 nDiv = nBasis; 2387 nFrac = ((sal_uLong)floor(0.5 + fNumber * 2388 pow(10.0,rInfo.nCntExp))); 2389 nGgt = ImpGGTRound(nDiv, nFrac); 2390 if (nGgt > 1) 2391 { 2392 nDiv /= nGgt; 2393 nFrac /= nGgt; 2394 } 2395 } 2396 } 2397 2398 if (rInfo.nCntPre == 0) // unechter Bruch 2399 { 2400 double fNum1 = fNum * (double)nDiv + (double)nFrac; 2401 if (fNum1 > _D_MAX_U_LONG_) 2402 { 2403 OutString = rScan.GetErrorString(); 2404 return sal_False; 2405 } 2406 nFrac = (sal_uLong) floor(fNum1); 2407 sStr.Erase(); 2408 } 2409 else if (fNum == 0.0 && nFrac != 0) 2410 sStr.Erase(); 2411 else 2412 { 2413 char aBuf[100]; 2414 sprintf( aBuf, "%.f", fNum ); // simple rounded integer (#100211# - checked) 2415 sStr.AssignAscii( aBuf ); 2416 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 2417 } 2418 if (rInfo.nCntPre > 0 && nFrac == 0) 2419 { 2420 sFrac.Erase(); 2421 sDiv.Erase(); 2422 } 2423 else 2424 { 2425 sFrac = ImpIntToString( nIx, nFrac ); 2426 sDiv = ImpIntToString( nIx, nDiv ); 2427 } 2428 2429 sal_uInt16 j = nAnz-1; // letztes Symbol->rueckw. 2430 xub_StrLen k; // Nenner: 2431 bRes |= ImpNumberFill(sDiv, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRAC); 2432 sal_Bool bCont = sal_True; 2433 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRAC) 2434 { 2435 if (rInfo.nCntPre > 0 && nFrac == 0) 2436 sDiv.Insert(' ',0); 2437 else 2438 sDiv.Insert( rInfo.sStrArray[j].GetChar(0), 0 ); 2439 if ( j ) 2440 j--; 2441 else 2442 bCont = sal_False; 2443 } 2444 // weiter Zaehler: 2445 if ( !bCont ) 2446 sFrac.Erase(); 2447 else 2448 { 2449 bRes |= ImpNumberFill(sFrac, fNumber, k, j, nIx, NF_SYMBOLTYPE_FRACBLANK); 2450 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_FRACBLANK) 2451 { 2452 sFrac.Insert(rInfo.sStrArray[j],0); 2453 if ( j ) 2454 j--; 2455 else 2456 bCont = sal_False; 2457 } 2458 } 2459 // weiter Hauptzahl 2460 if ( !bCont ) 2461 sStr.Erase(); 2462 else 2463 { 2464 k = sStr.Len(); // hinter letzter Ziffer 2465 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, 2466 rInfo.nCntPre); 2467 } 2468 if (bSign && !(nFrac == 0 && fNum == 0.0)) 2469 OutString.Insert('-',0); // nicht -0 2470 OutString += sStr; 2471 OutString += sFrac; 2472 OutString += sDiv; 2473 } 2474 break; 2475 case NUMBERFORMAT_SCIENTIFIC: 2476 { 2477 sal_Bool bSign = sal_False; 2478 if (fNumber < 0) 2479 { 2480 if (nIx == 0) // nicht in hinteren 2481 bSign = sal_True; // Formaten 2482 fNumber = -fNumber; 2483 } 2484 String sStr( ::rtl::math::doubleToUString( fNumber, 2485 rtl_math_StringFormat_E, 2486 rInfo.nCntPre + rInfo.nCntPost - 1, '.' )); 2487 2488 String ExpStr; 2489 short nExpSign = 1; 2490 xub_StrLen nExPos = sStr.Search('E'); 2491 if ( nExPos != STRING_NOTFOUND ) 2492 { 2493 // split into mantisse and exponent and get rid of "E+" or "E-" 2494 xub_StrLen nExpStart = nExPos + 1; 2495 switch ( sStr.GetChar( nExpStart ) ) 2496 { 2497 case '-' : 2498 nExpSign = -1; 2499 // fallthru 2500 case '+' : 2501 ++nExpStart; 2502 break; 2503 } 2504 ExpStr = sStr.Copy( nExpStart ); // part following the "E+" 2505 sStr.Erase( nExPos ); 2506 sStr.EraseAllChars('.'); // cut any decimal delimiter 2507 if ( rInfo.nCntPre != 1 ) // rescale Exp 2508 { 2509 sal_Int32 nExp = ExpStr.ToInt32() * nExpSign; 2510 nExp -= sal_Int32(rInfo.nCntPre)-1; 2511 if ( nExp < 0 ) 2512 { 2513 nExpSign = -1; 2514 nExp = -nExp; 2515 } 2516 else 2517 nExpSign = 1; 2518 ExpStr = String::CreateFromInt32( nExp ); 2519 } 2520 } 2521 sal_uInt16 j = nAnz-1; // last symbol 2522 xub_StrLen k; // position in ExpStr 2523 bRes |= ImpNumberFill(ExpStr, fNumber, k, j, nIx, NF_SYMBOLTYPE_EXP); 2524 2525 xub_StrLen nZeros = 0; // erase leading zeros 2526 while (nZeros < k && ExpStr.GetChar(nZeros) == '0') 2527 ++nZeros; 2528 if (nZeros) 2529 ExpStr.Erase( 0, nZeros); 2530 2531 sal_Bool bCont = sal_True; 2532 if (rInfo.nTypeArray[j] == NF_SYMBOLTYPE_EXP) 2533 { 2534 const String& rStr = rInfo.sStrArray[j]; 2535 if (nExpSign == -1) 2536 ExpStr.Insert('-',0); 2537 else if (rStr.Len() > 1 && rStr.GetChar(1) == '+') 2538 ExpStr.Insert('+',0); 2539 ExpStr.Insert(rStr.GetChar(0),0); 2540 if ( j ) 2541 j--; 2542 else 2543 bCont = sal_False; 2544 } 2545 // weiter Hauptzahl: 2546 if ( !bCont ) 2547 sStr.Erase(); 2548 else 2549 { 2550 k = sStr.Len(); // hinter letzter Ziffer 2551 bRes |= ImpNumberFillWithThousands(sStr,fNumber, k,j,nIx, 2552 rInfo.nCntPre + 2553 rInfo.nCntPost); 2554 } 2555 if (bSign) 2556 sStr.Insert('-',0); 2557 OutString = sStr; 2558 OutString += ExpStr; 2559 } 2560 break; 2561 } 2562 } 2563 return bRes; 2564 } 2565 2566 sal_Bool SvNumberformat::ImpGetTimeOutput(double fNumber, 2567 sal_uInt16 nIx, 2568 String& OutString) 2569 { 2570 using namespace ::com::sun::star::i18n; 2571 sal_Bool bCalendarSet = sal_False; 2572 double fNumberOrig = fNumber; 2573 sal_Bool bRes = sal_False; 2574 sal_Bool bSign = sal_False; 2575 if (fNumber < 0.0) 2576 { 2577 fNumber = -fNumber; 2578 if (nIx == 0) 2579 bSign = sal_True; 2580 } 2581 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2582 if (rInfo.bThousand) // []-Format 2583 { 2584 if (fNumber > 1.0E10) // zu gross 2585 { 2586 OutString = rScan.GetErrorString(); 2587 return sal_False; 2588 } 2589 } 2590 else 2591 fNumber -= floor(fNumber); // sonst Datum abtrennen 2592 sal_Bool bInputLine; 2593 xub_StrLen nCntPost; 2594 if ( rScan.GetStandardPrec() == 300 && 2595 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 2596 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 2597 bInputLine = sal_True; 2598 nCntPost = 7; 2599 } 2600 else 2601 { 2602 bInputLine = sal_False; 2603 nCntPost = xub_StrLen(rInfo.nCntPost); 2604 } 2605 if (bSign && !rInfo.bThousand) // kein []-Format 2606 fNumber = 1.0 - fNumber; // "Kehrwert" 2607 double fTime = fNumber * 86400.0; 2608 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 2609 if (bSign && fTime == 0.0) 2610 bSign = sal_False; // nicht -00:00:00 2611 2612 if( floor( fTime ) > _D_MAX_U_LONG_ ) 2613 { 2614 OutString = rScan.GetErrorString(); 2615 return sal_False; 2616 } 2617 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 2618 2619 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 2620 rtl_math_StringFormat_F, int(nCntPost), '.')); 2621 sSecStr.EraseLeadingChars('0'); 2622 sSecStr.EraseLeadingChars('.'); 2623 if ( bInputLine ) 2624 { 2625 sSecStr.EraseTrailingChars('0'); 2626 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 2627 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 2628 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2629 nCntPost = sSecStr.Len(); 2630 } 2631 else 2632 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 2633 2634 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 2635 // abarbeiten 2636 sal_uLong nHour, nMin, nSec; 2637 if (!rInfo.bThousand) // kein [] Format 2638 { 2639 nHour = (nSeconds/3600) % 24; 2640 nMin = (nSeconds%3600) / 60; 2641 nSec = nSeconds%60; 2642 } 2643 else if (rInfo.nThousand == 3) // [ss] 2644 { 2645 nHour = 0; 2646 nMin = 0; 2647 nSec = nSeconds; 2648 } 2649 else if (rInfo.nThousand == 2) // [mm]:ss 2650 { 2651 nHour = 0; 2652 nMin = nSeconds / 60; 2653 nSec = nSeconds % 60; 2654 } 2655 else if (rInfo.nThousand == 1) // [hh]:mm:ss 2656 { 2657 nHour = nSeconds / 3600; 2658 nMin = (nSeconds%3600) / 60; 2659 nSec = nSeconds%60; 2660 } 2661 else { 2662 // TODO What should these be set to? 2663 nHour = 0; 2664 nMin = 0; 2665 nSec = 0; 2666 } 2667 2668 sal_Unicode cAmPm = ' '; // a oder p 2669 if (rInfo.nCntExp) // AM/PM 2670 { 2671 if (nHour == 0) 2672 { 2673 nHour = 12; 2674 cAmPm = 'a'; 2675 } 2676 else if (nHour < 12) 2677 cAmPm = 'a'; 2678 else 2679 { 2680 cAmPm = 'p'; 2681 if (nHour > 12) 2682 nHour -= 12; 2683 } 2684 } 2685 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2686 for (sal_uInt16 i = 0; i < nAnz; i++) 2687 { 2688 switch (rInfo.nTypeArray[i]) 2689 { 2690 case NF_SYMBOLTYPE_STAR: 2691 if( bStarFlag ) 2692 { 2693 OutString += (sal_Unicode) 0x1B; 2694 OutString += rInfo.sStrArray[i].GetChar(1); 2695 bRes = sal_True; 2696 } 2697 break; 2698 case NF_SYMBOLTYPE_BLANK: 2699 InsertBlanks( OutString, OutString.Len(), 2700 rInfo.sStrArray[i].GetChar(1) ); 2701 break; 2702 case NF_SYMBOLTYPE_STRING: 2703 case NF_SYMBOLTYPE_CURRENCY: 2704 case NF_SYMBOLTYPE_DATESEP: 2705 case NF_SYMBOLTYPE_TIMESEP: 2706 case NF_SYMBOLTYPE_TIME100SECSEP: 2707 OutString += rInfo.sStrArray[i]; 2708 break; 2709 case NF_SYMBOLTYPE_DIGIT: 2710 { 2711 xub_StrLen nLen = ( bInputLine && i > 0 && 2712 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 2713 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 2714 nCntPost : rInfo.sStrArray[i].Len() ); 2715 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 2716 { 2717 OutString += sSecStr.GetChar(nSecPos); 2718 nSecPos++; 2719 } 2720 } 2721 break; 2722 case NF_KEY_AMPM: // AM/PM 2723 { 2724 if ( !bCalendarSet ) 2725 { 2726 double fDiff = DateTime(*(rScan.GetNullDate())) - GetCal().getEpochStart(); 2727 fDiff += fNumberOrig; 2728 GetCal().setLocalDateTime( fDiff ); 2729 bCalendarSet = sal_True; 2730 } 2731 if (cAmPm == 'a') 2732 OutString += GetCal().getDisplayName( 2733 CalendarDisplayIndex::AM_PM, AmPmValue::AM, 0 ); 2734 else 2735 OutString += GetCal().getDisplayName( 2736 CalendarDisplayIndex::AM_PM, AmPmValue::PM, 0 ); 2737 } 2738 break; 2739 case NF_KEY_AP: // A/P 2740 { 2741 if (cAmPm == 'a') 2742 OutString += 'a'; 2743 else 2744 OutString += 'p'; 2745 } 2746 break; 2747 case NF_KEY_MI: // M 2748 OutString += ImpIntToString( nIx, nMin ); 2749 break; 2750 case NF_KEY_MMI: // MM 2751 OutString += ImpIntToString( nIx, nMin, 2 ); 2752 break; 2753 case NF_KEY_H: // H 2754 OutString += ImpIntToString( nIx, nHour ); 2755 break; 2756 case NF_KEY_HH: // HH 2757 OutString += ImpIntToString( nIx, nHour, 2 ); 2758 break; 2759 case NF_KEY_S: // S 2760 OutString += ImpIntToString( nIx, nSec ); 2761 break; 2762 case NF_KEY_SS: // SS 2763 OutString += ImpIntToString( nIx, nSec, 2 ); 2764 break; 2765 default: 2766 break; 2767 } 2768 } 2769 if (bSign && rInfo.bThousand) 2770 OutString.Insert('-',0); 2771 return bRes; 2772 } 2773 2774 2775 sal_Bool SvNumberformat::ImpIsOtherCalendar( const ImpSvNumFor& rNumFor ) const 2776 { 2777 if ( GetCal().getUniqueID() != Gregorian::get() ) 2778 return sal_False; 2779 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2780 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2781 sal_uInt16 i; 2782 for ( i = 0; i < nAnz; i++ ) 2783 { 2784 switch ( rInfo.nTypeArray[i] ) 2785 { 2786 case NF_SYMBOLTYPE_CALENDAR : 2787 return sal_False; 2788 case NF_KEY_EC : 2789 case NF_KEY_EEC : 2790 case NF_KEY_R : 2791 case NF_KEY_RR : 2792 case NF_KEY_AAA : 2793 case NF_KEY_AAAA : 2794 return sal_True; 2795 } 2796 } 2797 return sal_False; 2798 } 2799 2800 2801 void SvNumberformat::SwitchToOtherCalendar( String& rOrgCalendar, 2802 double& fOrgDateTime ) const 2803 { 2804 CalendarWrapper& rCal = GetCal(); 2805 const rtl::OUString &rGregorian = Gregorian::get(); 2806 if ( rCal.getUniqueID() == rGregorian ) 2807 { 2808 using namespace ::com::sun::star::i18n; 2809 ::com::sun::star::uno::Sequence< ::rtl::OUString > xCals 2810 = rCal.getAllCalendars( rLoc().getLocale() ); 2811 sal_Int32 nCnt = xCals.getLength(); 2812 if ( nCnt > 1 ) 2813 { 2814 for ( sal_Int32 j=0; j < nCnt; j++ ) 2815 { 2816 if ( xCals[j] != rGregorian ) 2817 { 2818 if ( !rOrgCalendar.Len() ) 2819 { 2820 rOrgCalendar = rCal.getUniqueID(); 2821 fOrgDateTime = rCal.getDateTime(); 2822 } 2823 rCal.loadCalendar( xCals[j], rLoc().getLocale() ); 2824 rCal.setDateTime( fOrgDateTime ); 2825 break; // for 2826 } 2827 } 2828 } 2829 } 2830 } 2831 2832 2833 void SvNumberformat::SwitchToGregorianCalendar( const String& rOrgCalendar, 2834 double fOrgDateTime ) const 2835 { 2836 CalendarWrapper& rCal = GetCal(); 2837 const rtl::OUString &rGregorian = Gregorian::get(); 2838 if ( rOrgCalendar.Len() && rCal.getUniqueID() != rGregorian ) 2839 { 2840 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2841 rCal.setDateTime( fOrgDateTime ); 2842 } 2843 } 2844 2845 2846 sal_Bool SvNumberformat::ImpFallBackToGregorianCalendar( String& rOrgCalendar, double& fOrgDateTime ) 2847 { 2848 using namespace ::com::sun::star::i18n; 2849 CalendarWrapper& rCal = GetCal(); 2850 const rtl::OUString &rGregorian = Gregorian::get(); 2851 if ( rCal.getUniqueID() != rGregorian ) 2852 { 2853 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2854 if ( nVal == 0 && rCal.getLoadedCalendar().Eras[0].ID.equalsAsciiL( 2855 RTL_CONSTASCII_STRINGPARAM( "Dummy" ) ) ) 2856 { 2857 if ( !rOrgCalendar.Len() ) 2858 { 2859 rOrgCalendar = rCal.getUniqueID(); 2860 fOrgDateTime = rCal.getDateTime(); 2861 } 2862 else if ( rOrgCalendar == String(rGregorian) ) 2863 rOrgCalendar.Erase(); 2864 rCal.loadCalendar( rGregorian, rLoc().getLocale() ); 2865 rCal.setDateTime( fOrgDateTime ); 2866 return sal_True; 2867 } 2868 } 2869 return sal_False; 2870 } 2871 2872 2873 sal_Bool SvNumberformat::ImpSwitchToSpecifiedCalendar( String& rOrgCalendar, 2874 double& fOrgDateTime, const ImpSvNumFor& rNumFor ) const 2875 { 2876 const ImpSvNumberformatInfo& rInfo = rNumFor.Info(); 2877 const sal_uInt16 nAnz = rNumFor.GetnAnz(); 2878 for ( sal_uInt16 i = 0; i < nAnz; i++ ) 2879 { 2880 if ( rInfo.nTypeArray[i] == NF_SYMBOLTYPE_CALENDAR ) 2881 { 2882 CalendarWrapper& rCal = GetCal(); 2883 if ( !rOrgCalendar.Len() ) 2884 { 2885 rOrgCalendar = rCal.getUniqueID(); 2886 fOrgDateTime = rCal.getDateTime(); 2887 } 2888 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2889 rCal.setDateTime( fOrgDateTime ); 2890 return sal_True; 2891 } 2892 } 2893 return sal_False; 2894 } 2895 2896 2897 // static 2898 void SvNumberformat::ImpAppendEraG( String& OutString, 2899 const CalendarWrapper& rCal, sal_Int16 nNatNum ) 2900 { 2901 using namespace ::com::sun::star::i18n; 2902 if ( rCal.getUniqueID().equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "gengou" ) ) ) 2903 { 2904 sal_Unicode cEra; 2905 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::ERA ); 2906 switch ( nVal ) 2907 { 2908 case 1 : cEra = 'M'; break; 2909 case 2 : cEra = 'T'; break; 2910 case 3 : cEra = 'S'; break; 2911 case 4 : cEra = 'H'; break; 2912 default: 2913 cEra = '?'; 2914 } 2915 OutString += cEra; 2916 } 2917 else 2918 OutString += rCal.getDisplayString( CalendarDisplayCode::SHORT_ERA, nNatNum ); 2919 } 2920 2921 2922 sal_Bool SvNumberformat::ImpGetDateOutput(double fNumber, 2923 sal_uInt16 nIx, 2924 String& OutString) 2925 { 2926 using namespace ::com::sun::star::i18n; 2927 sal_Bool bRes = sal_False; 2928 CalendarWrapper& rCal = GetCal(); 2929 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 2930 fNumber += fDiff; 2931 rCal.setLocalDateTime( fNumber ); 2932 String aOrgCalendar; // empty => not changed yet 2933 double fOrgDateTime; 2934 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 2935 if ( bOtherCalendar ) 2936 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 2937 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 2938 bOtherCalendar = sal_False; 2939 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 2940 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 2941 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 2942 for (sal_uInt16 i = 0; i < nAnz; i++) 2943 { 2944 switch (rInfo.nTypeArray[i]) 2945 { 2946 case NF_SYMBOLTYPE_CALENDAR : 2947 if ( !aOrgCalendar.Len() ) 2948 { 2949 aOrgCalendar = rCal.getUniqueID(); 2950 fOrgDateTime = rCal.getDateTime(); 2951 } 2952 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 2953 rCal.setDateTime( fOrgDateTime ); 2954 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 2955 break; 2956 case NF_SYMBOLTYPE_STAR: 2957 if( bStarFlag ) 2958 { 2959 OutString += (sal_Unicode) 0x1B; 2960 OutString += rInfo.sStrArray[i].GetChar(1); 2961 bRes = sal_True; 2962 } 2963 break; 2964 case NF_SYMBOLTYPE_BLANK: 2965 InsertBlanks( OutString, OutString.Len(), 2966 rInfo.sStrArray[i].GetChar(1) ); 2967 break; 2968 case NF_SYMBOLTYPE_STRING: 2969 case NF_SYMBOLTYPE_CURRENCY: 2970 case NF_SYMBOLTYPE_DATESEP: 2971 case NF_SYMBOLTYPE_TIMESEP: 2972 case NF_SYMBOLTYPE_TIME100SECSEP: 2973 OutString += rInfo.sStrArray[i]; 2974 break; 2975 case NF_KEY_M: // M 2976 OutString += rCal.getDisplayString( 2977 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 2978 break; 2979 case NF_KEY_MM: // MM 2980 OutString += rCal.getDisplayString( 2981 CalendarDisplayCode::LONG_MONTH, nNatNum ); 2982 break; 2983 case NF_KEY_MMM: // MMM 2984 OutString += rCal.getDisplayString( 2985 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 2986 break; 2987 case NF_KEY_MMMM: // MMMM 2988 OutString += rCal.getDisplayString( 2989 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 2990 break; 2991 case NF_KEY_MMMMM: // MMMMM 2992 OutString += rCal.getDisplayString( 2993 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 2994 break; 2995 case NF_KEY_Q: // Q 2996 OutString += rCal.getDisplayString( 2997 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 2998 break; 2999 case NF_KEY_QQ: // QQ 3000 OutString += rCal.getDisplayString( 3001 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 3002 break; 3003 case NF_KEY_D: // D 3004 OutString += rCal.getDisplayString( 3005 CalendarDisplayCode::SHORT_DAY, nNatNum ); 3006 break; 3007 case NF_KEY_DD: // DD 3008 OutString += rCal.getDisplayString( 3009 CalendarDisplayCode::LONG_DAY, nNatNum ); 3010 break; 3011 case NF_KEY_DDD: // DDD 3012 { 3013 if ( bOtherCalendar ) 3014 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3015 OutString += rCal.getDisplayString( 3016 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3017 if ( bOtherCalendar ) 3018 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3019 } 3020 break; 3021 case NF_KEY_DDDD: // DDDD 3022 { 3023 if ( bOtherCalendar ) 3024 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3025 OutString += rCal.getDisplayString( 3026 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3027 if ( bOtherCalendar ) 3028 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3029 } 3030 break; 3031 case NF_KEY_YY: // YY 3032 { 3033 if ( bOtherCalendar ) 3034 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3035 OutString += rCal.getDisplayString( 3036 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3037 if ( bOtherCalendar ) 3038 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3039 } 3040 break; 3041 case NF_KEY_YYYY: // YYYY 3042 { 3043 if ( bOtherCalendar ) 3044 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3045 OutString += rCal.getDisplayString( 3046 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3047 if ( bOtherCalendar ) 3048 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3049 } 3050 break; 3051 case NF_KEY_EC: // E 3052 OutString += rCal.getDisplayString( 3053 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3054 break; 3055 case NF_KEY_EEC: // EE 3056 case NF_KEY_R: // R 3057 OutString += rCal.getDisplayString( 3058 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3059 break; 3060 case NF_KEY_NN: // NN 3061 case NF_KEY_AAA: // AAA 3062 OutString += rCal.getDisplayString( 3063 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3064 break; 3065 case NF_KEY_NNN: // NNN 3066 case NF_KEY_AAAA: // AAAA 3067 OutString += rCal.getDisplayString( 3068 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3069 break; 3070 case NF_KEY_NNNN: // NNNN 3071 { 3072 OutString += rCal.getDisplayString( 3073 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3074 OutString += rLoc().getLongDateDayOfWeekSep(); 3075 } 3076 break; 3077 case NF_KEY_WW : // WW 3078 { 3079 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3080 OutString += ImpIntToString( nIx, nVal ); 3081 } 3082 break; 3083 case NF_KEY_G: // G 3084 ImpAppendEraG( OutString, rCal, nNatNum ); 3085 break; 3086 case NF_KEY_GG: // GG 3087 OutString += rCal.getDisplayString( 3088 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3089 break; 3090 case NF_KEY_GGG: // GGG 3091 OutString += rCal.getDisplayString( 3092 CalendarDisplayCode::LONG_ERA, nNatNum ); 3093 break; 3094 case NF_KEY_RR: // RR => GGGEE 3095 OutString += rCal.getDisplayString( 3096 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3097 break; 3098 } 3099 } 3100 if ( aOrgCalendar.Len() ) 3101 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3102 return bRes; 3103 } 3104 3105 sal_Bool SvNumberformat::ImpGetDateTimeOutput(double fNumber, 3106 sal_uInt16 nIx, 3107 String& OutString) 3108 { 3109 using namespace ::com::sun::star::i18n; 3110 sal_Bool bRes = sal_False; 3111 3112 CalendarWrapper& rCal = GetCal(); 3113 double fDiff = DateTime(*(rScan.GetNullDate())) - rCal.getEpochStart(); 3114 fNumber += fDiff; 3115 3116 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3117 sal_Bool bInputLine; 3118 xub_StrLen nCntPost; 3119 if ( rScan.GetStandardPrec() == 300 && 3120 0 < rInfo.nCntPost && rInfo.nCntPost < 7 ) 3121 { // round at 7 decimals (+5 of 86400 == 12 significant digits) 3122 bInputLine = sal_True; 3123 nCntPost = 7; 3124 } 3125 else 3126 { 3127 bInputLine = sal_False; 3128 nCntPost = xub_StrLen(rInfo.nCntPost); 3129 } 3130 double fTime = (fNumber - floor( fNumber )) * 86400.0; 3131 fTime = ::rtl::math::round( fTime, int(nCntPost) ); 3132 if (fTime >= 86400.0) 3133 { 3134 // result of fNumber==x.999999999... rounded up, use correct date/time 3135 fTime -= 86400.0; 3136 fNumber = floor( fNumber + 0.5) + fTime; 3137 } 3138 rCal.setLocalDateTime( fNumber ); 3139 3140 String aOrgCalendar; // empty => not changed yet 3141 double fOrgDateTime; 3142 sal_Bool bOtherCalendar = ImpIsOtherCalendar( NumFor[nIx] ); 3143 if ( bOtherCalendar ) 3144 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3145 if ( ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ) ) 3146 bOtherCalendar = sal_False; 3147 sal_Int16 nNatNum = NumFor[nIx].GetNatNum().GetNatNum(); 3148 3149 sal_uLong nSeconds = (sal_uLong)floor( fTime ); 3150 String sSecStr( ::rtl::math::doubleToUString( fTime-nSeconds, 3151 rtl_math_StringFormat_F, int(nCntPost), '.')); 3152 sSecStr.EraseLeadingChars('0'); 3153 sSecStr.EraseLeadingChars('.'); 3154 if ( bInputLine ) 3155 { 3156 sSecStr.EraseTrailingChars('0'); 3157 if ( sSecStr.Len() < xub_StrLen(rInfo.nCntPost) ) 3158 sSecStr.Expand( xub_StrLen(rInfo.nCntPost), '0' ); 3159 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3160 nCntPost = sSecStr.Len(); 3161 } 3162 else 3163 ImpTransliterate( sSecStr, NumFor[nIx].GetNatNum() ); 3164 3165 xub_StrLen nSecPos = 0; // Zum Ziffernweisen 3166 // abarbeiten 3167 sal_uLong nHour, nMin, nSec; 3168 if (!rInfo.bThousand) // [] Format 3169 { 3170 nHour = (nSeconds/3600) % 24; 3171 nMin = (nSeconds%3600) / 60; 3172 nSec = nSeconds%60; 3173 } 3174 else if (rInfo.nThousand == 3) // [ss] 3175 { 3176 nHour = 0; 3177 nMin = 0; 3178 nSec = nSeconds; 3179 } 3180 else if (rInfo.nThousand == 2) // [mm]:ss 3181 { 3182 nHour = 0; 3183 nMin = nSeconds / 60; 3184 nSec = nSeconds % 60; 3185 } 3186 else if (rInfo.nThousand == 1) // [hh]:mm:ss 3187 { 3188 nHour = nSeconds / 3600; 3189 nMin = (nSeconds%3600) / 60; 3190 nSec = nSeconds%60; 3191 } 3192 else { 3193 nHour = 0; // TODO What should these values be? 3194 nMin = 0; 3195 nSec = 0; 3196 } 3197 sal_Unicode cAmPm = ' '; // a oder p 3198 if (rInfo.nCntExp) // AM/PM 3199 { 3200 if (nHour == 0) 3201 { 3202 nHour = 12; 3203 cAmPm = 'a'; 3204 } 3205 else if (nHour < 12) 3206 cAmPm = 'a'; 3207 else 3208 { 3209 cAmPm = 'p'; 3210 if (nHour > 12) 3211 nHour -= 12; 3212 } 3213 } 3214 const sal_uInt16 nAnz = NumFor[nIx].GetnAnz(); 3215 for (sal_uInt16 i = 0; i < nAnz; i++) 3216 { 3217 switch (rInfo.nTypeArray[i]) 3218 { 3219 case NF_SYMBOLTYPE_CALENDAR : 3220 if ( !aOrgCalendar.Len() ) 3221 { 3222 aOrgCalendar = rCal.getUniqueID(); 3223 fOrgDateTime = rCal.getDateTime(); 3224 } 3225 rCal.loadCalendar( rInfo.sStrArray[i], rLoc().getLocale() ); 3226 rCal.setDateTime( fOrgDateTime ); 3227 ImpFallBackToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3228 break; 3229 case NF_SYMBOLTYPE_STAR: 3230 if( bStarFlag ) 3231 { 3232 OutString += (sal_Unicode) 0x1B; 3233 OutString += rInfo.sStrArray[i].GetChar(1); 3234 bRes = sal_True; 3235 } 3236 break; 3237 case NF_SYMBOLTYPE_BLANK: 3238 InsertBlanks( OutString, OutString.Len(), 3239 rInfo.sStrArray[i].GetChar(1) ); 3240 break; 3241 case NF_SYMBOLTYPE_STRING: 3242 case NF_SYMBOLTYPE_CURRENCY: 3243 case NF_SYMBOLTYPE_DATESEP: 3244 case NF_SYMBOLTYPE_TIMESEP: 3245 case NF_SYMBOLTYPE_TIME100SECSEP: 3246 OutString += rInfo.sStrArray[i]; 3247 break; 3248 case NF_SYMBOLTYPE_DIGIT: 3249 { 3250 xub_StrLen nLen = ( bInputLine && i > 0 && 3251 (rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_STRING || 3252 rInfo.nTypeArray[i-1] == NF_SYMBOLTYPE_TIME100SECSEP) ? 3253 nCntPost : rInfo.sStrArray[i].Len() ); 3254 for (xub_StrLen j = 0; j < nLen && nSecPos < nCntPost; j++) 3255 { 3256 OutString += sSecStr.GetChar(nSecPos); 3257 nSecPos++; 3258 } 3259 } 3260 break; 3261 case NF_KEY_AMPM: // AM/PM 3262 { 3263 if (cAmPm == 'a') 3264 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3265 AmPmValue::AM, 0 ); 3266 else 3267 OutString += rCal.getDisplayName( CalendarDisplayIndex::AM_PM, 3268 AmPmValue::PM, 0 ); 3269 } 3270 break; 3271 case NF_KEY_AP: // A/P 3272 { 3273 if (cAmPm == 'a') 3274 OutString += 'a'; 3275 else 3276 OutString += 'p'; 3277 } 3278 break; 3279 case NF_KEY_MI: // M 3280 OutString += ImpIntToString( nIx, nMin ); 3281 break; 3282 case NF_KEY_MMI: // MM 3283 OutString += ImpIntToString( nIx, nMin, 2 ); 3284 break; 3285 case NF_KEY_H: // H 3286 OutString += ImpIntToString( nIx, nHour ); 3287 break; 3288 case NF_KEY_HH: // HH 3289 OutString += ImpIntToString( nIx, nHour, 2 ); 3290 break; 3291 case NF_KEY_S: // S 3292 OutString += ImpIntToString( nIx, nSec ); 3293 break; 3294 case NF_KEY_SS: // SS 3295 OutString += ImpIntToString( nIx, nSec, 2 ); 3296 break; 3297 case NF_KEY_M: // M 3298 OutString += rCal.getDisplayString( 3299 CalendarDisplayCode::SHORT_MONTH, nNatNum ); 3300 break; 3301 case NF_KEY_MM: // MM 3302 OutString += rCal.getDisplayString( 3303 CalendarDisplayCode::LONG_MONTH, nNatNum ); 3304 break; 3305 case NF_KEY_MMM: // MMM 3306 OutString += rCal.getDisplayString( 3307 CalendarDisplayCode::SHORT_MONTH_NAME, nNatNum ); 3308 break; 3309 case NF_KEY_MMMM: // MMMM 3310 OutString += rCal.getDisplayString( 3311 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ); 3312 break; 3313 case NF_KEY_MMMMM: // MMMMM 3314 OutString += rCal.getDisplayString( 3315 CalendarDisplayCode::LONG_MONTH_NAME, nNatNum ).GetChar(0); 3316 break; 3317 case NF_KEY_Q: // Q 3318 OutString += rCal.getDisplayString( 3319 CalendarDisplayCode::SHORT_QUARTER, nNatNum ); 3320 break; 3321 case NF_KEY_QQ: // QQ 3322 OutString += rCal.getDisplayString( 3323 CalendarDisplayCode::LONG_QUARTER, nNatNum ); 3324 break; 3325 case NF_KEY_D: // D 3326 OutString += rCal.getDisplayString( 3327 CalendarDisplayCode::SHORT_DAY, nNatNum ); 3328 break; 3329 case NF_KEY_DD: // DD 3330 OutString += rCal.getDisplayString( 3331 CalendarDisplayCode::LONG_DAY, nNatNum ); 3332 break; 3333 case NF_KEY_DDD: // DDD 3334 { 3335 if ( bOtherCalendar ) 3336 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3337 OutString += rCal.getDisplayString( 3338 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3339 if ( bOtherCalendar ) 3340 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3341 } 3342 break; 3343 case NF_KEY_DDDD: // DDDD 3344 { 3345 if ( bOtherCalendar ) 3346 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3347 OutString += rCal.getDisplayString( 3348 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3349 if ( bOtherCalendar ) 3350 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3351 } 3352 break; 3353 case NF_KEY_YY: // YY 3354 { 3355 if ( bOtherCalendar ) 3356 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3357 OutString += rCal.getDisplayString( 3358 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3359 if ( bOtherCalendar ) 3360 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3361 } 3362 break; 3363 case NF_KEY_YYYY: // YYYY 3364 { 3365 if ( bOtherCalendar ) 3366 SwitchToGregorianCalendar( aOrgCalendar, fOrgDateTime ); 3367 OutString += rCal.getDisplayString( 3368 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3369 if ( bOtherCalendar ) 3370 SwitchToOtherCalendar( aOrgCalendar, fOrgDateTime ); 3371 } 3372 break; 3373 case NF_KEY_EC: // E 3374 OutString += rCal.getDisplayString( 3375 CalendarDisplayCode::SHORT_YEAR, nNatNum ); 3376 break; 3377 case NF_KEY_EEC: // EE 3378 case NF_KEY_R: // R 3379 OutString += rCal.getDisplayString( 3380 CalendarDisplayCode::LONG_YEAR, nNatNum ); 3381 break; 3382 case NF_KEY_NN: // NN 3383 case NF_KEY_AAA: // AAA 3384 OutString += rCal.getDisplayString( 3385 CalendarDisplayCode::SHORT_DAY_NAME, nNatNum ); 3386 break; 3387 case NF_KEY_NNN: // NNN 3388 case NF_KEY_AAAA: // AAAA 3389 OutString += rCal.getDisplayString( 3390 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3391 break; 3392 case NF_KEY_NNNN: // NNNN 3393 { 3394 OutString += rCal.getDisplayString( 3395 CalendarDisplayCode::LONG_DAY_NAME, nNatNum ); 3396 OutString += rLoc().getLongDateDayOfWeekSep(); 3397 } 3398 break; 3399 case NF_KEY_WW : // WW 3400 { 3401 sal_Int16 nVal = rCal.getValue( CalendarFieldIndex::WEEK_OF_YEAR ); 3402 OutString += ImpIntToString( nIx, nVal ); 3403 } 3404 break; 3405 case NF_KEY_G: // G 3406 ImpAppendEraG( OutString, rCal, nNatNum ); 3407 break; 3408 case NF_KEY_GG: // GG 3409 OutString += rCal.getDisplayString( 3410 CalendarDisplayCode::SHORT_ERA, nNatNum ); 3411 break; 3412 case NF_KEY_GGG: // GGG 3413 OutString += rCal.getDisplayString( 3414 CalendarDisplayCode::LONG_ERA, nNatNum ); 3415 break; 3416 case NF_KEY_RR: // RR => GGGEE 3417 OutString += rCal.getDisplayString( 3418 CalendarDisplayCode::LONG_YEAR_AND_ERA, nNatNum ); 3419 break; 3420 } 3421 } 3422 if ( aOrgCalendar.Len() ) 3423 rCal.loadCalendar( aOrgCalendar, rLoc().getLocale() ); // restore calendar 3424 return bRes; 3425 } 3426 3427 sal_Bool SvNumberformat::ImpGetNumberOutput(double fNumber, 3428 sal_uInt16 nIx, 3429 String& OutString) 3430 { 3431 sal_Bool bRes = sal_False; 3432 sal_Bool bSign; 3433 if (fNumber < 0.0) 3434 { 3435 if (nIx == 0) // nicht in hinteren 3436 bSign = sal_True; // Formaten 3437 else 3438 bSign = sal_False; 3439 fNumber = -fNumber; 3440 } 3441 else 3442 { 3443 bSign = sal_False; 3444 if ( ::rtl::math::isSignBitSet( fNumber ) ) 3445 fNumber = -fNumber; // yes, -0.0 is possible, eliminate '-' 3446 } 3447 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3448 if (rInfo.eScannedType == NUMBERFORMAT_PERCENT) 3449 { 3450 if (fNumber < _D_MAX_D_BY_100) 3451 fNumber *= 100.0; 3452 else 3453 { 3454 OutString = rScan.GetErrorString(); 3455 return sal_False; 3456 } 3457 } 3458 sal_uInt16 i, j; 3459 xub_StrLen k; 3460 String sStr; 3461 long nPrecExp; 3462 sal_Bool bInteger = sal_False; 3463 if ( rInfo.nThousand != FLAG_STANDARD_IN_FORMAT ) 3464 { // special formatting only if no GENERAL keyword in format code 3465 const sal_uInt16 nThousand = rInfo.nThousand; 3466 for (i = 0; i < nThousand; i++) 3467 { 3468 if (fNumber > _D_MIN_M_BY_1000) 3469 fNumber /= 1000.0; 3470 else 3471 fNumber = 0.0; 3472 } 3473 if (fNumber > 0.0) 3474 nPrecExp = GetPrecExp( fNumber ); 3475 else 3476 nPrecExp = 0; 3477 if (rInfo.nCntPost) // NachkommaStellen 3478 { 3479 if (rInfo.nCntPost + nPrecExp > 15 && nPrecExp < 15) 3480 { 3481 sStr = ::rtl::math::doubleToUString( fNumber, 3482 rtl_math_StringFormat_F, 15-nPrecExp, '.'); 3483 for (long l = 15-nPrecExp; l < (long) rInfo.nCntPost; l++) 3484 sStr += '0'; 3485 } 3486 else 3487 sStr = ::rtl::math::doubleToUString( fNumber, 3488 rtl_math_StringFormat_F, rInfo.nCntPost, '.' ); 3489 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3490 } 3491 else if (fNumber == 0.0) // Null 3492 { 3493 // nothing to be done here, keep empty string sStr, 3494 // ImpNumberFillWithThousands does the rest 3495 } 3496 else // Integer 3497 { 3498 sStr = ::rtl::math::doubleToUString( fNumber, 3499 rtl_math_StringFormat_F, 0, '.'); 3500 sStr.EraseLeadingChars('0'); // fuehrende Nullen weg 3501 } 3502 xub_StrLen nPoint = sStr.Search( '.' ); 3503 if ( nPoint != STRING_NOTFOUND ) 3504 { 3505 register const sal_Unicode* p = sStr.GetBuffer() + nPoint; 3506 while ( *++p == '0' ) 3507 ; 3508 if ( !*p ) 3509 bInteger = sal_True; 3510 sStr.Erase( nPoint, 1 ); // . herausnehmen 3511 } 3512 if (bSign && 3513 (sStr.Len() == 0 || sStr.GetTokenCount('0') == sStr.Len()+1)) // nur 00000 3514 bSign = sal_False; // nicht -0.00 3515 } // End of != FLAG_STANDARD_IN_FORMAT 3516 3517 // von hinten nach vorn 3518 // editieren: 3519 k = sStr.Len(); // hinter letzter Ziffer 3520 j = NumFor[nIx].GetnAnz()-1; // letztes Symbol 3521 // Nachkommastellen: 3522 if (rInfo.nCntPost > 0) 3523 { 3524 sal_Bool bTrailing = sal_True; // ob Endnullen? 3525 sal_Bool bFilled = sal_False; // ob aufgefuellt wurde ? 3526 short nType; 3527 while (j > 0 && // rueckwaerts 3528 (nType = rInfo.nTypeArray[j]) != NF_SYMBOLTYPE_DECSEP) 3529 { 3530 switch ( nType ) 3531 { 3532 case NF_SYMBOLTYPE_STAR: 3533 if( bStarFlag ) 3534 { 3535 sStr.Insert( (sal_Unicode) 0x1B, k /*++*/ ); 3536 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3537 bRes = sal_True; 3538 } 3539 break; 3540 case NF_SYMBOLTYPE_BLANK: 3541 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3542 break; 3543 case NF_SYMBOLTYPE_STRING: 3544 case NF_SYMBOLTYPE_CURRENCY: 3545 case NF_SYMBOLTYPE_PERCENT: 3546 sStr.Insert(rInfo.sStrArray[j],k); 3547 break; 3548 case NF_SYMBOLTYPE_THSEP: 3549 if (rInfo.nThousand == 0) 3550 sStr.Insert(rInfo.sStrArray[j],k); 3551 break; 3552 case NF_SYMBOLTYPE_DIGIT: 3553 { 3554 const String& rStr = rInfo.sStrArray[j]; 3555 const sal_Unicode* p1 = rStr.GetBuffer(); 3556 register const sal_Unicode* p = p1 + rStr.Len(); 3557 while ( p1 < p-- ) 3558 { 3559 const sal_Unicode c = *p; 3560 k--; 3561 if ( sStr.GetChar(k) != '0' ) 3562 bTrailing = sal_False; 3563 if (bTrailing) 3564 { 3565 if ( c == '0' ) 3566 bFilled = sal_True; 3567 else if ( c == '-' ) 3568 { 3569 if ( bInteger ) 3570 sStr.SetChar( k, '-' ); 3571 bFilled = sal_True; 3572 } 3573 else if ( c == '?' ) 3574 { 3575 sStr.SetChar( k, ' ' ); 3576 bFilled = sal_True; 3577 } 3578 else if ( !bFilled ) // # 3579 sStr.Erase(k,1); 3580 } 3581 } // of for 3582 } // of case digi 3583 break; 3584 case NF_KEY_CCC: // CCC-Waehrung 3585 sStr.Insert(rScan.GetCurAbbrev(), k); 3586 break; 3587 case NF_KEY_GENERAL: // Standard im String 3588 { 3589 String sNum; 3590 ImpGetOutputStandard(fNumber, sNum); 3591 sNum.EraseLeadingChars('-'); 3592 sStr.Insert(sNum, k); 3593 } 3594 break; 3595 default: 3596 break; 3597 } // of switch 3598 j--; 3599 } // of while 3600 } // of Nachkomma 3601 3602 bRes |= ImpNumberFillWithThousands(sStr, fNumber, k, j, nIx, // ggfs Auffuellen mit . 3603 rInfo.nCntPre); 3604 if ( rInfo.nCntPost > 0 ) 3605 { 3606 const String& rDecSep = GetFormatter().GetNumDecimalSep(); 3607 xub_StrLen nLen = rDecSep.Len(); 3608 if ( sStr.Len() > nLen && sStr.Equals( rDecSep, sStr.Len() - nLen, nLen ) ) 3609 sStr.Erase( sStr.Len() - nLen ); // no decimals => strip DecSep 3610 } 3611 if (bSign) 3612 sStr.Insert('-',0); 3613 ImpTransliterate( sStr, NumFor[nIx].GetNatNum() ); 3614 OutString = sStr; 3615 return bRes; 3616 } 3617 3618 sal_Bool SvNumberformat::ImpNumberFillWithThousands( 3619 String& sStr, // number string 3620 double& rNumber, // number 3621 xub_StrLen k, // position within string 3622 sal_uInt16 j, // symbol index within format code 3623 sal_uInt16 nIx, // subformat index 3624 sal_uInt16 nDigCnt) // count of integer digits in format 3625 { 3626 sal_Bool bRes = sal_False; 3627 xub_StrLen nLeadingStringChars = 0; // inserted StringChars before number 3628 xub_StrLen nDigitCount = 0; // count of integer digits from the right 3629 sal_Bool bStop = sal_False; 3630 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3631 // no normal thousands separators if number divided by thousands 3632 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3633 utl::DigitGroupingIterator aGrouping( 3634 GetFormatter().GetLocaleData()->getDigitGrouping()); 3635 while (!bStop) // backwards 3636 { 3637 if (j == 0) 3638 bStop = sal_True; 3639 switch (rInfo.nTypeArray[j]) 3640 { 3641 case NF_SYMBOLTYPE_DECSEP: 3642 aGrouping.reset(); 3643 // fall thru 3644 case NF_SYMBOLTYPE_STRING: 3645 case NF_SYMBOLTYPE_CURRENCY: 3646 case NF_SYMBOLTYPE_PERCENT: 3647 sStr.Insert(rInfo.sStrArray[j],k); 3648 if ( k == 0 ) 3649 nLeadingStringChars = 3650 nLeadingStringChars + rInfo.sStrArray[j].Len(); 3651 break; 3652 case NF_SYMBOLTYPE_STAR: 3653 if( bStarFlag ) 3654 { 3655 sStr.Insert( (sal_Unicode) 0x1B, k/*++*/ ); 3656 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3657 bRes = sal_True; 3658 } 3659 break; 3660 case NF_SYMBOLTYPE_BLANK: 3661 /*k = */ InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3662 break; 3663 case NF_SYMBOLTYPE_THSEP: 3664 { 3665 // #i7284# #102685# Insert separator also if number is divided 3666 // by thousands and the separator is specified somewhere in 3667 // between and not only at the end. 3668 // #i12596# But do not insert if it's a parenthesized negative 3669 // format like (#,) 3670 // In fact, do not insert if divided and regex [0#,],[^0#] and 3671 // no other digit symbol follows (which was already detected 3672 // during scan of format code, otherwise there would be no 3673 // division), else do insert. Same in ImpNumberFill() below. 3674 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3675 bDoThousands = ((j == 0) || 3676 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3677 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3678 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3679 if ( bDoThousands ) 3680 { 3681 if (k > 0) 3682 sStr.Insert(rInfo.sStrArray[j],k); 3683 else if (nDigitCount < nDigCnt) 3684 { 3685 // Leading '#' displays nothing (e.g. no leading 3686 // separator for numbers <1000 with #,##0 format). 3687 // Leading '?' displays blank. 3688 // Everything else, including nothing, displays the 3689 // separator. 3690 sal_Unicode cLeader = 0; 3691 if (j > 0 && rInfo.nTypeArray[j-1] == NF_SYMBOLTYPE_DIGIT) 3692 { 3693 const String& rStr = rInfo.sStrArray[j-1]; 3694 xub_StrLen nLen = rStr.Len(); 3695 if (nLen) 3696 cLeader = rStr.GetChar(nLen-1); 3697 } 3698 switch (cLeader) 3699 { 3700 case '#': 3701 ; // nothing 3702 break; 3703 case '?': 3704 // erAck: 2008-04-03T16:24+0200 3705 // Actually this currently isn't executed 3706 // because the format scanner in the context of 3707 // "?," doesn't generate a group separator but 3708 // a literal ',' character instead that is 3709 // inserted unconditionally. Should be changed 3710 // on some occasion. 3711 sStr.Insert(' ',k); 3712 break; 3713 default: 3714 sStr.Insert(rInfo.sStrArray[j],k); 3715 } 3716 } 3717 aGrouping.advance(); 3718 } 3719 } 3720 break; 3721 case NF_SYMBOLTYPE_DIGIT: 3722 { 3723 const String& rStr = rInfo.sStrArray[j]; 3724 const sal_Unicode* p1 = rStr.GetBuffer(); 3725 register const sal_Unicode* p = p1 + rStr.Len(); 3726 while ( p1 < p-- ) 3727 { 3728 nDigitCount++; 3729 if (k > 0) 3730 k--; 3731 else 3732 { 3733 switch (*p) 3734 { 3735 case '0': 3736 sStr.Insert('0',0); 3737 break; 3738 case '?': 3739 sStr.Insert(' ',0); 3740 break; 3741 } 3742 } 3743 if (nDigitCount == nDigCnt && k > 0) 3744 { // more digits than specified 3745 ImpDigitFill(sStr, 0, k, nIx, nDigitCount, aGrouping); 3746 } 3747 } 3748 } 3749 break; 3750 case NF_KEY_CCC: // CCC currency 3751 sStr.Insert(rScan.GetCurAbbrev(), k); 3752 break; 3753 case NF_KEY_GENERAL: // "General" in string 3754 { 3755 String sNum; 3756 ImpGetOutputStandard(rNumber, sNum); 3757 sNum.EraseLeadingChars('-'); 3758 sStr.Insert(sNum, k); 3759 } 3760 break; 3761 3762 default: 3763 break; 3764 } // switch 3765 j--; // next format code string 3766 } // while 3767 k = k + nLeadingStringChars; // MSC converts += to int and then warns, so ... 3768 if (k > nLeadingStringChars) 3769 ImpDigitFill(sStr, nLeadingStringChars, k, nIx, nDigitCount, aGrouping); 3770 return bRes; 3771 } 3772 3773 void SvNumberformat::ImpDigitFill( 3774 String& sStr, // number string 3775 xub_StrLen nStart, // start of digits 3776 xub_StrLen& k, // position within string 3777 sal_uInt16 nIx, // subformat index 3778 xub_StrLen & nDigitCount, // count of integer digits from the right so far 3779 utl::DigitGroupingIterator & rGrouping ) // current grouping 3780 { 3781 if (NumFor[nIx].Info().bThousand) // only if grouping 3782 { // fill in separators 3783 const String& rThousandSep = GetFormatter().GetNumThousandSep(); 3784 while (k > nStart) 3785 { 3786 if (nDigitCount == rGrouping.getPos()) 3787 { 3788 sStr.Insert( rThousandSep, k ); 3789 rGrouping.advance(); 3790 } 3791 nDigitCount++; 3792 k--; 3793 } 3794 } 3795 else // simply skip 3796 k = nStart; 3797 } 3798 3799 sal_Bool SvNumberformat::ImpNumberFill( String& sStr, // number string 3800 double& rNumber, // number for "General" format 3801 xub_StrLen& k, // position within string 3802 sal_uInt16& j, // symbol index within format code 3803 sal_uInt16 nIx, // subformat index 3804 short eSymbolType ) // type of stop condition 3805 { 3806 sal_Bool bRes = sal_False; 3807 k = sStr.Len(); // behind last digit 3808 const ImpSvNumberformatInfo& rInfo = NumFor[nIx].Info(); 3809 // no normal thousands separators if number divided by thousands 3810 sal_Bool bDoThousands = (rInfo.nThousand == 0); 3811 short nType; 3812 while (j > 0 && (nType = rInfo.nTypeArray[j]) != eSymbolType ) 3813 { // rueckwaerts: 3814 switch ( nType ) 3815 { 3816 case NF_SYMBOLTYPE_STAR: 3817 if( bStarFlag ) 3818 { 3819 sStr.Insert( sal_Unicode(0x1B), k++ ); 3820 sStr.Insert(rInfo.sStrArray[j].GetChar(1),k); 3821 bRes = sal_True; 3822 } 3823 break; 3824 case NF_SYMBOLTYPE_BLANK: 3825 k = InsertBlanks( sStr,k,rInfo.sStrArray[j].GetChar(1) ); 3826 break; 3827 case NF_SYMBOLTYPE_THSEP: 3828 { 3829 // Same as in ImpNumberFillWithThousands() above, do not insert 3830 // if divided and regex [0#,],[^0#] and no other digit symbol 3831 // follows (which was already detected during scan of format 3832 // code, otherwise there would be no division), else do insert. 3833 if ( !bDoThousands && j < NumFor[nIx].GetnAnz()-1 ) 3834 bDoThousands = ((j == 0) || 3835 (rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_DIGIT && 3836 rInfo.nTypeArray[j-1] != NF_SYMBOLTYPE_THSEP) || 3837 (rInfo.nTypeArray[j+1] == NF_SYMBOLTYPE_DIGIT)); 3838 if ( bDoThousands && k > 0 ) 3839 { 3840 sStr.Insert(rInfo.sStrArray[j],k); 3841 } 3842 } 3843 break; 3844 case NF_SYMBOLTYPE_DIGIT: 3845 { 3846 const String& rStr = rInfo.sStrArray[j]; 3847 const sal_Unicode* p1 = rStr.GetBuffer(); 3848 register const sal_Unicode* p = p1 + rStr.Len(); 3849 while ( p1 < p-- ) 3850 { 3851 if (k > 0) 3852 k--; 3853 else 3854 { 3855 switch (*p) 3856 { 3857 case '0': 3858 sStr.Insert('0',0); 3859 break; 3860 case '?': 3861 sStr.Insert(' ',0); 3862 break; 3863 } 3864 } 3865 } 3866 } 3867 break; 3868 case NF_KEY_CCC: // CCC-Waehrung 3869 sStr.Insert(rScan.GetCurAbbrev(), k); 3870 break; 3871 case NF_KEY_GENERAL: // Standard im String 3872 { 3873 String sNum; 3874 ImpGetOutputStandard(rNumber, sNum); 3875 sNum.EraseLeadingChars('-'); // Vorzeichen weg!! 3876 sStr.Insert(sNum, k); 3877 } 3878 break; 3879 3880 default: 3881 sStr.Insert(rInfo.sStrArray[j],k); 3882 break; 3883 } // of switch 3884 j--; // naechster String 3885 } // of while 3886 return bRes; 3887 } 3888 3889 void SvNumberformat::GetFormatSpecialInfo(sal_Bool& bThousand, 3890 sal_Bool& IsRed, 3891 sal_uInt16& nPrecision, 3892 sal_uInt16& nAnzLeading) const 3893 { 3894 // as before: take info from nNumFor=0 for whole format (for dialog etc.) 3895 3896 short nDummyType; 3897 GetNumForInfo( 0, nDummyType, bThousand, nPrecision, nAnzLeading ); 3898 3899 // "negative in red" is only useful for the whole format 3900 3901 const Color* pColor = NumFor[1].GetColor(); 3902 if (fLimit1 == 0.0 && fLimit2 == 0.0 && pColor 3903 && (*pColor == rScan.GetRedColor())) 3904 IsRed = sal_True; 3905 else 3906 IsRed = sal_False; 3907 } 3908 3909 void SvNumberformat::GetNumForInfo( sal_uInt16 nNumFor, short& rScannedType, 3910 sal_Bool& bThousand, sal_uInt16& nPrecision, sal_uInt16& nAnzLeading ) const 3911 { 3912 // take info from a specified sub-format (for XML export) 3913 3914 if ( nNumFor > 3 ) 3915 return; // invalid 3916 3917 const ImpSvNumberformatInfo& rInfo = NumFor[nNumFor].Info(); 3918 rScannedType = rInfo.eScannedType; 3919 bThousand = rInfo.bThousand; 3920 nPrecision = rInfo.nCntPost; 3921 if (bStandard && rInfo.eScannedType == NUMBERFORMAT_NUMBER) 3922 // StandardFormat 3923 nAnzLeading = 1; 3924 else 3925 { 3926 nAnzLeading = 0; 3927 sal_Bool bStop = sal_False; 3928 sal_uInt16 i = 0; 3929 const sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3930 while (!bStop && i < nAnz) 3931 { 3932 short nType = rInfo.nTypeArray[i]; 3933 if ( nType == NF_SYMBOLTYPE_DIGIT) 3934 { 3935 register const sal_Unicode* p = rInfo.sStrArray[i].GetBuffer(); 3936 while ( *p == '#' ) 3937 p++; 3938 while ( *p++ == '0' ) 3939 nAnzLeading++; 3940 } 3941 else if (nType == NF_SYMBOLTYPE_DECSEP || nType == NF_SYMBOLTYPE_EXP) 3942 bStop = sal_True; 3943 i++; 3944 } 3945 } 3946 } 3947 3948 const String* SvNumberformat::GetNumForString( sal_uInt16 nNumFor, sal_uInt16 nPos, 3949 sal_Bool bString /* = sal_False */ ) const 3950 { 3951 if ( nNumFor > 3 ) 3952 return NULL; 3953 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3954 if ( !nAnz ) 3955 return NULL; 3956 if ( nPos == 0xFFFF ) 3957 { 3958 nPos = nAnz - 1; 3959 if ( bString ) 3960 { // rueckwaerts 3961 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3962 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 3963 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3964 { 3965 pType--; 3966 nPos--; 3967 } 3968 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3969 return NULL; 3970 } 3971 } 3972 else if ( nPos > nAnz - 1 ) 3973 return NULL; 3974 else if ( bString ) 3975 { // vorwaerts 3976 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 3977 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 3978 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 3979 { 3980 pType++; 3981 nPos++; 3982 } 3983 if ( nPos >= nAnz || ((*pType != NF_SYMBOLTYPE_STRING) && 3984 (*pType != NF_SYMBOLTYPE_CURRENCY)) ) 3985 return NULL; 3986 } 3987 return &NumFor[nNumFor].Info().sStrArray[nPos]; 3988 } 3989 3990 3991 short SvNumberformat::GetNumForType( sal_uInt16 nNumFor, sal_uInt16 nPos, 3992 sal_Bool bString /* = sal_False */ ) const 3993 { 3994 if ( nNumFor > 3 ) 3995 return 0; 3996 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 3997 if ( !nAnz ) 3998 return 0; 3999 if ( nPos == 0xFFFF ) 4000 { 4001 nPos = nAnz - 1; 4002 if ( bString ) 4003 { // rueckwaerts 4004 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 4005 while ( nPos > 0 && (*pType != NF_SYMBOLTYPE_STRING) && 4006 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4007 { 4008 pType--; 4009 nPos--; 4010 } 4011 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4012 return 0; 4013 } 4014 } 4015 else if ( nPos > nAnz - 1 ) 4016 return 0; 4017 else if ( bString ) 4018 { // vorwaerts 4019 short* pType = NumFor[nNumFor].Info().nTypeArray + nPos; 4020 while ( nPos < nAnz && (*pType != NF_SYMBOLTYPE_STRING) && 4021 (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4022 { 4023 pType++; 4024 nPos++; 4025 } 4026 if ( (*pType != NF_SYMBOLTYPE_STRING) && (*pType != NF_SYMBOLTYPE_CURRENCY) ) 4027 return 0; 4028 } 4029 return NumFor[nNumFor].Info().nTypeArray[nPos]; 4030 } 4031 4032 4033 sal_Bool SvNumberformat::IsNegativeWithoutSign() const 4034 { 4035 if ( IsNegativeRealNegative() ) 4036 { 4037 const String* pStr = GetNumForString( 1, 0, sal_True ); 4038 if ( pStr ) 4039 return !HasStringNegativeSign( *pStr ); 4040 } 4041 return sal_False; 4042 } 4043 4044 4045 DateFormat SvNumberformat::GetDateOrder() const 4046 { 4047 if ( (eType & NUMBERFORMAT_DATE) == NUMBERFORMAT_DATE ) 4048 { 4049 short const * const pType = NumFor[0].Info().nTypeArray; 4050 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4051 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4052 { 4053 switch ( pType[j] ) 4054 { 4055 case NF_KEY_D : 4056 case NF_KEY_DD : 4057 return DMY; 4058 case NF_KEY_M : 4059 case NF_KEY_MM : 4060 case NF_KEY_MMM : 4061 case NF_KEY_MMMM : 4062 case NF_KEY_MMMMM : 4063 return MDY; 4064 case NF_KEY_YY : 4065 case NF_KEY_YYYY : 4066 case NF_KEY_EC : 4067 case NF_KEY_EEC : 4068 case NF_KEY_R : 4069 case NF_KEY_RR : 4070 return YMD; 4071 } 4072 } 4073 } 4074 else 4075 { 4076 DBG_ERROR( "SvNumberformat::GetDateOrder: no date" ); 4077 } 4078 return rLoc().getDateFormat(); 4079 } 4080 4081 4082 sal_uInt32 SvNumberformat::GetExactDateOrder() const 4083 { 4084 sal_uInt32 nRet = 0; 4085 if ( (eType & NUMBERFORMAT_DATE) != NUMBERFORMAT_DATE ) 4086 { 4087 DBG_ERROR( "SvNumberformat::GetExactDateOrder: no date" ); 4088 return nRet; 4089 } 4090 short const * const pType = NumFor[0].Info().nTypeArray; 4091 sal_uInt16 nAnz = NumFor[0].GetnAnz(); 4092 int nShift = 0; 4093 for ( sal_uInt16 j=0; j<nAnz && nShift < 3; j++ ) 4094 { 4095 switch ( pType[j] ) 4096 { 4097 case NF_KEY_D : 4098 case NF_KEY_DD : 4099 nRet = (nRet << 8) | 'D'; 4100 ++nShift; 4101 break; 4102 case NF_KEY_M : 4103 case NF_KEY_MM : 4104 case NF_KEY_MMM : 4105 case NF_KEY_MMMM : 4106 case NF_KEY_MMMMM : 4107 nRet = (nRet << 8) | 'M'; 4108 ++nShift; 4109 break; 4110 case NF_KEY_YY : 4111 case NF_KEY_YYYY : 4112 case NF_KEY_EC : 4113 case NF_KEY_EEC : 4114 case NF_KEY_R : 4115 case NF_KEY_RR : 4116 nRet = (nRet << 8) | 'Y'; 4117 ++nShift; 4118 break; 4119 } 4120 } 4121 return nRet; 4122 } 4123 4124 4125 void SvNumberformat::GetConditions( SvNumberformatLimitOps& rOper1, double& rVal1, 4126 SvNumberformatLimitOps& rOper2, double& rVal2 ) const 4127 { 4128 rOper1 = eOp1; 4129 rOper2 = eOp2; 4130 rVal1 = fLimit1; 4131 rVal2 = fLimit2; 4132 } 4133 4134 4135 Color* SvNumberformat::GetColor( sal_uInt16 nNumFor ) const 4136 { 4137 if ( nNumFor > 3 ) 4138 return NULL; 4139 4140 return NumFor[nNumFor].GetColor(); 4141 } 4142 4143 4144 void lcl_SvNumberformat_AddLimitStringImpl( String& rStr, 4145 SvNumberformatLimitOps eOp, double fLimit, const String& rDecSep ) 4146 { 4147 if ( eOp != NUMBERFORMAT_OP_NO ) 4148 { 4149 switch ( eOp ) 4150 { 4151 case NUMBERFORMAT_OP_EQ : 4152 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[=" ) ); 4153 break; 4154 case NUMBERFORMAT_OP_NE : 4155 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<>" ) ); 4156 break; 4157 case NUMBERFORMAT_OP_LT : 4158 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<" ) ); 4159 break; 4160 case NUMBERFORMAT_OP_LE : 4161 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[<=" ) ); 4162 break; 4163 case NUMBERFORMAT_OP_GT : 4164 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>" ) ); 4165 break; 4166 case NUMBERFORMAT_OP_GE : 4167 rStr.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "[>=" ) ); 4168 break; 4169 default: 4170 OSL_ASSERT( "unsupported number format" ); 4171 break; 4172 } 4173 rStr += String( ::rtl::math::doubleToUString( fLimit, 4174 rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, 4175 rDecSep.GetChar(0), sal_True)); 4176 rStr += ']'; 4177 } 4178 } 4179 4180 4181 String SvNumberformat::GetMappedFormatstring( 4182 const NfKeywordTable& rKeywords, const LocaleDataWrapper& rLocWrp, 4183 sal_Bool bDontQuote ) const 4184 { 4185 String aStr; 4186 sal_Bool bDefault[4]; 4187 // 1 subformat matches all if no condition specified, 4188 bDefault[0] = ( NumFor[1].GetnAnz() == 0 && eOp1 == NUMBERFORMAT_OP_NO ); 4189 // with 2 subformats [>=0];[<0] is implied if no condition specified 4190 bDefault[1] = ( !bDefault[0] && NumFor[2].GetnAnz() == 0 && 4191 eOp1 == NUMBERFORMAT_OP_GE && fLimit1 == 0.0 && 4192 eOp2 == NUMBERFORMAT_OP_NO && fLimit2 == 0.0 ); 4193 // with 3 or more subformats [>0];[<0];[=0] is implied if no condition specified, 4194 // note that subformats may be empty (;;;) and NumFor[2].GetnAnz()>0 is not checked. 4195 bDefault[2] = ( !bDefault[0] && !bDefault[1] && 4196 eOp1 == NUMBERFORMAT_OP_GT && fLimit1 == 0.0 && 4197 eOp2 == NUMBERFORMAT_OP_LT && fLimit2 == 0.0 ); 4198 sal_Bool bDefaults = bDefault[0] || bDefault[1] || bDefault[2]; 4199 // from now on bDefault[] values are used to append empty subformats at the end 4200 bDefault[3] = sal_False; 4201 if ( !bDefaults ) 4202 { // conditions specified 4203 if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 == NUMBERFORMAT_OP_NO ) 4204 bDefault[0] = bDefault[1] = sal_True; // [];x 4205 else if ( eOp1 != NUMBERFORMAT_OP_NO && eOp2 != NUMBERFORMAT_OP_NO && 4206 NumFor[2].GetnAnz() == 0 ) 4207 bDefault[0] = bDefault[1] = bDefault[2] = bDefault[3] = sal_True; // [];[];; 4208 // nothing to do if conditions specified for every subformat 4209 } 4210 else if ( bDefault[0] ) 4211 bDefault[0] = sal_False; // a single unconditional subformat is never delimited 4212 else 4213 { 4214 if ( bDefault[2] && NumFor[2].GetnAnz() == 0 && NumFor[1].GetnAnz() > 0 ) 4215 bDefault[3] = sal_True; // special cases x;x;; and ;x;; 4216 for ( int i=0; i<3 && !bDefault[i]; ++i ) 4217 bDefault[i] = sal_True; 4218 } 4219 int nSem = 0; // needed ';' delimiters 4220 int nSub = 0; // subformats delimited so far 4221 for ( int n=0; n<4; n++ ) 4222 { 4223 if ( n > 0 ) 4224 nSem++; 4225 4226 String aPrefix; 4227 4228 if ( !bDefaults ) 4229 { 4230 switch ( n ) 4231 { 4232 case 0 : 4233 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp1, 4234 fLimit1, rLocWrp.getNumDecimalSep() ); 4235 break; 4236 case 1 : 4237 lcl_SvNumberformat_AddLimitStringImpl( aPrefix, eOp2, 4238 fLimit2, rLocWrp.getNumDecimalSep() ); 4239 break; 4240 } 4241 } 4242 4243 const String& rColorName = NumFor[n].GetColorName(); 4244 if ( rColorName.Len() ) 4245 { 4246 const NfKeywordTable & rKey = rScan.GetKeywords(); 4247 for ( int j=NF_KEY_FIRSTCOLOR; j<=NF_KEY_LASTCOLOR; j++ ) 4248 { 4249 if ( rKey[j] == rColorName ) 4250 { 4251 aPrefix += '['; 4252 aPrefix += rKeywords[j]; 4253 aPrefix += ']'; 4254 break; // for 4255 } 4256 } 4257 } 4258 4259 const SvNumberNatNum& rNum = NumFor[n].GetNatNum(); 4260 // The Thai T NatNum modifier during Xcl export. 4261 if (rNum.IsSet() && rNum.GetNatNum() == 1 && 4262 rKeywords[NF_KEY_THAI_T].EqualsAscii( "T") && 4263 MsLangId::getRealLanguage( rNum.GetLang()) == 4264 LANGUAGE_THAI) 4265 { 4266 aPrefix += 't'; // must be lowercase, otherwise taken as literal 4267 } 4268 4269 sal_uInt16 nAnz = NumFor[n].GetnAnz(); 4270 if ( nSem && (nAnz || aPrefix.Len()) ) 4271 { 4272 for ( ; nSem; --nSem ) 4273 aStr += ';'; 4274 for ( ; nSub <= n; ++nSub ) 4275 bDefault[nSub] = sal_False; 4276 } 4277 4278 if ( aPrefix.Len() ) 4279 aStr += aPrefix; 4280 4281 if ( nAnz ) 4282 { 4283 const short* pType = NumFor[n].Info().nTypeArray; 4284 const String* pStr = NumFor[n].Info().sStrArray; 4285 for ( sal_uInt16 j=0; j<nAnz; j++ ) 4286 { 4287 if ( 0 <= pType[j] && pType[j] < NF_KEYWORD_ENTRIES_COUNT ) 4288 { 4289 aStr += rKeywords[pType[j]]; 4290 if( NF_KEY_NNNN == pType[j] ) 4291 aStr += rLocWrp.getLongDateDayOfWeekSep(); 4292 } 4293 else 4294 { 4295 switch ( pType[j] ) 4296 { 4297 case NF_SYMBOLTYPE_DECSEP : 4298 aStr += rLocWrp.getNumDecimalSep(); 4299 break; 4300 case NF_SYMBOLTYPE_THSEP : 4301 aStr += rLocWrp.getNumThousandSep(); 4302 break; 4303 case NF_SYMBOLTYPE_DATESEP : 4304 aStr += rLocWrp.getDateSep(); 4305 break; 4306 case NF_SYMBOLTYPE_TIMESEP : 4307 aStr += rLocWrp.getTimeSep(); 4308 break; 4309 case NF_SYMBOLTYPE_TIME100SECSEP : 4310 aStr += rLocWrp.getTime100SecSep(); 4311 break; 4312 case NF_SYMBOLTYPE_STRING : 4313 if( bDontQuote ) 4314 aStr += pStr[j]; 4315 else if ( pStr[j].Len() == 1 ) 4316 { 4317 aStr += '\\'; 4318 aStr += pStr[j]; 4319 } 4320 else 4321 { 4322 aStr += '"'; 4323 aStr += pStr[j]; 4324 aStr += '"'; 4325 } 4326 break; 4327 default: 4328 aStr += pStr[j]; 4329 } 4330 4331 } 4332 } 4333 } 4334 } 4335 for ( ; nSub<4 && bDefault[nSub]; ++nSub ) 4336 { // append empty subformats 4337 aStr += ';'; 4338 } 4339 return aStr; 4340 } 4341 4342 4343 String SvNumberformat::ImpGetNatNumString( const SvNumberNatNum& rNum, 4344 sal_Int32 nVal, sal_uInt16 nMinDigits ) const 4345 { 4346 String aStr; 4347 if ( nMinDigits ) 4348 { 4349 if ( nMinDigits == 2 ) 4350 { // speed up the most common case 4351 if ( 0 <= nVal && nVal < 10 ) 4352 { 4353 sal_Unicode* p = aStr.AllocBuffer( 2 ); 4354 *p++ = '0'; 4355 *p = sal_Unicode( '0' + nVal ); 4356 } 4357 else 4358 aStr = String::CreateFromInt32( nVal ); 4359 } 4360 else 4361 { 4362 String aValStr( String::CreateFromInt32( nVal ) ); 4363 if ( aValStr.Len() >= nMinDigits ) 4364 aStr = aValStr; 4365 else 4366 { 4367 aStr.Fill( nMinDigits - aValStr.Len(), '0' ); 4368 aStr += aValStr; 4369 } 4370 } 4371 } 4372 else 4373 aStr = String::CreateFromInt32( nVal ); 4374 ImpTransliterate( aStr, rNum ); 4375 return aStr; 4376 } 4377 4378 4379 void SvNumberformat::ImpTransliterateImpl( String& rStr, 4380 const SvNumberNatNum& rNum ) const 4381 { 4382 com::sun::star::lang::Locale aLocale( 4383 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4384 rStr = GetFormatter().GetNatNum()->getNativeNumberString( rStr, 4385 aLocale, rNum.GetNatNum() ); 4386 } 4387 4388 4389 void SvNumberformat::GetNatNumXml( 4390 com::sun::star::i18n::NativeNumberXmlAttributes& rAttr, 4391 sal_uInt16 nNumFor ) const 4392 { 4393 if ( nNumFor <= 3 ) 4394 { 4395 const SvNumberNatNum& rNum = NumFor[nNumFor].GetNatNum(); 4396 if ( rNum.IsSet() ) 4397 { 4398 com::sun::star::lang::Locale aLocale( 4399 MsLangId::convertLanguageToLocale( rNum.GetLang() ) ); 4400 rAttr = GetFormatter().GetNatNum()->convertToXmlAttributes( 4401 aLocale, rNum.GetNatNum() ); 4402 } 4403 else 4404 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4405 } 4406 else 4407 rAttr = com::sun::star::i18n::NativeNumberXmlAttributes(); 4408 } 4409 4410 // static 4411 sal_Bool SvNumberformat::HasStringNegativeSign( const String& rStr ) 4412 { 4413 // fuer Sign muss '-' am Anfang oder am Ende des TeilStrings sein (Blanks ignored) 4414 xub_StrLen nLen = rStr.Len(); 4415 if ( !nLen ) 4416 return sal_False; 4417 const sal_Unicode* const pBeg = rStr.GetBuffer(); 4418 const sal_Unicode* const pEnd = pBeg + nLen; 4419 register const sal_Unicode* p = pBeg; 4420 do 4421 { // Anfang 4422 if ( *p == '-' ) 4423 return sal_True; 4424 } while ( *p == ' ' && ++p < pEnd ); 4425 p = pEnd - 1; 4426 do 4427 { // Ende 4428 if ( *p == '-' ) 4429 return sal_True; 4430 } while ( *p == ' ' && pBeg < --p ); 4431 return sal_False; 4432 } 4433 4434 4435 // static 4436 void SvNumberformat::SetComment( const String& rStr, String& rFormat, 4437 String& rComment ) 4438 { 4439 if ( rComment.Len() ) 4440 { // alten Kommentar aus Formatstring loeschen 4441 //! nicht per EraseComment, der Kommentar muss matchen 4442 String aTmp( '{' ); 4443 aTmp += ' '; 4444 aTmp += rComment; 4445 aTmp += ' '; 4446 aTmp += '}'; 4447 xub_StrLen nCom = 0; 4448 do 4449 { 4450 nCom = rFormat.Search( aTmp, nCom ); 4451 } while ( (nCom != STRING_NOTFOUND) && (nCom + aTmp.Len() != rFormat.Len()) ); 4452 if ( nCom != STRING_NOTFOUND ) 4453 rFormat.Erase( nCom ); 4454 } 4455 if ( rStr.Len() ) 4456 { // neuen Kommentar setzen 4457 rFormat += '{'; 4458 rFormat += ' '; 4459 rFormat += rStr; 4460 rFormat += ' '; 4461 rFormat += '}'; 4462 rComment = rStr; 4463 } 4464 } 4465 4466 4467 // static 4468 void SvNumberformat::EraseCommentBraces( String& rStr ) 4469 { 4470 xub_StrLen nLen = rStr.Len(); 4471 if ( nLen && rStr.GetChar(0) == '{' ) 4472 { 4473 rStr.Erase( 0, 1 ); 4474 --nLen; 4475 } 4476 if ( nLen && rStr.GetChar(0) == ' ' ) 4477 { 4478 rStr.Erase( 0, 1 ); 4479 --nLen; 4480 } 4481 if ( nLen && rStr.GetChar( nLen-1 ) == '}' ) 4482 rStr.Erase( --nLen, 1 ); 4483 if ( nLen && rStr.GetChar( nLen-1 ) == ' ' ) 4484 rStr.Erase( --nLen, 1 ); 4485 } 4486 4487 4488 // static 4489 void SvNumberformat::EraseComment( String& rStr ) 4490 { 4491 register const sal_Unicode* p = rStr.GetBuffer(); 4492 sal_Bool bInString = sal_False; 4493 sal_Bool bEscaped = sal_False; 4494 sal_Bool bFound = sal_False; 4495 xub_StrLen nPos = 0; 4496 while ( !bFound && *p ) 4497 { 4498 switch ( *p ) 4499 { 4500 case '\\' : 4501 bEscaped = !bEscaped; 4502 break; 4503 case '\"' : 4504 if ( !bEscaped ) 4505 bInString = !bInString; 4506 break; 4507 case '{' : 4508 if ( !bEscaped && !bInString ) 4509 { 4510 bFound = sal_True; 4511 nPos = sal::static_int_cast< xub_StrLen >( 4512 p - rStr.GetBuffer()); 4513 } 4514 break; 4515 } 4516 if ( bEscaped && *p != '\\' ) 4517 bEscaped = sal_False; 4518 ++p; 4519 } 4520 if ( bFound ) 4521 rStr.Erase( nPos ); 4522 } 4523 4524 4525 // static 4526 sal_Bool SvNumberformat::IsInQuote( const String& rStr, xub_StrLen nPos, 4527 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4528 { 4529 xub_StrLen nLen = rStr.Len(); 4530 if ( nPos >= nLen ) 4531 return sal_False; 4532 register const sal_Unicode* p0 = rStr.GetBuffer(); 4533 register const sal_Unicode* p = p0; 4534 register const sal_Unicode* p1 = p0 + nPos; 4535 sal_Bool bQuoted = sal_False; 4536 while ( p <= p1 ) 4537 { 4538 if ( *p == cQuote ) 4539 { 4540 if ( p == p0 ) 4541 bQuoted = sal_True; 4542 else if ( bQuoted ) 4543 { 4544 if ( *(p-1) != cEscIn ) 4545 bQuoted = sal_False; 4546 } 4547 else 4548 { 4549 if ( *(p-1) != cEscOut ) 4550 bQuoted = sal_True; 4551 } 4552 } 4553 p++; 4554 } 4555 return bQuoted; 4556 } 4557 4558 4559 // static 4560 xub_StrLen SvNumberformat::GetQuoteEnd( const String& rStr, xub_StrLen nPos, 4561 sal_Unicode cQuote, sal_Unicode cEscIn, sal_Unicode cEscOut ) 4562 { 4563 xub_StrLen nLen = rStr.Len(); 4564 if ( nPos >= nLen ) 4565 return STRING_NOTFOUND; 4566 if ( !IsInQuote( rStr, nPos, cQuote, cEscIn, cEscOut ) ) 4567 { 4568 if ( rStr.GetChar( nPos ) == cQuote ) 4569 return nPos; // schliessendes cQuote 4570 return STRING_NOTFOUND; 4571 } 4572 register const sal_Unicode* p0 = rStr.GetBuffer(); 4573 register const sal_Unicode* p = p0 + nPos; 4574 register const sal_Unicode* p1 = p0 + nLen; 4575 while ( p < p1 ) 4576 { 4577 if ( *p == cQuote && p > p0 && *(p-1) != cEscIn ) 4578 return sal::static_int_cast< xub_StrLen >(p - p0); 4579 p++; 4580 } 4581 return nLen; // String Ende 4582 } 4583 4584 4585 sal_uInt16 SvNumberformat::ImpGetNumForStringElementCount( sal_uInt16 nNumFor ) const 4586 { 4587 sal_uInt16 nCnt = 0; 4588 sal_uInt16 nAnz = NumFor[nNumFor].GetnAnz(); 4589 short const * const pType = NumFor[nNumFor].Info().nTypeArray; 4590 for ( sal_uInt16 j=0; j<nAnz; ++j ) 4591 { 4592 switch ( pType[j] ) 4593 { 4594 case NF_SYMBOLTYPE_STRING: 4595 case NF_SYMBOLTYPE_CURRENCY: 4596 case NF_SYMBOLTYPE_DATESEP: 4597 case NF_SYMBOLTYPE_TIMESEP: 4598 case NF_SYMBOLTYPE_TIME100SECSEP: 4599 case NF_SYMBOLTYPE_PERCENT: 4600 ++nCnt; 4601 break; 4602 } 4603 } 4604 return nCnt; 4605 } 4606 4607