1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 21 #include <stdlib.h> 22 #include <comphelper/string.hxx> 23 #include <sal/log.hxx> 24 #include <tools/debug.hxx> 25 #include <i18nlangtag/mslangid.hxx> 26 #include <unotools/charclass.hxx> 27 #include <unotools/localedatawrapper.hxx> 28 #include <com/sun/star/i18n/NumberFormatCode.hpp> 29 30 #include <svl/zforlist.hxx> 31 #include <svl/zformat.hxx> 32 #include <unotools/digitgroupingiterator.hxx> 33 34 #include "zforscan.hxx" 35 36 #include <svl/nfsymbol.hxx> 37 using namespace svt; 38 39 const sal_Unicode cNoBreakSpace = 0xA0; 40 const sal_Unicode cNarrowNoBreakSpace = 0x202F; 41 42 const ::std::vector<OUString> ImpSvNumberformatScan::sEnglishKeyword = 43 { // Syntax keywords in English (USA) 44 //! All keywords MUST be UPPERCASE! In same order as NfKeywordTable 45 "", // NF_KEY_NONE 0 46 "E", // NF_KEY_E Exponent 47 "AM/PM", // NF_KEY_AMPM AM/PM 48 "A/P", // NF_KEY_AP AM/PM short 49 "M", // NF_KEY_MI Minute 50 "MM", // NF_KEY_MMI Minute 02 51 "M", // NF_KEY_M month (!) 52 "MM", // NF_KEY_MM month 02 (!) 53 "MMM", // NF_KEY_MMM month short name 54 "MMMM", // NF_KEY_MMMM month long name 55 "H", // NF_KEY_H hour 56 "HH", // NF_KEY_HH hour 02 57 "S", // NF_KEY_S Second 58 "SS", // NF_KEY_SS Second 02 59 "Q", // NF_KEY_Q Quarter short 'Q' 60 "QQ", // NF_KEY_QQ Quarter long 61 "D", // NF_KEY_D day of month 62 "DD", // NF_KEY_DD day of month 02 63 "DDD", // NF_KEY_DDD day of week short 64 "DDDD", // NF_KEY_DDDD day of week long 65 "YY", // NF_KEY_YY year two digits 66 "YYYY", // NF_KEY_YYYY year four digits 67 "NN", // NF_KEY_NN Day of week short 68 "NNNN", // NF_KEY_NNNN Day of week long incl. separator 69 "CCC", // NF_KEY_CCC Currency abbreviation 70 "GENERAL", // NF_KEY_GENERAL General / Standard 71 "NNN", // NF_KEY_NNN Day of week long 72 "WW", // NF_KEY_WW Week of year 73 "MMMMM", // NF_KEY_MMMMM first letter of month name 74 "", // NF_KEY_UNUSED4, 75 "", // NF_KEY_UNUSED5, // was quarter word, not used anymore from SRC631 on (26.04.01) 76 "TRUE", // NF_KEY_TRUE boolean true 77 "FALSE", // NF_KEY_FALSE boolean false 78 "BOOLEAN", // NF_KEY_BOOLEAN boolean 79 "COLOR", // NF_KEY_COLOR color 80 // colours 81 "BLACK", // NF_KEY_BLACK 82 "BLUE", // NF_KEY_BLUE 83 "GREEN", // NF_KEY_GREEN 84 "CYAN", // NF_KEY_CYAN 85 "RED", // NF_KEY_RED 86 "MAGENTA", // NF_KEY_MAGENTA 87 "BROWN", // NF_KEY_BROWN 88 "GREY", // NF_KEY_GREY 89 "YELLOW", // NF_KEY_YELLOW 90 "WHITE", // NF_KEY_WHITE 91 // preset new calendar keywords 92 "AAA", // NF_KEY_AAA 93 "AAAA", // NF_KEY_AAAA 94 "E", // NF_KEY_EC 95 "EE", // NF_KEY_EEC 96 "G", // NF_KEY_G 97 "GG", // NF_KEY_GG 98 "GGG", // NF_KEY_GGG 99 "R", // NF_KEY_R 100 "RR", // NF_KEY_RR 101 "t" // NF_KEY_THAI_T Thai T modifier, speciality of Thai Excel, only used with Thai locale and converted to [NatNum1] 102 }; // only exception as lowercase 103 104 ::std::vector<Color> ImpSvNumberformatScan::StandardColor; 105 bool ImpSvNumberformatScan::bStandardColorNeedInitialization = true; 106 107 const OUString ImpSvNumberformatScan::sErrStr = "###"; 108 109 ImpSvNumberformatScan::ImpSvNumberformatScan( SvNumberFormatter* pFormatterP ) 110 : maNullDate( 30, 12, 1899) 111 , eNewLnge(LANGUAGE_DONTKNOW) 112 , eTmpLnge(LANGUAGE_DONTKNOW) 113 , nCurrPos(-1) 114 { 115 pFormatter = pFormatterP; 116 xNFC = css::i18n::NumberFormatMapper::create( pFormatter->GetComponentContext() ); 117 bConvertMode = false; 118 bConvertSystemToSystem = false; 119 120 sKeyword[NF_KEY_E] = sEnglishKeyword[NF_KEY_E]; // Exponent 121 sKeyword[NF_KEY_AMPM] = sEnglishKeyword[NF_KEY_AMPM]; // AM/PM 122 sKeyword[NF_KEY_AP] = sEnglishKeyword[NF_KEY_AP]; // AM/PM short 123 sKeyword[NF_KEY_MI] = sEnglishKeyword[NF_KEY_MI]; // Minute 124 sKeyword[NF_KEY_MMI] = sEnglishKeyword[NF_KEY_MMI]; // Minute 02 125 sKeyword[NF_KEY_S] = sEnglishKeyword[NF_KEY_S]; // Second 126 sKeyword[NF_KEY_SS] = sEnglishKeyword[NF_KEY_SS]; // Second 02 127 sKeyword[NF_KEY_Q] = sEnglishKeyword[NF_KEY_Q]; // Quarter short 'Q' 128 sKeyword[NF_KEY_QQ] = sEnglishKeyword[NF_KEY_QQ]; // Quarter long 129 sKeyword[NF_KEY_NN] = sEnglishKeyword[NF_KEY_NN]; // Day of week short 130 sKeyword[NF_KEY_NNN] = sEnglishKeyword[NF_KEY_NNN]; // Day of week long 131 sKeyword[NF_KEY_NNNN] = sEnglishKeyword[NF_KEY_NNNN]; // Day of week long incl. separator 132 sKeyword[NF_KEY_WW] = sEnglishKeyword[NF_KEY_WW]; // Week of year 133 sKeyword[NF_KEY_CCC] = sEnglishKeyword[NF_KEY_CCC]; // Currency abbreviation 134 bKeywordsNeedInit = true; // locale dependent keywords 135 bCompatCurNeedInit = true; // locale dependent compatibility currency strings 136 137 if ( bStandardColorNeedInitialization ) 138 { 139 bStandardColorNeedInitialization = false; 140 StandardColor.push_back( Color(COL_BLACK) ); 141 StandardColor.push_back( Color(COL_LIGHTBLUE) ); 142 StandardColor.push_back( Color(COL_LIGHTGREEN) ); 143 StandardColor.push_back( Color(COL_LIGHTCYAN) ); 144 StandardColor.push_back( Color(COL_LIGHTRED) ); 145 StandardColor.push_back( Color(COL_LIGHTMAGENTA) ); 146 StandardColor.push_back( Color(COL_BROWN) ); 147 StandardColor.push_back( Color(COL_GRAY) ); 148 StandardColor.push_back( Color(COL_YELLOW) ); 149 StandardColor.push_back( Color(COL_WHITE) ); 150 } 151 152 nStandardPrec = 2; 153 154 Reset(); 155 } 156 157 ImpSvNumberformatScan::~ImpSvNumberformatScan() 158 { 159 Reset(); 160 } 161 162 void ImpSvNumberformatScan::ChangeIntl() 163 { 164 bKeywordsNeedInit = true; 165 bCompatCurNeedInit = true; 166 // may be initialized by InitSpecialKeyword() 167 sKeyword[NF_KEY_TRUE].clear(); 168 sKeyword[NF_KEY_FALSE].clear(); 169 } 170 171 void ImpSvNumberformatScan::InitSpecialKeyword( NfKeywordIndex eIdx ) const 172 { 173 switch ( eIdx ) 174 { 175 case NF_KEY_TRUE : 176 const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_TRUE] = 177 pFormatter->GetCharClass()->uppercase( pFormatter->GetLocaleData()->getTrueWord() ); 178 if ( sKeyword[NF_KEY_TRUE].isEmpty() ) 179 { 180 SAL_WARN( "svl.numbers", "InitSpecialKeyword: TRUE_WORD?" ); 181 const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_TRUE] = sEnglishKeyword[NF_KEY_TRUE]; 182 } 183 break; 184 case NF_KEY_FALSE : 185 const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_FALSE] = 186 pFormatter->GetCharClass()->uppercase( pFormatter->GetLocaleData()->getFalseWord() ); 187 if ( sKeyword[NF_KEY_FALSE].isEmpty() ) 188 { 189 SAL_WARN( "svl.numbers", "InitSpecialKeyword: FALSE_WORD?" ); 190 const_cast<ImpSvNumberformatScan*>(this)->sKeyword[NF_KEY_FALSE] = sEnglishKeyword[NF_KEY_FALSE]; 191 } 192 break; 193 default: 194 SAL_WARN( "svl.numbers", "InitSpecialKeyword: unknown request" ); 195 } 196 } 197 198 void ImpSvNumberformatScan::InitCompatCur() const 199 { 200 ImpSvNumberformatScan* pThis = const_cast<ImpSvNumberformatScan*>(this); 201 // currency symbol for old style ("automatic") compatibility format codes 202 pFormatter->GetCompatibilityCurrency( pThis->sCurSymbol, pThis->sCurAbbrev ); 203 // currency symbol upper case 204 pThis->sCurString = pFormatter->GetCharClass()->uppercase( sCurSymbol ); 205 bCompatCurNeedInit = false; 206 } 207 208 void ImpSvNumberformatScan::InitKeywords() const 209 { 210 if ( !bKeywordsNeedInit ) 211 return ; 212 const_cast<ImpSvNumberformatScan*>(this)->SetDependentKeywords(); 213 bKeywordsNeedInit = false; 214 } 215 216 /** Extract the name of General, Standard, Whatever, ignoring leading modifiers 217 such as [NatNum1]. */ 218 static OUString lcl_extractStandardGeneralName( const OUString & rCode ) 219 { 220 OUString aStr; 221 const sal_Unicode* p = rCode.getStr(); 222 const sal_Unicode* const pStop = p + rCode.getLength(); 223 const sal_Unicode* pBeg = p; // name begins here 224 bool bMod = false; 225 bool bDone = false; 226 while (p < pStop && !bDone) 227 { 228 switch (*p) 229 { 230 case '[': 231 bMod = true; 232 break; 233 case ']': 234 if (bMod) 235 { 236 bMod = false; 237 pBeg = p+1; 238 } 239 // else: would be a locale data error, easily to be spotted in 240 // UI dialog 241 break; 242 case ';': 243 if (!bMod) 244 { 245 bDone = true; 246 --p; // put back, increment by one follows 247 } 248 break; 249 } 250 ++p; 251 if (bMod) 252 { 253 pBeg = p; 254 } 255 } 256 if (pBeg < p) 257 { 258 aStr = rCode.copy( pBeg - rCode.getStr(), p - pBeg); 259 } 260 return aStr; 261 } 262 263 void ImpSvNumberformatScan::SetDependentKeywords() 264 { 265 using namespace ::com::sun::star; 266 using namespace ::com::sun::star::uno; 267 268 const CharClass* pCharClass = pFormatter->GetCharClass(); 269 const LocaleDataWrapper* pLocaleData = pFormatter->GetLocaleData(); 270 // #80023# be sure to generate keywords for the loaded Locale, not for the 271 // requested Locale, otherwise number format codes might not match 272 const LanguageTag& rLoadedLocale = pLocaleData->getLoadedLanguageTag(); 273 LanguageType eLang = rLoadedLocale.getLanguageType( false); 274 275 i18n::NumberFormatCode aFormat = xNFC->getFormatCode( NF_NUMBER_STANDARD, rLoadedLocale.getLocale() ); 276 sNameStandardFormat = lcl_extractStandardGeneralName( aFormat.Code ); 277 sKeyword[NF_KEY_GENERAL] = pCharClass->uppercase( sNameStandardFormat ); 278 279 // preset new calendar keywords 280 sKeyword[NF_KEY_AAA] = sEnglishKeyword[NF_KEY_AAA]; 281 sKeyword[NF_KEY_AAAA] = sEnglishKeyword[NF_KEY_AAAA]; 282 sKeyword[NF_KEY_EC] = sEnglishKeyword[NF_KEY_EC]; 283 sKeyword[NF_KEY_EEC] = sEnglishKeyword[NF_KEY_EEC]; 284 sKeyword[NF_KEY_G] = sEnglishKeyword[NF_KEY_G]; 285 sKeyword[NF_KEY_GG] = sEnglishKeyword[NF_KEY_GG]; 286 sKeyword[NF_KEY_GGG] = sEnglishKeyword[NF_KEY_GGG]; 287 sKeyword[NF_KEY_R] = sEnglishKeyword[NF_KEY_R]; 288 sKeyword[NF_KEY_RR] = sEnglishKeyword[NF_KEY_RR]; 289 290 // Thai T NatNum special. Other locale's small letter 't' results in upper 291 // case comparison not matching but length does in conversion mode. Ugly. 292 if (eLang == LANGUAGE_THAI) 293 { 294 sKeyword[NF_KEY_THAI_T] = "T"; 295 } 296 else 297 { 298 sKeyword[NF_KEY_THAI_T] = sEnglishKeyword[NF_KEY_THAI_T]; 299 } 300 if ( eLang.anyOf( 301 LANGUAGE_GERMAN, 302 LANGUAGE_GERMAN_SWISS, 303 LANGUAGE_GERMAN_AUSTRIAN, 304 LANGUAGE_GERMAN_LUXEMBOURG, 305 LANGUAGE_GERMAN_LIECHTENSTEIN)) 306 { 307 //! all capital letters 308 sKeyword[NF_KEY_M] = "M"; // month 1 309 sKeyword[NF_KEY_MM] = "MM"; // month 01 310 sKeyword[NF_KEY_MMM] = "MMM"; // month Jan 311 sKeyword[NF_KEY_MMMM] = "MMMM"; // month Januar 312 sKeyword[NF_KEY_MMMMM] = "MMMMM"; // month J 313 sKeyword[NF_KEY_H] = "H"; // hour 2 314 sKeyword[NF_KEY_HH] = "HH"; // hour 02 315 sKeyword[NF_KEY_D] = "T"; 316 sKeyword[NF_KEY_DD] = "TT"; 317 sKeyword[NF_KEY_DDD] = "TTT"; 318 sKeyword[NF_KEY_DDDD] = "TTTT"; 319 sKeyword[NF_KEY_YY] = "JJ"; 320 sKeyword[NF_KEY_YYYY] = "JJJJ"; 321 sKeyword[NF_KEY_BOOLEAN] = "LOGISCH"; 322 sKeyword[NF_KEY_COLOR] = "FARBE"; 323 sKeyword[NF_KEY_BLACK] = "SCHWARZ"; 324 sKeyword[NF_KEY_BLUE] = "BLAU"; 325 sKeyword[NF_KEY_GREEN] = OUString( "GR" "\xDC" "N", 4, RTL_TEXTENCODING_ISO_8859_1 ); 326 sKeyword[NF_KEY_CYAN] = "CYAN"; 327 sKeyword[NF_KEY_RED] = "ROT"; 328 sKeyword[NF_KEY_MAGENTA] = "MAGENTA"; 329 sKeyword[NF_KEY_BROWN] = "BRAUN"; 330 sKeyword[NF_KEY_GREY] = "GRAU"; 331 sKeyword[NF_KEY_YELLOW] = "GELB"; 332 sKeyword[NF_KEY_WHITE] = "WEISS"; 333 } 334 else 335 { 336 // day 337 if ( eLang.anyOf( 338 LANGUAGE_ITALIAN, 339 LANGUAGE_ITALIAN_SWISS)) 340 { 341 sKeyword[NF_KEY_D] = "G"; 342 sKeyword[NF_KEY_DD] = "GG"; 343 sKeyword[NF_KEY_DDD] = "GGG"; 344 sKeyword[NF_KEY_DDDD] = "GGGG"; 345 // must exchange the era code, same as Xcl 346 sKeyword[NF_KEY_G] = "X"; 347 sKeyword[NF_KEY_GG] = "XX"; 348 sKeyword[NF_KEY_GGG] = "XXX"; 349 } 350 else if ( eLang.anyOf( 351 LANGUAGE_FRENCH, 352 LANGUAGE_FRENCH_BELGIAN, 353 LANGUAGE_FRENCH_CANADIAN, 354 LANGUAGE_FRENCH_SWISS, 355 LANGUAGE_FRENCH_LUXEMBOURG, 356 LANGUAGE_FRENCH_MONACO)) 357 { 358 sKeyword[NF_KEY_D] = "J"; 359 sKeyword[NF_KEY_DD] = "JJ"; 360 sKeyword[NF_KEY_DDD] = "JJJ"; 361 sKeyword[NF_KEY_DDDD] = "JJJJ"; 362 } 363 else if ( eLang == LANGUAGE_FINNISH ) 364 { 365 sKeyword[NF_KEY_D] = "P"; 366 sKeyword[NF_KEY_DD] = "PP"; 367 sKeyword[NF_KEY_DDD] = "PPP"; 368 sKeyword[NF_KEY_DDDD] = "PPPP"; 369 } 370 else 371 { 372 sKeyword[NF_KEY_D] = sEnglishKeyword[NF_KEY_D]; 373 sKeyword[NF_KEY_DD] = sEnglishKeyword[NF_KEY_DD]; 374 sKeyword[NF_KEY_DDD] = sEnglishKeyword[NF_KEY_DDD]; 375 sKeyword[NF_KEY_DDDD] = sEnglishKeyword[NF_KEY_DDDD]; 376 } 377 // month 378 if ( eLang == LANGUAGE_FINNISH ) 379 { 380 sKeyword[NF_KEY_M] = "K"; 381 sKeyword[NF_KEY_MM] = "KK"; 382 sKeyword[NF_KEY_MMM] = "KKK"; 383 sKeyword[NF_KEY_MMMM] = "KKKK"; 384 sKeyword[NF_KEY_MMMMM] = "KKKKK"; 385 } 386 else 387 { 388 sKeyword[NF_KEY_M] = sEnglishKeyword[NF_KEY_M]; 389 sKeyword[NF_KEY_MM] = sEnglishKeyword[NF_KEY_MM]; 390 sKeyword[NF_KEY_MMM] = sEnglishKeyword[NF_KEY_MMM]; 391 sKeyword[NF_KEY_MMMM] = sEnglishKeyword[NF_KEY_MMMM]; 392 sKeyword[NF_KEY_MMMMM] = sEnglishKeyword[NF_KEY_MMMMM]; 393 } 394 // year 395 if ( eLang.anyOf( 396 LANGUAGE_ITALIAN, 397 LANGUAGE_ITALIAN_SWISS, 398 LANGUAGE_FRENCH, 399 LANGUAGE_FRENCH_BELGIAN, 400 LANGUAGE_FRENCH_CANADIAN, 401 LANGUAGE_FRENCH_SWISS, 402 LANGUAGE_FRENCH_LUXEMBOURG, 403 LANGUAGE_FRENCH_MONACO, 404 LANGUAGE_PORTUGUESE, 405 LANGUAGE_PORTUGUESE_BRAZILIAN, 406 LANGUAGE_SPANISH_MODERN, 407 LANGUAGE_SPANISH_DATED, 408 LANGUAGE_SPANISH_MEXICAN, 409 LANGUAGE_SPANISH_GUATEMALA, 410 LANGUAGE_SPANISH_COSTARICA, 411 LANGUAGE_SPANISH_PANAMA, 412 LANGUAGE_SPANISH_DOMINICAN_REPUBLIC, 413 LANGUAGE_SPANISH_VENEZUELA, 414 LANGUAGE_SPANISH_COLOMBIA, 415 LANGUAGE_SPANISH_PERU, 416 LANGUAGE_SPANISH_ARGENTINA, 417 LANGUAGE_SPANISH_ECUADOR, 418 LANGUAGE_SPANISH_CHILE, 419 LANGUAGE_SPANISH_URUGUAY, 420 LANGUAGE_SPANISH_PARAGUAY, 421 LANGUAGE_SPANISH_BOLIVIA, 422 LANGUAGE_SPANISH_EL_SALVADOR, 423 LANGUAGE_SPANISH_HONDURAS, 424 LANGUAGE_SPANISH_NICARAGUA, 425 LANGUAGE_SPANISH_PUERTO_RICO)) 426 { 427 sKeyword[NF_KEY_YY] = "AA"; 428 sKeyword[NF_KEY_YYYY] = "AAAA"; 429 // must exchange the day of week name code, same as Xcl 430 sKeyword[NF_KEY_AAA] = "OOO"; 431 sKeyword[NF_KEY_AAAA] = "OOOO"; 432 } 433 else if ( eLang.anyOf( 434 LANGUAGE_DUTCH, 435 LANGUAGE_DUTCH_BELGIAN)) 436 { 437 sKeyword[NF_KEY_YY] = "JJ"; 438 sKeyword[NF_KEY_YYYY] = "JJJJ"; 439 } 440 else if ( eLang == LANGUAGE_FINNISH ) 441 { 442 sKeyword[NF_KEY_YY] = "VV"; 443 sKeyword[NF_KEY_YYYY] = "VVVV"; 444 } 445 else 446 { 447 sKeyword[NF_KEY_YY] = sEnglishKeyword[NF_KEY_YY]; 448 sKeyword[NF_KEY_YYYY] = sEnglishKeyword[NF_KEY_YYYY]; 449 } 450 // hour 451 if ( eLang.anyOf( 452 LANGUAGE_DUTCH, 453 LANGUAGE_DUTCH_BELGIAN)) 454 { 455 sKeyword[NF_KEY_H] = "U"; 456 sKeyword[NF_KEY_HH] = "UU"; 457 } 458 else if ( eLang.anyOf( 459 LANGUAGE_FINNISH, 460 LANGUAGE_SWEDISH, 461 LANGUAGE_SWEDISH_FINLAND, 462 LANGUAGE_DANISH, 463 LANGUAGE_NORWEGIAN, 464 LANGUAGE_NORWEGIAN_BOKMAL, 465 LANGUAGE_NORWEGIAN_NYNORSK)) 466 { 467 sKeyword[NF_KEY_H] = "T"; 468 sKeyword[NF_KEY_HH] = "TT"; 469 } 470 else 471 { 472 sKeyword[NF_KEY_H] = sEnglishKeyword[NF_KEY_H]; 473 sKeyword[NF_KEY_HH] = sEnglishKeyword[NF_KEY_HH]; 474 } 475 // boolean 476 sKeyword[NF_KEY_BOOLEAN] = sEnglishKeyword[NF_KEY_BOOLEAN]; 477 // colours 478 sKeyword[NF_KEY_COLOR] = sEnglishKeyword[NF_KEY_COLOR]; 479 sKeyword[NF_KEY_BLACK] = sEnglishKeyword[NF_KEY_BLACK]; 480 sKeyword[NF_KEY_BLUE] = sEnglishKeyword[NF_KEY_BLUE]; 481 sKeyword[NF_KEY_GREEN] = sEnglishKeyword[NF_KEY_GREEN]; 482 sKeyword[NF_KEY_CYAN] = sEnglishKeyword[NF_KEY_CYAN]; 483 sKeyword[NF_KEY_RED] = sEnglishKeyword[NF_KEY_RED]; 484 sKeyword[NF_KEY_MAGENTA] = sEnglishKeyword[NF_KEY_MAGENTA]; 485 sKeyword[NF_KEY_BROWN] = sEnglishKeyword[NF_KEY_BROWN]; 486 sKeyword[NF_KEY_GREY] = sEnglishKeyword[NF_KEY_GREY]; 487 sKeyword[NF_KEY_YELLOW] = sEnglishKeyword[NF_KEY_YELLOW]; 488 sKeyword[NF_KEY_WHITE] = sEnglishKeyword[NF_KEY_WHITE]; 489 } 490 491 // boolean keywords 492 InitSpecialKeyword( NF_KEY_TRUE ); 493 InitSpecialKeyword( NF_KEY_FALSE ); 494 495 // compatibility currency strings 496 InitCompatCur(); 497 } 498 499 void ImpSvNumberformatScan::ChangeNullDate(sal_uInt16 nDay, sal_uInt16 nMonth, sal_Int16 nYear) 500 { 501 maNullDate = Date(nDay, nMonth, nYear); 502 if (!maNullDate.IsValidDate()) 503 { 504 maNullDate.Normalize(); 505 SAL_WARN("svl.numbers","ImpSvNumberformatScan::ChangeNullDate - not valid" 506 " d: " << nDay << " m: " << nMonth << " y: " << nYear << " normalized to" 507 " d: " << maNullDate.GetDay() << " m: " << maNullDate.GetMonth() << " y: " << maNullDate.GetYear()); 508 } 509 } 510 511 void ImpSvNumberformatScan::ChangeStandardPrec(sal_uInt16 nPrec) 512 { 513 nStandardPrec = nPrec; 514 } 515 516 Color* ImpSvNumberformatScan::GetColor(OUString& sStr) 517 { 518 OUString sString = pFormatter->GetCharClass()->uppercase(sStr); 519 const NfKeywordTable & rKeyword = GetKeywords(); 520 size_t i = 0; 521 while (i < NF_MAX_DEFAULT_COLORS && sString != rKeyword[NF_KEY_FIRSTCOLOR+i] ) 522 { 523 i++; 524 } 525 LanguageType eLang = pFormatter->GetLocaleData()->getLoadedLanguageTag().getLanguageType( false); 526 if ( i >= NF_MAX_DEFAULT_COLORS && eLang.anyOf( 527 LANGUAGE_GERMAN, 528 LANGUAGE_GERMAN_SWISS, 529 LANGUAGE_GERMAN_AUSTRIAN, 530 LANGUAGE_GERMAN_LUXEMBOURG, 531 LANGUAGE_GERMAN_LIECHTENSTEIN )) // only German use localized color names 532 { 533 size_t j = 0; 534 while ( j < NF_MAX_DEFAULT_COLORS && sString != sEnglishKeyword[NF_KEY_FIRSTCOLOR + j] ) 535 { 536 ++j; 537 } 538 if ( j < NF_MAX_DEFAULT_COLORS ) 539 { 540 i = j; 541 } 542 } 543 544 Color* pResult = nullptr; 545 if (i >= NF_MAX_DEFAULT_COLORS) 546 { 547 const OUString& rColorWord = rKeyword[NF_KEY_COLOR]; 548 if (sString.startsWith(rColorWord) || sString.startsWith(sEnglishKeyword[NF_KEY_COLOR])) 549 { 550 sal_Int32 nPos = sString.startsWith(rColorWord) ? 551 rColorWord.getLength() : 552 sEnglishKeyword[NF_KEY_COLOR].getLength(); 553 sStr = sStr.copy(nPos); 554 sStr = comphelper::string::strip(sStr, ' '); 555 if (bConvertMode) 556 { 557 pFormatter->ChangeIntl(eNewLnge); 558 sStr = GetKeywords()[NF_KEY_COLOR] + sStr; // Color -> FARBE 559 pFormatter->ChangeIntl(eTmpLnge); 560 } 561 else 562 { 563 sStr = rColorWord + sStr; 564 } 565 sString = sString.copy(nPos); 566 sString = comphelper::string::strip(sString, ' '); 567 568 if ( CharClass::isAsciiNumeric( sString ) ) 569 { 570 long nIndex = sString.toInt32(); 571 if (nIndex > 0 && nIndex <= 64) 572 { 573 pResult = pFormatter->GetUserDefColor((sal_uInt16)nIndex-1); 574 } 575 } 576 } 577 } 578 else 579 { 580 sStr.clear(); 581 if (bConvertMode) 582 { 583 pFormatter->ChangeIntl(eNewLnge); 584 sStr = GetKeywords()[NF_KEY_FIRSTCOLOR+i]; // red -> rot 585 pFormatter->ChangeIntl(eTmpLnge); 586 } 587 else 588 { 589 sStr = rKeyword[NF_KEY_FIRSTCOLOR+i]; 590 } 591 pResult = &(StandardColor[i]); 592 } 593 return pResult; 594 } 595 596 short ImpSvNumberformatScan::GetKeyWord( const OUString& sSymbol, sal_Int32 nPos ) const 597 { 598 OUString sString = pFormatter->GetCharClass()->uppercase( sSymbol, nPos, sSymbol.getLength() - nPos ); 599 const NfKeywordTable & rKeyword = GetKeywords(); 600 // #77026# for the Xcl perverts: the GENERAL keyword is recognized anywhere 601 if ( sString.startsWith( rKeyword[NF_KEY_GENERAL] ) || sString.startsWith( sEnglishKeyword[NF_KEY_GENERAL] ) ) 602 { 603 return NF_KEY_GENERAL; 604 } 605 //! MUST be a reverse search to find longer strings first 606 short i = NF_KEYWORD_ENTRIES_COUNT-1; 607 bool bFound = false; 608 for ( ; i > NF_KEY_LASTKEYWORD_SO5; --i ) 609 { 610 bFound = sString.startsWith(rKeyword[i]); 611 if ( bFound ) 612 { 613 break; 614 } 615 } 616 // new keywords take precedence over old keywords 617 if ( !bFound ) 618 { 619 // skip the gap of colors et al between new and old keywords and search on 620 i = NF_KEY_LASTKEYWORD; 621 while ( i > 0 && sString.indexOf(rKeyword[i]) != 0 ) 622 { 623 i--; 624 } 625 if ( i > NF_KEY_LASTOLDKEYWORD && sString != rKeyword[i] ) 626 { 627 // found something, but maybe it's something else? 628 // e.g. new NNN is found in NNNN, for NNNN we must search on 629 short j = i - 1; 630 while ( j > 0 && sString.indexOf(rKeyword[j]) != 0 ) 631 { 632 j--; 633 } 634 if ( j && rKeyword[j].getLength() > rKeyword[i].getLength() ) 635 { 636 return j; 637 } 638 } 639 LanguageType eLang = pFormatter->GetLocaleData()->getLoadedLanguageTag().getLanguageType( false); 640 if ( i == 0 && eLang.anyOf( LANGUAGE_GERMAN, 641 LANGUAGE_GERMAN_SWISS, 642 LANGUAGE_GERMAN_AUSTRIAN, 643 LANGUAGE_GERMAN_LUXEMBOURG, 644 LANGUAGE_GERMAN_LIECHTENSTEIN, 645 LANGUAGE_DUTCH, 646 LANGUAGE_DUTCH_BELGIAN, 647 LANGUAGE_FRENCH, 648 LANGUAGE_FRENCH_BELGIAN, 649 LANGUAGE_FRENCH_CANADIAN, 650 LANGUAGE_FRENCH_SWISS, 651 LANGUAGE_FRENCH_LUXEMBOURG, 652 LANGUAGE_FRENCH_MONACO, 653 LANGUAGE_FINNISH, 654 LANGUAGE_ITALIAN, 655 LANGUAGE_ITALIAN_SWISS, 656 LANGUAGE_DANISH, 657 LANGUAGE_NORWEGIAN, 658 LANGUAGE_NORWEGIAN_BOKMAL, 659 LANGUAGE_NORWEGIAN_NYNORSK, 660 LANGUAGE_SWEDISH, 661 LANGUAGE_SWEDISH_FINLAND, 662 LANGUAGE_PORTUGUESE, 663 LANGUAGE_PORTUGUESE_BRAZILIAN, 664 LANGUAGE_SPANISH_MODERN, 665 LANGUAGE_SPANISH_DATED, 666 LANGUAGE_SPANISH_MEXICAN, 667 LANGUAGE_SPANISH_GUATEMALA, 668 LANGUAGE_SPANISH_COSTARICA, 669 LANGUAGE_SPANISH_PANAMA, 670 LANGUAGE_SPANISH_DOMINICAN_REPUBLIC, 671 LANGUAGE_SPANISH_VENEZUELA, 672 LANGUAGE_SPANISH_COLOMBIA, 673 LANGUAGE_SPANISH_PERU, 674 LANGUAGE_SPANISH_ARGENTINA, 675 LANGUAGE_SPANISH_ECUADOR, 676 LANGUAGE_SPANISH_CHILE, 677 LANGUAGE_SPANISH_URUGUAY, 678 LANGUAGE_SPANISH_PARAGUAY, 679 LANGUAGE_SPANISH_BOLIVIA, 680 LANGUAGE_SPANISH_EL_SALVADOR, 681 LANGUAGE_SPANISH_HONDURAS, 682 LANGUAGE_SPANISH_NICARAGUA, 683 LANGUAGE_SPANISH_PUERTO_RICO ) ) 684 { 685 // no localized keyword, try English keywords 686 i = NF_KEY_LASTKEYWORD; 687 while ( i > 0 && sString.indexOf(sEnglishKeyword[i]) != 0 ) 688 { 689 i--; 690 } 691 if ( i > NF_KEY_LASTOLDKEYWORD && sString != sEnglishKeyword[i] ) 692 { 693 // found something, but maybe it's something else? 694 // e.g. new NNN is found in NNNN, for NNNN we must search on 695 short j = i - 1; 696 while ( j > 0 && sString.indexOf(sEnglishKeyword[j]) != 0 ) 697 { 698 j--; 699 } 700 if ( j && sEnglishKeyword[j].getLength() > sEnglishKeyword[i].getLength() ) 701 { 702 return j; 703 } 704 } 705 } 706 } 707 // The Thai T NatNum modifier during Xcl import. 708 if (i == 0 && bConvertMode && 709 sString[0] == 'T' && 710 eTmpLnge == LANGUAGE_ENGLISH_US && 711 MsLangId::getRealLanguage( eNewLnge) == LANGUAGE_THAI) 712 { 713 i = NF_KEY_THAI_T; 714 } 715 return i; // 0 => not found 716 } 717 718 /** 719 * Next_Symbol 720 * 721 * Splits up the input for further processing (by the Turing machine). 722 * 723 * Starting state = SsStar 724 * 725 * ---------------+-------------------+---------------------------+--------------- 726 * Old state | Character read | Event | New state 727 * ---------------+-------------------+---------------------------+--------------- 728 * SsStart | Character | Symbol = Character | SsGetWord 729 * | " | Type = String | SsGetString 730 * | \ | Type = String | SsGetChar 731 * | * | Type = Star | SsGetStar 732 * | _ | Type = Blank | SsGetBlank 733 * | @ # 0 ? / . , % [ | Symbol = Character; | 734 * | ] ' Blank | Type = Control character | SsStop 735 * | $ - + ( ) : | Type = String; | 736 * | Else | Symbol = Character | SsStop 737 * ---------------|-------------------+---------------------------+--------------- 738 * SsGetChar | Else | Symbol = Character | SsStop 739 * ---------------+-------------------+---------------------------+--------------- 740 * GetString | " | | SsStop 741 * | Else | Symbol += Character | GetString 742 * ---------------+-------------------+---------------------------+--------------- 743 * SsGetWord | Character | Symbol += Character | 744 * | + - (E+ E-)| Symbol += Character | SsStop 745 * | / (AM/PM)| Symbol += Character | 746 * | Else | Pos--, if Key Type = Word | SsStop 747 * ---------------+-------------------+---------------------------+--------------- 748 * SsGetStar | Else | Symbol += Character | SsStop 749 * | | Mark special case * | 750 * ---------------+-------------------+---------------------------+--------------- 751 * SsGetBlank | Else | Symbol + =Character | SsStop 752 * | | Mark special case _ | 753 * ---------------------------------------------------------------+-------------- 754 * 755 * If we recognize a keyword in the state SsGetWord (even as the symbol's start text) 756 * we write back the rest of the characters! 757 */ 758 759 enum ScanState 760 { 761 SsStop = 0, 762 SsStart = 1, 763 SsGetChar = 2, 764 SsGetString = 3, 765 SsGetWord = 4, 766 SsGetStar = 5, 767 SsGetBlank = 6 768 }; 769 770 short ImpSvNumberformatScan::Next_Symbol( const OUString& rStr, 771 sal_Int32& nPos, 772 OUString& sSymbol ) const 773 { 774 InitKeywords(); 775 const CharClass* pChrCls = pFormatter->GetCharClass(); 776 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); 777 short eType = 0; 778 ScanState eState = SsStart; 779 sSymbol.clear(); 780 while ( nPos < rStr.getLength() && eState != SsStop ) 781 { 782 sal_Unicode cToken = rStr[nPos++]; 783 switch (eState) 784 { 785 case SsStart: 786 // Fetch any currency longer than one character and don't get 787 // confused later on by "E/" or other combinations of letters 788 // and meaningful symbols. Necessary for old automatic currency. 789 // #96158# But don't do it if we're starting a "[...]" section, 790 // for example a "[$...]" new currency symbol to not parse away 791 // "$U" (symbol) of "[$UYU]" (abbreviation). 792 if ( nCurrPos >= 0 && sCurString.getLength() > 1 && 793 nPos-1 + sCurString.getLength() <= rStr.getLength() && 794 !(nPos > 1 && rStr[nPos-2] == '[') ) 795 { 796 OUString aTest = pChrCls->uppercase( rStr.copy( nPos-1, sCurString.getLength() ) ); 797 if ( aTest == sCurString ) 798 { 799 sSymbol = rStr.copy( --nPos, sCurString.getLength() ); 800 nPos = nPos + sSymbol.getLength(); 801 eType = NF_SYMBOLTYPE_STRING; 802 return eType; 803 } 804 } 805 switch (cToken) 806 { 807 case '#': 808 case '0': 809 case '?': 810 case '%': 811 case '@': 812 case '[': 813 case ']': 814 case ',': 815 case '.': 816 case '/': 817 case '\'': 818 case ' ': 819 case ':': 820 case '-': 821 eType = NF_SYMBOLTYPE_DEL; 822 sSymbol += OUStringLiteral1(cToken); 823 eState = SsStop; 824 break; 825 case '*': 826 eType = NF_SYMBOLTYPE_STAR; 827 sSymbol += OUStringLiteral1(cToken); 828 eState = SsGetStar; 829 break; 830 case '_': 831 eType = NF_SYMBOLTYPE_BLANK; 832 sSymbol += OUStringLiteral1(cToken); 833 eState = SsGetBlank; 834 break; 835 case '"': 836 eType = NF_SYMBOLTYPE_STRING; 837 eState = SsGetString; 838 sSymbol += OUStringLiteral1(cToken); 839 break; 840 case '\\': 841 eType = NF_SYMBOLTYPE_STRING; 842 eState = SsGetChar; 843 sSymbol += OUStringLiteral1(cToken); 844 break; 845 case '$': 846 case '+': 847 case '(': 848 case ')': 849 eType = NF_SYMBOLTYPE_STRING; 850 eState = SsStop; 851 sSymbol += OUStringLiteral1(cToken); 852 break; 853 default : 854 if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cToken) || 855 StringEqualsChar( pFormatter->GetNumThousandSep(), cToken) || 856 StringEqualsChar( pFormatter->GetDateSep(), cToken) || 857 StringEqualsChar( pLoc->getTimeSep(), cToken) || 858 StringEqualsChar( pLoc->getTime100SecSep(), cToken)) 859 { 860 // Another separator than pre-known ASCII 861 eType = NF_SYMBOLTYPE_DEL; 862 sSymbol += OUStringLiteral1(cToken); 863 eState = SsStop; 864 } 865 else if ( pChrCls->isLetter( rStr, nPos-1 ) ) 866 { 867 short nTmpType = GetKeyWord( rStr, nPos-1 ); 868 if ( nTmpType ) 869 { 870 bool bCurrency = false; 871 // "Automatic" currency may start with keyword, 872 // like "R" (Rand) and 'R' (era) 873 if ( nCurrPos >= 0 && 874 nPos-1 + sCurString.getLength() <= rStr.getLength() && 875 sCurString.startsWith( sKeyword[nTmpType] ) ) 876 { 877 OUString aTest = pChrCls->uppercase( rStr.copy( nPos-1, sCurString.getLength() ) ); 878 if ( aTest == sCurString ) 879 { 880 bCurrency = true; 881 } 882 } 883 if ( bCurrency ) 884 { 885 eState = SsGetWord; 886 sSymbol += OUStringLiteral1(cToken); 887 } 888 else 889 { 890 eType = nTmpType; 891 sal_Int32 nLen = sKeyword[eType].getLength(); 892 sSymbol = rStr.copy( nPos-1, nLen ); 893 if ((eType == NF_KEY_E || IsAmbiguousE(eType)) && nPos < rStr.getLength()) 894 { 895 sal_Unicode cNext = rStr[nPos]; 896 switch ( cNext ) 897 { 898 case '+' : 899 case '-' : // E+ E- combine to one symbol 900 sSymbol += OUStringLiteral1(cNext); 901 eType = NF_KEY_E; 902 nPos++; 903 break; 904 case '0' : 905 case '#' : // scientific E without sign 906 eType = NF_KEY_E; 907 break; 908 } 909 } 910 nPos--; 911 nPos = nPos + nLen; 912 eState = SsStop; 913 } 914 } 915 else 916 { 917 eState = SsGetWord; 918 sSymbol += OUStringLiteral1(cToken); 919 } 920 } 921 else 922 { 923 eType = NF_SYMBOLTYPE_STRING; 924 eState = SsStop; 925 sSymbol += OUStringLiteral1(cToken); 926 } 927 break; 928 } 929 break; 930 case SsGetChar: 931 sSymbol += OUStringLiteral1(cToken); 932 eState = SsStop; 933 break; 934 case SsGetString: 935 if (cToken == '"') 936 { 937 eState = SsStop; 938 } 939 sSymbol += OUStringLiteral1(cToken); 940 break; 941 case SsGetWord: 942 if ( pChrCls->isLetter( rStr, nPos-1 ) ) 943 { 944 short nTmpType = GetKeyWord( rStr, nPos-1 ); 945 if ( nTmpType ) 946 { 947 // beginning of keyword, stop scan and put back 948 eType = NF_SYMBOLTYPE_STRING; 949 eState = SsStop; 950 nPos--; 951 } 952 else 953 { 954 sSymbol += OUStringLiteral1(cToken); 955 } 956 } 957 else 958 { 959 bool bDontStop = false; 960 sal_Unicode cNext; 961 switch (cToken) 962 { 963 case '/': // AM/PM, A/P 964 if (nPos < rStr.getLength()) 965 { 966 cNext = rStr[nPos]; 967 if ( cNext == 'P' || cNext == 'p' ) 968 { 969 sal_Int32 nLen = sSymbol.getLength(); 970 if ( 1 <= nLen && 971 (sSymbol[0] == 'A' || sSymbol[0] == 'a') && 972 (nLen == 1 || 973 (nLen == 2 && (sSymbol[1] == 'M' || sSymbol[1] == 'm') 974 && (rStr[nPos + 1] == 'M' || rStr[nPos + 1] == 'm')))) 975 { 976 sSymbol += OUStringLiteral1(cToken); 977 bDontStop = true; 978 } 979 } 980 } 981 break; 982 } 983 // anything not recognized will stop the scan 984 if ( eState != SsStop && !bDontStop ) 985 { 986 eState = SsStop; 987 nPos--; 988 eType = NF_SYMBOLTYPE_STRING; 989 } 990 } 991 break; 992 case SsGetStar: 993 eState = SsStop; 994 sSymbol += OUStringLiteral1(cToken); 995 break; 996 case SsGetBlank: 997 eState = SsStop; 998 sSymbol += OUStringLiteral1(cToken); 999 break; 1000 default: 1001 break; 1002 } // of switch 1003 } // of while 1004 if (eState == SsGetWord) 1005 { 1006 eType = NF_SYMBOLTYPE_STRING; 1007 } 1008 return eType; 1009 } 1010 1011 sal_Int32 ImpSvNumberformatScan::Symbol_Division(const OUString& rString) 1012 { 1013 nCurrPos = -1; 1014 // Do we have some sort of currency? 1015 OUString sString = pFormatter->GetCharClass()->uppercase(rString); 1016 sal_Int32 nCPos = 0; 1017 while (nCPos >= 0 && nCPos < sString.getLength()) 1018 { 1019 nCPos = sString.indexOf(GetCurString(),nCPos); 1020 if (nCPos >= 0) 1021 { 1022 // In Quotes? 1023 sal_Int32 nQ = SvNumberformat::GetQuoteEnd( sString, nCPos ); 1024 if ( nQ < 0 ) 1025 { 1026 sal_Unicode c; 1027 if ( nCPos == 0 || 1028 ((c = sString[nCPos-1]) != '"' 1029 && c != '\\') ) // dm can be protected by "dm \d 1030 { 1031 nCurrPos = nCPos; 1032 nCPos = -1; 1033 } 1034 else 1035 { 1036 nCPos++; // Continue search 1037 } 1038 } 1039 else 1040 { 1041 nCPos = nQ + 1; // Continue search 1042 } 1043 } 1044 } 1045 nStringsCnt = 0; 1046 bool bStar = false; // Is set on detecting '*' 1047 Reset(); 1048 1049 sal_Int32 nPos = 0; 1050 const sal_Int32 nLen = rString.getLength(); 1051 while (nPos < nLen && nStringsCnt < NF_MAX_FORMAT_SYMBOLS) 1052 { 1053 nTypeArray[nStringsCnt] = Next_Symbol(rString, nPos, sStrArray[nStringsCnt]); 1054 if (nTypeArray[nStringsCnt] == NF_SYMBOLTYPE_STAR) 1055 { // Monitoring the '*' 1056 if (bStar) 1057 { 1058 return nPos; // Error: double '*' 1059 } 1060 else 1061 { 1062 // Valid only if there is a character following, else we are 1063 // at the end of a code that does not have a fill character 1064 // (yet?). 1065 if (sStrArray[nStringsCnt].getLength() < 2) 1066 return nPos; 1067 bStar = true; 1068 } 1069 } 1070 nStringsCnt++; 1071 } 1072 1073 return 0; // 0 => ok 1074 } 1075 1076 void ImpSvNumberformatScan::SkipStrings(sal_uInt16& i, sal_Int32& nPos) const 1077 { 1078 while (i < nStringsCnt && ( nTypeArray[i] == NF_SYMBOLTYPE_STRING 1079 || nTypeArray[i] == NF_SYMBOLTYPE_BLANK 1080 || nTypeArray[i] == NF_SYMBOLTYPE_STAR) ) 1081 { 1082 nPos = nPos + sStrArray[i].getLength(); 1083 i++; 1084 } 1085 } 1086 1087 sal_uInt16 ImpSvNumberformatScan::PreviousKeyword(sal_uInt16 i) const 1088 { 1089 short res = 0; 1090 if (i > 0 && i < nStringsCnt) 1091 { 1092 i--; 1093 while (i > 0 && nTypeArray[i] <= 0) 1094 { 1095 i--; 1096 } 1097 if (nTypeArray[i] > 0) 1098 { 1099 res = nTypeArray[i]; 1100 } 1101 } 1102 return res; 1103 } 1104 1105 sal_uInt16 ImpSvNumberformatScan::NextKeyword(sal_uInt16 i) const 1106 { 1107 short res = 0; 1108 if (i < nStringsCnt-1) 1109 { 1110 i++; 1111 while (i < nStringsCnt-1 && nTypeArray[i] <= 0) 1112 { 1113 i++; 1114 } 1115 if (nTypeArray[i] > 0) 1116 { 1117 res = nTypeArray[i]; 1118 } 1119 } 1120 return res; 1121 } 1122 1123 short ImpSvNumberformatScan::PreviousType( sal_uInt16 i ) const 1124 { 1125 if ( i > 0 && i < nStringsCnt ) 1126 { 1127 do 1128 { 1129 i--; 1130 } 1131 while ( i > 0 && nTypeArray[i] == NF_SYMBOLTYPE_EMPTY ); 1132 return nTypeArray[i]; 1133 } 1134 return 0; 1135 } 1136 1137 sal_Unicode ImpSvNumberformatScan::PreviousChar(sal_uInt16 i) const 1138 { 1139 sal_Unicode res = ' '; 1140 if (i > 0 && i < nStringsCnt) 1141 { 1142 i--; 1143 while (i > 0 && 1144 ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY || 1145 nTypeArray[i] == NF_SYMBOLTYPE_STRING || 1146 nTypeArray[i] == NF_SYMBOLTYPE_STAR || 1147 nTypeArray[i] == NF_SYMBOLTYPE_BLANK )) 1148 { 1149 i--; 1150 } 1151 if (sStrArray[i].getLength() > 0) 1152 { 1153 res = sStrArray[i][sStrArray[i].getLength()-1]; 1154 } 1155 } 1156 return res; 1157 } 1158 1159 sal_Unicode ImpSvNumberformatScan::NextChar(sal_uInt16 i) const 1160 { 1161 sal_Unicode res = ' '; 1162 if (i < nStringsCnt-1) 1163 { 1164 i++; 1165 while (i < nStringsCnt-1 && 1166 ( nTypeArray[i] == NF_SYMBOLTYPE_EMPTY || 1167 nTypeArray[i] == NF_SYMBOLTYPE_STRING || 1168 nTypeArray[i] == NF_SYMBOLTYPE_STAR || 1169 nTypeArray[i] == NF_SYMBOLTYPE_BLANK)) 1170 { 1171 i++; 1172 } 1173 if (sStrArray[i].getLength() > 0) 1174 { 1175 res = sStrArray[i][0]; 1176 } 1177 } 1178 return res; 1179 } 1180 1181 bool ImpSvNumberformatScan::IsLastBlankBeforeFrac(sal_uInt16 i) const 1182 { 1183 bool res = true; 1184 if (i < nStringsCnt-1) 1185 { 1186 bool bStop = false; 1187 i++; 1188 while (i < nStringsCnt-1 && !bStop) 1189 { 1190 i++; 1191 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL && 1192 sStrArray[i][0] == '/') 1193 { 1194 bStop = true; 1195 } 1196 else if ( ( nTypeArray[i] == NF_SYMBOLTYPE_DEL && 1197 sStrArray[i][0] == ' ') || 1198 nTypeArray[i] == NF_SYMBOLTYPE_STRING ) // integer/fraction delimiter can also be a string 1199 { 1200 res = false; 1201 } 1202 } 1203 if (!bStop) // no '/'{ 1204 { 1205 res = false; 1206 } 1207 } 1208 else 1209 { 1210 res = false; // no '/' any more 1211 } 1212 return res; 1213 } 1214 1215 void ImpSvNumberformatScan::Reset() 1216 { 1217 nStringsCnt = 0; 1218 nResultStringsCnt = 0; 1219 eScannedType = css::util::NumberFormat::UNDEFINED; 1220 bExp = false; 1221 bThousand = false; 1222 nThousand = 0; 1223 bDecSep = false; 1224 nDecPos = (sal_uInt16)-1; 1225 nExpPos = (sal_uInt16)-1; 1226 nBlankPos = (sal_uInt16)-1; 1227 nCntPre = 0; 1228 nCntPost = 0; 1229 nCntExp = 0; 1230 bFrac = false; 1231 bBlank = false; 1232 nNatNumModifier = 0; 1233 } 1234 1235 bool ImpSvNumberformatScan::Is100SecZero( sal_uInt16 i, bool bHadDecSep ) const 1236 { 1237 sal_uInt16 nIndexPre = PreviousKeyword( i ); 1238 return (nIndexPre == NF_KEY_S || nIndexPre == NF_KEY_SS) && 1239 (bHadDecSep || 1240 ( i > 0 && nTypeArray[i-1] == NF_SYMBOLTYPE_STRING)); 1241 // SS"any"00 take "any" as a valid decimal separator 1242 } 1243 1244 sal_Int32 ImpSvNumberformatScan::ScanType() 1245 { 1246 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); 1247 1248 sal_Int32 nPos = 0; 1249 sal_uInt16 i = 0; 1250 short eNewType; 1251 bool bMatchBracket = false; 1252 bool bHaveGeneral = false; // if General/Standard encountered 1253 bool bIsTimeDetected =false; // hour or second found in format 1254 bool bHaveMinute = false; 1255 1256 SkipStrings(i, nPos); 1257 while (i < nStringsCnt) 1258 { 1259 if (nTypeArray[i] > 0) 1260 { // keyword 1261 sal_uInt16 nIndexPre; 1262 sal_uInt16 nIndexNex; 1263 1264 switch (nTypeArray[i]) 1265 { 1266 case NF_KEY_E: // E 1267 eNewType = css::util::NumberFormat::SCIENTIFIC; 1268 break; 1269 case NF_KEY_H: // H 1270 case NF_KEY_HH: // HH 1271 bIsTimeDetected = true; 1272 SAL_FALLTHROUGH; 1273 case NF_KEY_S: // S 1274 case NF_KEY_SS: // SS 1275 if ( !bHaveMinute ) 1276 bIsTimeDetected = true; 1277 SAL_FALLTHROUGH; 1278 case NF_KEY_AMPM: // AM,A,PM,P 1279 case NF_KEY_AP: 1280 eNewType = css::util::NumberFormat::TIME; 1281 break; 1282 case NF_KEY_M: // M 1283 case NF_KEY_MM: // MM 1284 case NF_KEY_MI: // M minute detected in Finnish 1285 case NF_KEY_MMI: // MM 1286 /* Minute or month. 1287 Minute if one of: 1288 * preceded by time keyword H (ignoring separators) 1289 * followed by time keyword S (ignoring separators) 1290 * H or S was detected and this is the first M following 1291 * preceded by '[' amount bracket 1292 Else month. 1293 That are the Excel rules. BUT, we break it because certainly 1294 in something like {HH YYYY-MM-DD} the MM is NOT meant to be 1295 minute, so not if MM is between YY and DD or DD and YY. 1296 Actually not if any date specific keyword followed a time 1297 setting keyword. 1298 */ 1299 nIndexPre = PreviousKeyword(i); 1300 nIndexNex = NextKeyword(i); 1301 if (nIndexPre == NF_KEY_H || // H 1302 nIndexPre == NF_KEY_HH || // HH 1303 nIndexNex == NF_KEY_S || // S 1304 nIndexNex == NF_KEY_SS || // SS 1305 bIsTimeDetected || // tdf#101147 1306 PreviousChar(i) == '[' ) // [M 1307 { 1308 eNewType = css::util::NumberFormat::TIME; 1309 if ( nTypeArray[i] == NF_KEY_M || nTypeArray[i] == NF_KEY_MM ) 1310 { 1311 nTypeArray[i] -= 2; // 6 -> 4, 7 -> 5 1312 } 1313 bIsTimeDetected = false; // next M should be month 1314 bHaveMinute = true; 1315 } 1316 else 1317 { 1318 eNewType = css::util::NumberFormat::DATE; 1319 if ( nTypeArray[i] == NF_KEY_MI || nTypeArray[i] == NF_KEY_MMI ) 1320 { // follow resolution of tdf#33689 for Finnish 1321 nTypeArray[i] += 2; // 4 -> 6, 5 -> 7 1322 } 1323 } 1324 break; 1325 case NF_KEY_MMM: // MMM 1326 case NF_KEY_MMMM: // MMMM 1327 case NF_KEY_MMMMM: // MMMMM 1328 case NF_KEY_Q: // Q 1329 case NF_KEY_QQ: // QQ 1330 case NF_KEY_D: // D 1331 case NF_KEY_DD: // DD 1332 case NF_KEY_DDD: // DDD 1333 case NF_KEY_DDDD: // DDDD 1334 case NF_KEY_YY: // YY 1335 case NF_KEY_YYYY: // YYYY 1336 case NF_KEY_NN: // NN 1337 case NF_KEY_NNN: // NNN 1338 case NF_KEY_NNNN: // NNNN 1339 case NF_KEY_WW : // WW 1340 case NF_KEY_AAA : // AAA 1341 case NF_KEY_AAAA : // AAAA 1342 case NF_KEY_EC : // E 1343 case NF_KEY_EEC : // EE 1344 case NF_KEY_G : // G 1345 case NF_KEY_GG : // GG 1346 case NF_KEY_GGG : // GGG 1347 case NF_KEY_R : // R 1348 case NF_KEY_RR : // RR 1349 eNewType = css::util::NumberFormat::DATE; 1350 bIsTimeDetected = false; 1351 break; 1352 case NF_KEY_CCC: // CCC 1353 eNewType = css::util::NumberFormat::CURRENCY; 1354 break; 1355 case NF_KEY_GENERAL: // Standard 1356 eNewType = css::util::NumberFormat::NUMBER; 1357 bHaveGeneral = true; 1358 break; 1359 default: 1360 eNewType = css::util::NumberFormat::UNDEFINED; 1361 break; 1362 } 1363 } 1364 else 1365 { // control character 1366 switch ( sStrArray[i][0] ) 1367 { 1368 case '#': 1369 case '?': 1370 eNewType = css::util::NumberFormat::NUMBER; 1371 break; 1372 case '0': 1373 if ( (eScannedType & css::util::NumberFormat::TIME) == css::util::NumberFormat::TIME ) 1374 { 1375 if ( Is100SecZero( i, bDecSep ) ) 1376 { 1377 bDecSep = true; // subsequent 0's 1378 eNewType = css::util::NumberFormat::TIME; 1379 } 1380 else 1381 { 1382 return nPos; // Error 1383 } 1384 } 1385 else 1386 { 1387 eNewType = css::util::NumberFormat::NUMBER; 1388 } 1389 break; 1390 case '%': 1391 eNewType = css::util::NumberFormat::PERCENT; 1392 break; 1393 case '/': 1394 eNewType = css::util::NumberFormat::FRACTION; 1395 break; 1396 case '[': 1397 if ( i < nStringsCnt-1 && 1398 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && 1399 sStrArray[i+1][0] == '$' ) 1400 { 1401 eNewType = css::util::NumberFormat::CURRENCY; 1402 bMatchBracket = true; 1403 } 1404 else if ( i < nStringsCnt-1 && 1405 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && 1406 sStrArray[i+1][0] == '~' ) 1407 { 1408 eNewType = css::util::NumberFormat::DATE; 1409 bMatchBracket = true; 1410 } 1411 else 1412 { 1413 sal_uInt16 nIndexNex = NextKeyword(i); 1414 if (nIndexNex == NF_KEY_H || // H 1415 nIndexNex == NF_KEY_HH || // HH 1416 nIndexNex == NF_KEY_M || // M 1417 nIndexNex == NF_KEY_MM || // MM 1418 nIndexNex == NF_KEY_S || // S 1419 nIndexNex == NF_KEY_SS ) // SS 1420 eNewType = css::util::NumberFormat::TIME; 1421 else 1422 { 1423 return nPos; // Error 1424 } 1425 } 1426 break; 1427 case '@': 1428 eNewType = css::util::NumberFormat::TEXT; 1429 break; 1430 default: 1431 if (pLoc->getTime100SecSep() == sStrArray[i]) 1432 { 1433 bDecSep = true; // for SS,0 1434 } 1435 eNewType = css::util::NumberFormat::UNDEFINED; 1436 break; 1437 } 1438 } 1439 if (eScannedType == css::util::NumberFormat::UNDEFINED) 1440 { 1441 eScannedType = eNewType; 1442 } 1443 else if (eScannedType == css::util::NumberFormat::TEXT || eNewType == css::util::NumberFormat::TEXT) 1444 { 1445 eScannedType = css::util::NumberFormat::TEXT; // Text always remains text 1446 } 1447 else if (eNewType == css::util::NumberFormat::UNDEFINED) 1448 { // Remains as is 1449 } 1450 else if (eScannedType != eNewType) 1451 { 1452 switch (eScannedType) 1453 { 1454 case css::util::NumberFormat::DATE: 1455 switch (eNewType) 1456 { 1457 case css::util::NumberFormat::TIME: 1458 eScannedType = css::util::NumberFormat::DATETIME; 1459 break; 1460 case css::util::NumberFormat::FRACTION: // DD/MM 1461 break; 1462 default: 1463 if (nCurrPos >= 0) 1464 { 1465 eScannedType = css::util::NumberFormat::UNDEFINED; 1466 } 1467 else if ( sStrArray[i] != pFormatter->GetDateSep() ) 1468 { 1469 return nPos; 1470 } 1471 } 1472 break; 1473 case css::util::NumberFormat::TIME: 1474 switch (eNewType) 1475 { 1476 case css::util::NumberFormat::DATE: 1477 eScannedType = css::util::NumberFormat::DATETIME; 1478 break; 1479 case css::util::NumberFormat::FRACTION: // MM/SS 1480 break; 1481 default: 1482 if (nCurrPos >= 0) 1483 { 1484 eScannedType = css::util::NumberFormat::UNDEFINED; 1485 } 1486 else if (pLoc->getTimeSep() != sStrArray[i]) 1487 { 1488 return nPos; 1489 } 1490 break; 1491 } 1492 break; 1493 case css::util::NumberFormat::DATETIME: 1494 switch (eNewType) 1495 { 1496 case css::util::NumberFormat::TIME: 1497 case css::util::NumberFormat::DATE: 1498 break; 1499 case css::util::NumberFormat::FRACTION: // DD/MM 1500 break; 1501 default: 1502 if (nCurrPos >= 0) 1503 { 1504 eScannedType = css::util::NumberFormat::UNDEFINED; 1505 } 1506 else if ( pFormatter->GetDateSep() != sStrArray[i] && 1507 pLoc->getTimeSep() != sStrArray[i] ) 1508 { 1509 return nPos; 1510 } 1511 } 1512 break; 1513 case css::util::NumberFormat::PERCENT: 1514 switch (eNewType) 1515 { 1516 case css::util::NumberFormat::NUMBER: // Only number to percent 1517 break; 1518 default: 1519 return nPos; 1520 } 1521 break; 1522 case css::util::NumberFormat::SCIENTIFIC: 1523 switch (eNewType) 1524 { 1525 case css::util::NumberFormat::NUMBER: // Only number to E 1526 break; 1527 default: 1528 return nPos; 1529 } 1530 break; 1531 case css::util::NumberFormat::NUMBER: 1532 switch (eNewType) 1533 { 1534 case css::util::NumberFormat::SCIENTIFIC: 1535 case css::util::NumberFormat::PERCENT: 1536 case css::util::NumberFormat::FRACTION: 1537 case css::util::NumberFormat::CURRENCY: 1538 eScannedType = eNewType; 1539 break; 1540 default: 1541 if (nCurrPos >= 0) 1542 { 1543 eScannedType = css::util::NumberFormat::UNDEFINED; 1544 } 1545 else 1546 { 1547 return nPos; 1548 } 1549 } 1550 break; 1551 case css::util::NumberFormat::FRACTION: 1552 switch (eNewType) 1553 { 1554 case css::util::NumberFormat::NUMBER: // Only number to fraction 1555 break; 1556 default: 1557 return nPos; 1558 } 1559 break; 1560 default: 1561 break; 1562 } 1563 } 1564 nPos = nPos + sStrArray[i].getLength(); // Position of correction 1565 i++; 1566 if ( bMatchBracket ) 1567 { // no type detection inside of matching brackets if [$...], [~...] 1568 while ( bMatchBracket && i < nStringsCnt ) 1569 { 1570 if ( nTypeArray[i] == NF_SYMBOLTYPE_DEL 1571 && sStrArray[i][0] == ']' ) 1572 { 1573 bMatchBracket = false; 1574 } 1575 else 1576 { 1577 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 1578 } 1579 nPos = nPos + sStrArray[i].getLength(); 1580 i++; 1581 } 1582 if ( bMatchBracket ) 1583 { 1584 return nPos; // missing closing bracket at end of code 1585 } 1586 } 1587 SkipStrings(i, nPos); 1588 } 1589 1590 if ((eScannedType == css::util::NumberFormat::NUMBER || 1591 eScannedType == css::util::NumberFormat::UNDEFINED) && 1592 nCurrPos >= 0 && !bHaveGeneral) 1593 { 1594 eScannedType = css::util::NumberFormat::CURRENCY; // old "automatic" currency 1595 } 1596 if (eScannedType == css::util::NumberFormat::UNDEFINED) 1597 { 1598 eScannedType = css::util::NumberFormat::DEFINED; 1599 } 1600 return 0; // All is fine 1601 } 1602 1603 bool ImpSvNumberformatScan::InsertSymbol( sal_uInt16 & nPos, svt::NfSymbolType eType, const OUString& rStr ) 1604 { 1605 if (nStringsCnt >= NF_MAX_FORMAT_SYMBOLS || nPos > nStringsCnt) 1606 { 1607 return false; 1608 } 1609 if (nPos > 0 && nTypeArray[nPos-1] == NF_SYMBOLTYPE_EMPTY) 1610 { 1611 --nPos; // reuse position 1612 } 1613 else 1614 { 1615 if ((size_t) (nStringsCnt + 1) >= NF_MAX_FORMAT_SYMBOLS) 1616 { 1617 return false; 1618 } 1619 ++nStringsCnt; 1620 for (size_t i = nStringsCnt; i > nPos; --i) 1621 { 1622 nTypeArray[i] = nTypeArray[i-1]; 1623 sStrArray[i] = sStrArray[i-1]; 1624 } 1625 } 1626 ++nResultStringsCnt; 1627 nTypeArray[nPos] = static_cast<short>(eType); 1628 sStrArray[nPos] = rStr; 1629 return true; 1630 } 1631 1632 int ImpSvNumberformatScan::FinalScanGetCalendar( sal_Int32& nPos, sal_uInt16& i, 1633 sal_uInt16& rResultStringsCnt ) 1634 { 1635 if ( i < nStringsCnt-1 && 1636 sStrArray[i][0] == '[' && 1637 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && 1638 sStrArray[i+1][0] == '~' ) 1639 { 1640 // [~calendarID] 1641 nPos = nPos + sStrArray[i].getLength(); // [ 1642 nTypeArray[i] = NF_SYMBOLTYPE_CALDEL; 1643 nPos = nPos + sStrArray[++i].getLength(); // ~ 1644 sStrArray[i-1] += sStrArray[i]; // [~ 1645 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 1646 rResultStringsCnt--; 1647 if ( ++i >= nStringsCnt ) 1648 { 1649 return -1; // error 1650 } 1651 nPos = nPos + sStrArray[i].getLength(); // calendarID 1652 OUString& rStr = sStrArray[i]; 1653 nTypeArray[i] = NF_SYMBOLTYPE_CALENDAR; // convert 1654 i++; 1655 while ( i < nStringsCnt && sStrArray[i][0] != ']' ) 1656 { 1657 nPos = nPos + sStrArray[i].getLength(); 1658 rStr += sStrArray[i]; 1659 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 1660 rResultStringsCnt--; 1661 i++; 1662 } 1663 if ( rStr.getLength() && i < nStringsCnt && 1664 sStrArray[i][0] == ']' ) 1665 { 1666 nTypeArray[i] = NF_SYMBOLTYPE_CALDEL; 1667 nPos = nPos + sStrArray[i].getLength(); 1668 i++; 1669 } 1670 else 1671 { 1672 return -1; // error 1673 } 1674 return 1; 1675 } 1676 return 0; 1677 } 1678 1679 bool ImpSvNumberformatScan::IsDateFragment( size_t nPos1, size_t nPos2 ) const 1680 { 1681 return nPos2 - nPos1 == 2 && nTypeArray[nPos1+1] == NF_SYMBOLTYPE_DATESEP; 1682 } 1683 1684 void ImpSvNumberformatScan::SwapArrayElements( size_t nPos1, size_t nPos2 ) 1685 { 1686 std::swap( nTypeArray[nPos1], nTypeArray[nPos2]); 1687 std::swap( sStrArray[nPos1], sStrArray[nPos2]); 1688 } 1689 1690 sal_Int32 ImpSvNumberformatScan::FinalScan( OUString& rString ) 1691 { 1692 const LocaleDataWrapper* pLoc = pFormatter->GetLocaleData(); 1693 1694 // save values for convert mode 1695 OUString sOldDecSep = pFormatter->GetNumDecimalSep(); 1696 OUString sOldThousandSep = pFormatter->GetNumThousandSep(); 1697 OUString sOldDateSep = pFormatter->GetDateSep(); 1698 OUString sOldTimeSep = pLoc->getTimeSep(); 1699 OUString sOldTime100SecSep= pLoc->getTime100SecSep(); 1700 OUString sOldCurSymbol = GetCurSymbol(); 1701 OUString sOldCurString = GetCurString(); 1702 sal_Unicode cOldKeyH = sKeyword[NF_KEY_H][0]; 1703 sal_Unicode cOldKeyMI = sKeyword[NF_KEY_MI][0]; 1704 sal_Unicode cOldKeyS = sKeyword[NF_KEY_S][0]; 1705 DateOrder eOldDateOrder = pLoc->getDateOrder(); 1706 sal_uInt16 nDayPos, nMonthPos, nYearPos; 1707 nDayPos = nMonthPos = nYearPos = SAL_MAX_UINT16; 1708 1709 // If the group separator is a No-Break Space (French) continue with a 1710 // normal space instead so queries on space work correctly. 1711 // The same for Narrow No-Break Space just in case some locale uses it. 1712 // The format string is adjusted to allow both. 1713 // For output of the format code string the LocaleData characters are used. 1714 if ( (sOldThousandSep[0] == cNoBreakSpace || sOldThousandSep[0] == cNarrowNoBreakSpace) && 1715 sOldThousandSep.getLength() == 1 ) 1716 { 1717 sOldThousandSep = " "; 1718 } 1719 bool bNewDateOrder = false; 1720 // change locale data et al 1721 if (bConvertMode) 1722 { 1723 pFormatter->ChangeIntl(eNewLnge); 1724 //! pointer may have changed 1725 pLoc = pFormatter->GetLocaleData(); 1726 //! init new keywords 1727 InitKeywords(); 1728 bNewDateOrder = (eOldDateOrder != pLoc->getDateOrder()); 1729 } 1730 const CharClass* pChrCls = pFormatter->GetCharClass(); 1731 1732 sal_Int32 nPos = 0; // error correction position 1733 sal_uInt16 i = 0; // symbol loop counter 1734 sal_uInt16 nCounter = 0; // counts digits 1735 nResultStringsCnt = nStringsCnt; // counts remaining symbols 1736 bDecSep = false; // reset in case already used in TypeCheck 1737 bool bThaiT = false; // Thai T NatNum modifier present 1738 bool bTimePart = false; 1739 bool bDenomin = false; // Set when reading end of denominator 1740 1741 switch (eScannedType) 1742 { 1743 case css::util::NumberFormat::TEXT: 1744 case css::util::NumberFormat::DEFINED: 1745 while (i < nStringsCnt) 1746 { 1747 switch (nTypeArray[i]) 1748 { 1749 case NF_SYMBOLTYPE_BLANK: 1750 case NF_SYMBOLTYPE_STAR: 1751 break; 1752 case NF_KEY_GENERAL : // #77026# "General" is the same as "@" 1753 break; 1754 default: 1755 if ( nTypeArray[i] != NF_SYMBOLTYPE_DEL || 1756 sStrArray[i][0] != '@' ) 1757 { 1758 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 1759 } 1760 break; 1761 } 1762 nPos = nPos + sStrArray[i].getLength(); 1763 i++; 1764 } // of while 1765 break; 1766 1767 case css::util::NumberFormat::NUMBER: 1768 case css::util::NumberFormat::PERCENT: 1769 case css::util::NumberFormat::CURRENCY: 1770 case css::util::NumberFormat::SCIENTIFIC: 1771 case css::util::NumberFormat::FRACTION: 1772 while (i < nStringsCnt) 1773 { 1774 // TODO: rechecking eScannedType is unnecessary. 1775 // This switch-case is for eScannedType == css::util::NumberFormat::FRACTION anyway 1776 if (eScannedType == css::util::NumberFormat::FRACTION && // special case 1777 nTypeArray[i] == NF_SYMBOLTYPE_DEL && // # ### #/# 1778 StringEqualsChar( sOldThousandSep, ' ' ) && // e.g. France or Sweden 1779 StringEqualsChar( sStrArray[i], ' ' ) && 1780 !bFrac && 1781 IsLastBlankBeforeFrac(i) ) 1782 { 1783 nTypeArray[i] = NF_SYMBOLTYPE_STRING; // del->string 1784 } // No thousands marker 1785 1786 if (nTypeArray[i] == NF_SYMBOLTYPE_BLANK || 1787 nTypeArray[i] == NF_SYMBOLTYPE_STAR || 1788 nTypeArray[i] == NF_KEY_CCC || // CCC 1789 nTypeArray[i] == NF_KEY_GENERAL ) // Standard 1790 { 1791 if (nTypeArray[i] == NF_KEY_GENERAL) 1792 { 1793 nThousand = FLAG_STANDARD_IN_FORMAT; 1794 if ( bConvertMode ) 1795 { 1796 sStrArray[i] = sNameStandardFormat; 1797 } 1798 } 1799 nPos = nPos + sStrArray[i].getLength(); 1800 i++; 1801 } 1802 else if (nTypeArray[i] == NF_SYMBOLTYPE_STRING || // No Strings or 1803 nTypeArray[i] > 0) // Keywords 1804 { 1805 if (eScannedType == css::util::NumberFormat::SCIENTIFIC && 1806 nTypeArray[i] == NF_KEY_E) // E+ 1807 { 1808 if (bExp) // Double 1809 { 1810 return nPos; 1811 } 1812 bExp = true; 1813 nExpPos = i; 1814 if (bDecSep) 1815 { 1816 nCntPost = nCounter; 1817 } 1818 else 1819 { 1820 nCntPre = nCounter; 1821 } 1822 nCounter = 0; 1823 nTypeArray[i] = NF_SYMBOLTYPE_EXP; 1824 } 1825 else if (eScannedType == css::util::NumberFormat::FRACTION && 1826 (sStrArray[i][0] == ' ' || ( nTypeArray[i] == NF_SYMBOLTYPE_STRING && (sStrArray[i][0] < '0' || sStrArray[i][0] > '9') ) ) ) 1827 { 1828 if (!bBlank && !bFrac) // Not double or after a / 1829 { 1830 if (bDecSep && nCounter > 0) // Decimal places 1831 { 1832 return nPos; // Error 1833 } 1834 if (sStrArray[i][0] == ' ' || nCounter > 0 ) // treat string as integer/fraction delimiter only if there is integer 1835 { 1836 bBlank = true; 1837 nBlankPos = i; 1838 nCntPre = nCounter; 1839 nCounter = 0; 1840 nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK; 1841 } 1842 } 1843 else if ( sStrArray[i][0] == ' ' ) 1844 nTypeArray[i] = NF_SYMBOLTYPE_FRACBLANK; 1845 else if ( bFrac && ( nCounter > 0 ) ) 1846 bDenomin = true; // following elements are no more part of denominator 1847 } 1848 else if (nTypeArray[i] == NF_KEY_THAI_T) 1849 { 1850 bThaiT = true; 1851 sStrArray[i] = sKeyword[nTypeArray[i]]; 1852 } 1853 else if (sStrArray[i][0] >= '0' && 1854 sStrArray[i][0] <= '9' && !bDenomin) // denominator was not yet found 1855 { 1856 OUString sDiv; 1857 sal_uInt16 j = i; 1858 while(j < nStringsCnt && sStrArray[j][0] >= '0' && sStrArray[j][0] <= '9') 1859 { 1860 sDiv += sStrArray[j++]; 1861 } 1862 assert(j > 0 && "if i is 0, first iteration through loop is guaranteed by surrounding if condition"); 1863 if (OUString::number(sDiv.toInt32()) == sDiv) 1864 { 1865 // Found a Divisor 1866 while (i < j) 1867 { 1868 nTypeArray[i++] = NF_SYMBOLTYPE_FRAC_FDIV; 1869 } 1870 i = j - 1; // Stop the loop 1871 if (nCntPost) 1872 { 1873 nCounter = nCntPost; 1874 } 1875 else if (nCntPre) 1876 { 1877 nCounter = nCntPre; 1878 } 1879 // don't artificially increment nCntPre for forced denominator 1880 if ( ( eScannedType != css::util::NumberFormat::FRACTION ) && (!nCntPre) ) 1881 { 1882 nCntPre++; 1883 } 1884 if ( bFrac ) 1885 bDenomin = true; // next content should be treated as outside denominator 1886 } 1887 } 1888 else 1889 { 1890 if ( bFrac && ( nCounter > 0 ) ) 1891 bDenomin = true; // next content should be treated as outside denominator 1892 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 1893 } 1894 nPos = nPos + sStrArray[i].getLength(); 1895 i++; 1896 } 1897 else if (nTypeArray[i] == NF_SYMBOLTYPE_DEL) 1898 { 1899 sal_Unicode cHere = sStrArray[i][0]; 1900 sal_Unicode cSaved = cHere; 1901 // Handle not pre-known separators in switch. 1902 sal_Unicode cSimplified; 1903 if (StringEqualsChar( pFormatter->GetNumThousandSep(), cHere)) 1904 { 1905 cSimplified = ','; 1906 } 1907 else if (StringEqualsChar( pFormatter->GetNumDecimalSep(), cHere)) 1908 { 1909 cSimplified = '.'; 1910 } 1911 else 1912 { 1913 cSimplified = cHere; 1914 } 1915 1916 OUString& rStr = sStrArray[i]; 1917 1918 switch ( cSimplified ) 1919 { 1920 case '#': 1921 case '0': 1922 case '?': 1923 if (nThousand > 0) // #... # 1924 { 1925 return nPos; // Error 1926 } 1927 if ( !bDenomin ) 1928 { 1929 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; 1930 nPos = nPos + rStr.getLength(); 1931 i++; 1932 nCounter++; 1933 while (i < nStringsCnt && 1934 (sStrArray[i][0] == '#' || 1935 sStrArray[i][0] == '0' || 1936 sStrArray[i][0] == '?')) 1937 { 1938 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; 1939 nPos = nPos + sStrArray[i].getLength(); 1940 nCounter++; 1941 i++; 1942 } 1943 } 1944 else // after denominator, treat any character as text 1945 { 1946 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 1947 nPos = nPos + sStrArray[i].getLength(); 1948 } 1949 break; 1950 case '-': 1951 if ( bDecSep && nDecPos+1 == i && 1952 nTypeArray[nDecPos] == NF_SYMBOLTYPE_DECSEP ) 1953 { 1954 // "0.--" 1955 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; 1956 nPos = nPos + rStr.getLength(); 1957 i++; 1958 nCounter++; 1959 while (i < nStringsCnt && 1960 (sStrArray[i][0] == '-') ) 1961 { 1962 // If more than two dashes are present in 1963 // currency formats the last dash will be 1964 // interpreted literally as a minus sign. 1965 // Has to be this ugly. Period. 1966 if ( eScannedType == css::util::NumberFormat::CURRENCY 1967 && rStr.getLength() >= 2 && 1968 (i == nStringsCnt-1 || 1969 sStrArray[i+1][0] != '-') ) 1970 { 1971 break; 1972 } 1973 rStr += sStrArray[i]; 1974 nPos = nPos + sStrArray[i].getLength(); 1975 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 1976 nResultStringsCnt--; 1977 nCounter++; 1978 i++; 1979 } 1980 } 1981 else 1982 { 1983 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 1984 nPos = nPos + sStrArray[i].getLength(); 1985 i++; 1986 } 1987 break; 1988 case '.': 1989 case ',': 1990 case '\'': 1991 case ' ': 1992 if ( StringEqualsChar( sOldThousandSep, cSaved ) ) 1993 { 1994 // previous char with skip empty 1995 sal_Unicode cPre = PreviousChar(i); 1996 sal_Unicode cNext; 1997 if (bExp || bBlank || bFrac) 1998 { 1999 // after E, / or ' ' 2000 if ( !StringEqualsChar( sOldThousandSep, ' ' ) ) 2001 { 2002 nPos = nPos + sStrArray[i].getLength(); 2003 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2004 nResultStringsCnt--; 2005 i++; // eat it 2006 } 2007 else 2008 { 2009 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2010 if ( bFrac && (nCounter > 0) ) 2011 bDenomin = true; // end of denominator 2012 } 2013 } 2014 else if (i > 0 && i < nStringsCnt-1 && 2015 (cPre == '#' || cPre == '0') && 2016 ((cNext = NextChar(i)) == '#' || cNext == '0')) // #,# 2017 { 2018 nPos = nPos + sStrArray[i].getLength(); 2019 if (!bThousand) // only once 2020 { 2021 bThousand = true; 2022 } 2023 // Eat it, will be reinserted at proper grouping positions further down. 2024 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2025 nResultStringsCnt--; 2026 i++; 2027 } 2028 else if (i > 0 && (cPre == '#' || cPre == '0') 2029 && PreviousType(i) == NF_SYMBOLTYPE_DIGIT 2030 && nThousand < FLAG_STANDARD_IN_FORMAT ) 2031 { // #,,,, 2032 if ( StringEqualsChar( sOldThousandSep, ' ' ) ) 2033 { 2034 // strange, those French.. 2035 bool bFirst = true; 2036 // set a hard No-Break Space or ConvertMode 2037 const OUString& rSepF = pFormatter->GetNumThousandSep(); 2038 while ( i < nStringsCnt && 2039 sStrArray[i] == sOldThousandSep && 2040 StringEqualsChar( sOldThousandSep, NextChar(i) ) ) 2041 { // last was a space or another space 2042 // is following => separator 2043 nPos = nPos + sStrArray[i].getLength(); 2044 if ( bFirst ) 2045 { 2046 bFirst = false; 2047 rStr = rSepF; 2048 nTypeArray[i] = NF_SYMBOLTYPE_THSEP; 2049 } 2050 else 2051 { 2052 rStr += rSepF; 2053 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2054 nResultStringsCnt--; 2055 } 2056 nThousand++; 2057 i++; 2058 } 2059 if ( i < nStringsCnt-1 && 2060 sStrArray[i] == sOldThousandSep ) 2061 { 2062 // something following last space 2063 // => space if currency contained, 2064 // else separator 2065 nPos = nPos + sStrArray[i].getLength(); 2066 if ( (nPos <= nCurrPos && 2067 nCurrPos < nPos + sStrArray[i+1].getLength()) || 2068 nTypeArray[i+1] == NF_KEY_CCC || 2069 (i < nStringsCnt-2 && 2070 sStrArray[i+1][0] == '[' && 2071 sStrArray[i+2][0] == '$') ) 2072 { 2073 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2074 } 2075 else 2076 { 2077 if ( bFirst ) 2078 { 2079 rStr = rSepF; 2080 nTypeArray[i] = NF_SYMBOLTYPE_THSEP; 2081 } 2082 else 2083 { 2084 rStr += rSepF; 2085 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2086 nResultStringsCnt--; 2087 } 2088 nThousand++; 2089 } 2090 i++; 2091 } 2092 } 2093 else 2094 { 2095 do 2096 { 2097 nThousand++; 2098 nTypeArray[i] = NF_SYMBOLTYPE_THSEP; 2099 nPos = nPos + sStrArray[i].getLength(); 2100 sStrArray[i] = pFormatter->GetNumThousandSep(); 2101 i++; 2102 } 2103 while (i < nStringsCnt && sStrArray[i] == sOldThousandSep); 2104 } 2105 } 2106 else // any grsep 2107 { 2108 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2109 nPos = nPos + rStr.getLength(); 2110 i++; 2111 while ( i < nStringsCnt && sStrArray[i] == sOldThousandSep ) 2112 { 2113 rStr += sStrArray[i]; 2114 nPos = nPos + sStrArray[i].getLength(); 2115 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2116 nResultStringsCnt--; 2117 i++; 2118 } 2119 } 2120 } 2121 else if ( StringEqualsChar( sOldDecSep, cSaved ) ) 2122 { 2123 if (bBlank || bFrac) // . behind / or ' ' 2124 { 2125 return nPos; // error 2126 } 2127 else if (bExp) // behind E 2128 { 2129 nPos = nPos + sStrArray[i].getLength(); 2130 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2131 nResultStringsCnt--; 2132 i++; // eat it 2133 } 2134 else if (bDecSep) // any . 2135 { 2136 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2137 nPos = nPos + rStr.getLength(); 2138 i++; 2139 while ( i < nStringsCnt && sStrArray[i] == sOldDecSep ) 2140 { 2141 rStr += sStrArray[i]; 2142 nPos = nPos + sStrArray[i].getLength(); 2143 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2144 nResultStringsCnt--; 2145 i++; 2146 } 2147 } 2148 else 2149 { 2150 nPos = nPos + sStrArray[i].getLength(); 2151 nTypeArray[i] = NF_SYMBOLTYPE_DECSEP; 2152 sStrArray[i] = pFormatter->GetNumDecimalSep(); 2153 bDecSep = true; 2154 nDecPos = i; 2155 nCntPre = nCounter; 2156 nCounter = 0; 2157 2158 i++; 2159 } 2160 } // of else = DecSep 2161 else // . without meaning 2162 { 2163 if (cSaved == ' ' && 2164 eScannedType == css::util::NumberFormat::FRACTION && 2165 StringEqualsChar( sStrArray[i], ' ' ) ) 2166 { 2167 if (!bBlank && !bFrac) // no dups 2168 { // or behind / 2169 if (bDecSep && nCounter > 0) // dec. 2170 { 2171 return nPos; // error 2172 } 2173 bBlank = true; 2174 nBlankPos = i; 2175 nCntPre = nCounter; 2176 nCounter = 0; 2177 } 2178 if ( bFrac && (nCounter > 0) ) 2179 bDenomin = true; // next content is not part of denominator 2180 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2181 nPos = nPos + sStrArray[i].getLength(); 2182 } 2183 else 2184 { 2185 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2186 if ( bFrac && (nCounter > 0) ) 2187 bDenomin = true; // next content is not part of denominator 2188 nPos = nPos + rStr.getLength(); 2189 i++; 2190 while (i < nStringsCnt && StringEqualsChar( sStrArray[i], cSaved ) ) 2191 { 2192 rStr += sStrArray[i]; 2193 nPos = nPos + sStrArray[i].getLength(); 2194 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2195 nResultStringsCnt--; 2196 i++; 2197 } 2198 } 2199 } 2200 break; 2201 case '/': 2202 if (eScannedType == css::util::NumberFormat::FRACTION) 2203 { 2204 if ( i == 0 || 2205 (nTypeArray[i-1] != NF_SYMBOLTYPE_DIGIT && 2206 nTypeArray[i-1] != NF_SYMBOLTYPE_EMPTY) ) 2207 { 2208 return nPos ? nPos : 1; // /? not allowed 2209 } 2210 else if (!bFrac || (bDecSep && nCounter > 0)) 2211 { 2212 bFrac = true; 2213 nCntPost = nCounter; 2214 nCounter = 0; 2215 nTypeArray[i] = NF_SYMBOLTYPE_FRAC; 2216 nPos = nPos + sStrArray[i].getLength(); 2217 i++; 2218 } 2219 else // / double or in , in the denominator 2220 { 2221 return nPos; // Error 2222 } 2223 } 2224 else 2225 { 2226 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2227 nPos = nPos + sStrArray[i].getLength(); 2228 i++; 2229 } 2230 break; 2231 case '[' : 2232 if ( eScannedType == css::util::NumberFormat::CURRENCY && 2233 i < nStringsCnt-1 && 2234 nTypeArray[i+1] == NF_SYMBOLTYPE_STRING && 2235 sStrArray[i+1][0] == '$' ) 2236 { 2237 // [$DM-xxx] 2238 nPos = nPos + sStrArray[i].getLength(); // [ 2239 nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL; 2240 nPos = nPos + sStrArray[++i].getLength(); // $ 2241 sStrArray[i-1] += sStrArray[i]; // [$ 2242 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2243 nResultStringsCnt--; 2244 if ( ++i >= nStringsCnt ) 2245 { 2246 return nPos; // Error 2247 } 2248 nPos = nPos + sStrArray[i].getLength(); // DM 2249 OUString* pStr = &sStrArray[i]; 2250 nTypeArray[i] = NF_SYMBOLTYPE_CURRENCY; // convert 2251 bool bHadDash = false; 2252 i++; 2253 while ( i < nStringsCnt && sStrArray[i][0] != ']' ) 2254 { 2255 nPos = nPos + sStrArray[i].getLength(); 2256 if ( bHadDash ) 2257 { 2258 *pStr += sStrArray[i]; 2259 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2260 nResultStringsCnt--; 2261 } 2262 else 2263 { 2264 if ( sStrArray[i][0] == '-' ) 2265 { 2266 bHadDash = true; 2267 pStr = &sStrArray[i]; 2268 nTypeArray[i] = NF_SYMBOLTYPE_CURREXT; 2269 } 2270 else 2271 { 2272 *pStr += sStrArray[i]; 2273 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2274 nResultStringsCnt--; 2275 } 2276 } 2277 i++; 2278 } 2279 if ( rStr.getLength() && i < nStringsCnt && sStrArray[i][0] == ']' ) 2280 { 2281 nTypeArray[i] = NF_SYMBOLTYPE_CURRDEL; 2282 nPos = nPos + sStrArray[i].getLength(); 2283 i++; 2284 } 2285 else 2286 { 2287 return nPos; // Error 2288 } 2289 } 2290 else 2291 { 2292 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2293 nPos = nPos + sStrArray[i].getLength(); 2294 i++; 2295 } 2296 break; 2297 default: // Other Dels 2298 if (eScannedType == css::util::NumberFormat::PERCENT && cHere == '%') 2299 { 2300 nTypeArray[i] = NF_SYMBOLTYPE_PERCENT; 2301 } 2302 else 2303 { 2304 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2305 } 2306 nPos = nPos + sStrArray[i].getLength(); 2307 i++; 2308 break; 2309 } // of switch (Del) 2310 } // of else Del 2311 else 2312 { 2313 SAL_WARN( "svl.numbers", "unknown NF_SYMBOLTYPE_..." ); 2314 nPos = nPos + sStrArray[i].getLength(); 2315 i++; 2316 } 2317 } // of while 2318 if (eScannedType == css::util::NumberFormat::FRACTION) 2319 { 2320 if (bFrac) 2321 { 2322 nCntExp = nCounter; 2323 } 2324 else if (bBlank) 2325 { 2326 nCntPost = nCounter; 2327 } 2328 else 2329 { 2330 nCntPre = nCounter; 2331 } 2332 } 2333 else 2334 { 2335 if (bExp) 2336 { 2337 nCntExp = nCounter; 2338 } 2339 else if (bDecSep) 2340 { 2341 nCntPost = nCounter; 2342 } 2343 else 2344 { 2345 nCntPre = nCounter; 2346 } 2347 } 2348 if (bThousand) // Expansion of grouping separators 2349 { 2350 sal_uInt16 nMaxPos; 2351 if (bFrac) 2352 { 2353 if (bBlank) 2354 { 2355 nMaxPos = nBlankPos; 2356 } 2357 else 2358 { 2359 nMaxPos = 0; // no grouping 2360 } 2361 } 2362 else if (bDecSep) // decimal separator present 2363 { 2364 nMaxPos = nDecPos; 2365 } 2366 else if (bExp) // 'E' exponent present 2367 { 2368 nMaxPos = nExpPos; 2369 } 2370 else // up to end 2371 { 2372 nMaxPos = i; 2373 } 2374 // Insert separators at proper positions. 2375 sal_Int32 nCount = 0; 2376 utl::DigitGroupingIterator aGrouping( pLoc->getDigitGrouping()); 2377 size_t nFirstDigitSymbol = nMaxPos; 2378 size_t nFirstGroupingSymbol = nMaxPos; 2379 i = nMaxPos; 2380 while (i-- > 0) 2381 { 2382 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT) 2383 { 2384 nFirstDigitSymbol = i; 2385 nCount = nCount + sStrArray[i].getLength(); // MSC converts += to int and then warns, so ... 2386 // Insert separator only if not leftmost symbol. 2387 if (i > 0 && nCount >= aGrouping.getPos()) 2388 { 2389 DBG_ASSERT( sStrArray[i].getLength() == 1, 2390 "ImpSvNumberformatScan::FinalScan: combined digits in group separator insertion"); 2391 if (!InsertSymbol( i, NF_SYMBOLTYPE_THSEP, pFormatter->GetNumThousandSep())) 2392 { 2393 // nPos isn't correct here, but signals error 2394 return nPos; 2395 } 2396 // i may have been decremented by 1 2397 nFirstDigitSymbol = i + 1; 2398 nFirstGroupingSymbol = i; 2399 aGrouping.advance(); 2400 } 2401 } 2402 } 2403 // Generated something like "string",000; remove separator again. 2404 if (nFirstGroupingSymbol < nFirstDigitSymbol) 2405 { 2406 nTypeArray[nFirstGroupingSymbol] = NF_SYMBOLTYPE_EMPTY; 2407 nResultStringsCnt--; 2408 } 2409 } 2410 // Combine digits into groups to save memory (Info will be copied 2411 // later, taking only non-empty symbols). 2412 for (i = 0; i < nStringsCnt; ++i) 2413 { 2414 if (nTypeArray[i] == NF_SYMBOLTYPE_DIGIT) 2415 { 2416 OUString& rStr = sStrArray[i]; 2417 while (++i < nStringsCnt && nTypeArray[i] == NF_SYMBOLTYPE_DIGIT) 2418 { 2419 rStr += sStrArray[i]; 2420 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2421 nResultStringsCnt--; 2422 } 2423 } 2424 } 2425 break; // of css::util::NumberFormat::NUMBER 2426 case css::util::NumberFormat::DATE: 2427 while (i < nStringsCnt) 2428 { 2429 switch (nTypeArray[i]) 2430 { 2431 case NF_SYMBOLTYPE_BLANK: 2432 case NF_SYMBOLTYPE_STAR: 2433 case NF_SYMBOLTYPE_STRING: 2434 nPos = nPos + sStrArray[i].getLength(); 2435 i++; 2436 break; 2437 case NF_SYMBOLTYPE_DEL: 2438 int nCalRet; 2439 if (sStrArray[i] == sOldDateSep) 2440 { 2441 nTypeArray[i] = NF_SYMBOLTYPE_DATESEP; 2442 nPos = nPos + sStrArray[i].getLength(); 2443 if (bConvertMode) 2444 { 2445 sStrArray[i] = pFormatter->GetDateSep(); 2446 } 2447 i++; 2448 } 2449 else if ( (nCalRet = FinalScanGetCalendar( nPos, i, nResultStringsCnt )) != 0 ) 2450 { 2451 if ( nCalRet < 0 ) 2452 { 2453 return nPos; // error 2454 } 2455 } 2456 else 2457 { 2458 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2459 nPos = nPos + sStrArray[i].getLength(); 2460 i++; 2461 } 2462 break; 2463 case NF_KEY_THAI_T : 2464 bThaiT = true; 2465 SAL_FALLTHROUGH; 2466 case NF_KEY_M: // M 2467 case NF_KEY_MM: // MM 2468 case NF_KEY_MMM: // MMM 2469 case NF_KEY_MMMM: // MMMM 2470 case NF_KEY_MMMMM: // MMMMM 2471 case NF_KEY_Q: // Q 2472 case NF_KEY_QQ: // QQ 2473 case NF_KEY_D: // D 2474 case NF_KEY_DD: // DD 2475 case NF_KEY_DDD: // DDD 2476 case NF_KEY_DDDD: // DDDD 2477 case NF_KEY_YY: // YY 2478 case NF_KEY_YYYY: // YYYY 2479 case NF_KEY_NN: // NN 2480 case NF_KEY_NNN: // NNN 2481 case NF_KEY_NNNN: // NNNN 2482 case NF_KEY_WW : // WW 2483 case NF_KEY_AAA : // AAA 2484 case NF_KEY_AAAA : // AAAA 2485 case NF_KEY_EC : // E 2486 case NF_KEY_EEC : // EE 2487 case NF_KEY_G : // G 2488 case NF_KEY_GG : // GG 2489 case NF_KEY_GGG : // GGG 2490 case NF_KEY_R : // R 2491 case NF_KEY_RR : // RR 2492 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT 2493 nPos = nPos + sStrArray[i].getLength(); 2494 if (bNewDateOrder) 2495 { 2496 // For simple numeric date formats record date order and 2497 // later rearrange. 2498 switch (nTypeArray[i]) 2499 { 2500 case NF_KEY_M: 2501 case NF_KEY_MM: 2502 if (nMonthPos == SAL_MAX_UINT16) 2503 nMonthPos = i; 2504 else 2505 bNewDateOrder = false; 2506 break; 2507 case NF_KEY_D: 2508 case NF_KEY_DD: 2509 if (nDayPos == SAL_MAX_UINT16) 2510 nDayPos = i; 2511 else 2512 bNewDateOrder = false; 2513 break; 2514 case NF_KEY_YY: 2515 case NF_KEY_YYYY: 2516 if (nYearPos == SAL_MAX_UINT16) 2517 nYearPos = i; 2518 else 2519 bNewDateOrder = false; 2520 break; 2521 default: 2522 ; // nothing 2523 } 2524 } 2525 i++; 2526 break; 2527 default: // Other keywords 2528 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2529 nPos = nPos + sStrArray[i].getLength(); 2530 i++; 2531 break; 2532 } 2533 } // of while 2534 break; // of css::util::NumberFormat::DATE 2535 case css::util::NumberFormat::TIME: 2536 while (i < nStringsCnt) 2537 { 2538 sal_Unicode cChar; 2539 2540 switch (nTypeArray[i]) 2541 { 2542 case NF_SYMBOLTYPE_BLANK: 2543 case NF_SYMBOLTYPE_STAR: 2544 nPos = nPos + sStrArray[i].getLength(); 2545 i++; 2546 break; 2547 case NF_SYMBOLTYPE_DEL: 2548 switch( sStrArray[i][0] ) 2549 { 2550 case '0': 2551 if ( Is100SecZero( i, bDecSep ) ) 2552 { 2553 bDecSep = true; 2554 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; 2555 OUString& rStr = sStrArray[i]; 2556 nCounter++; 2557 i++; 2558 while (i < nStringsCnt && 2559 sStrArray[i][0] == '0') 2560 { 2561 rStr += sStrArray[i]; 2562 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2563 nResultStringsCnt--; 2564 nCounter++; 2565 i++; 2566 } 2567 nPos += rStr.getLength(); 2568 } 2569 else 2570 { 2571 return nPos; 2572 } 2573 break; 2574 case '#': 2575 case '?': 2576 return nPos; 2577 case '[': 2578 if (bThousand) // Double 2579 { 2580 return nPos; 2581 } 2582 bThousand = true; // Empty for Time 2583 cChar = pChrCls->uppercase(OUString(NextChar(i)))[0]; 2584 if ( cChar == cOldKeyH ) 2585 { 2586 nThousand = 1; // H 2587 } 2588 else if ( cChar == cOldKeyMI ) 2589 { 2590 nThousand = 2; // M 2591 } 2592 else if ( cChar == cOldKeyS ) 2593 { 2594 nThousand = 3; // S 2595 } 2596 else 2597 { 2598 return nPos; 2599 } 2600 nPos = nPos + sStrArray[i].getLength(); 2601 i++; 2602 break; 2603 case ']': 2604 if (!bThousand) // No preceding [ 2605 { 2606 return nPos; 2607 } 2608 nPos = nPos + sStrArray[i].getLength(); 2609 i++; 2610 break; 2611 default: 2612 nPos = nPos + sStrArray[i].getLength(); 2613 if ( sStrArray[i] == sOldTimeSep ) 2614 { 2615 nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP; 2616 if ( bConvertMode ) 2617 { 2618 sStrArray[i] = pLoc->getTimeSep(); 2619 } 2620 } 2621 else if ( sStrArray[i] == sOldTime100SecSep ) 2622 { 2623 bDecSep = true; 2624 nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP; 2625 if ( bConvertMode ) 2626 { 2627 sStrArray[i] = pLoc->getTime100SecSep(); 2628 } 2629 } 2630 else 2631 { 2632 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2633 } 2634 i++; 2635 break; 2636 } 2637 break; 2638 case NF_SYMBOLTYPE_STRING: 2639 nPos = nPos + sStrArray[i].getLength(); 2640 i++; 2641 break; 2642 case NF_KEY_AMPM: // AM/PM 2643 case NF_KEY_AP: // A/P 2644 bExp = true; // Abuse for A/P 2645 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT 2646 nPos = nPos + sStrArray[i].getLength(); 2647 i++; 2648 break; 2649 case NF_KEY_THAI_T : 2650 bThaiT = true; 2651 SAL_FALLTHROUGH; 2652 case NF_KEY_MI: // M 2653 case NF_KEY_MMI: // MM 2654 case NF_KEY_H: // H 2655 case NF_KEY_HH: // HH 2656 case NF_KEY_S: // S 2657 case NF_KEY_SS: // SS 2658 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT 2659 nPos = nPos + sStrArray[i].getLength(); 2660 i++; 2661 break; 2662 default: // Other keywords 2663 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2664 nPos = nPos + sStrArray[i].getLength(); 2665 i++; 2666 break; 2667 } 2668 } // of while 2669 nCntPost = nCounter; // Zero counter 2670 if (bExp) 2671 { 2672 nCntExp = 1; // Remembers AM/PM 2673 } 2674 break; // of css::util::NumberFormat::TIME 2675 case css::util::NumberFormat::DATETIME: 2676 while (i < nStringsCnt) 2677 { 2678 int nCalRet; 2679 switch (nTypeArray[i]) 2680 { 2681 case NF_SYMBOLTYPE_BLANK: 2682 case NF_SYMBOLTYPE_STAR: 2683 case NF_SYMBOLTYPE_STRING: 2684 nPos = nPos + sStrArray[i].getLength(); 2685 i++; 2686 break; 2687 case NF_SYMBOLTYPE_DEL: 2688 if ( (nCalRet = FinalScanGetCalendar( nPos, i, nResultStringsCnt )) != 0 ) 2689 { 2690 if ( nCalRet < 0 ) 2691 { 2692 return nPos; // Error 2693 } 2694 } 2695 else 2696 { 2697 switch( sStrArray[i][0] ) 2698 { 2699 case '0': 2700 if ( bTimePart && Is100SecZero( i, bDecSep ) ) 2701 { 2702 bDecSep = true; 2703 nTypeArray[i] = NF_SYMBOLTYPE_DIGIT; 2704 OUString& rStr = sStrArray[i]; 2705 nCounter++; 2706 i++; 2707 while (i < nStringsCnt && 2708 sStrArray[i][0] == '0') 2709 { 2710 rStr += sStrArray[i]; 2711 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 2712 nResultStringsCnt--; 2713 nCounter++; 2714 i++; 2715 } 2716 nPos += rStr.getLength(); 2717 } 2718 else 2719 { 2720 return nPos; 2721 } 2722 break; 2723 case '#': 2724 case '?': 2725 return nPos; 2726 default: 2727 nPos = nPos + sStrArray[i].getLength(); 2728 if (bTimePart) 2729 { 2730 if ( sStrArray[i] == sOldTimeSep ) 2731 { 2732 nTypeArray[i] = NF_SYMBOLTYPE_TIMESEP; 2733 if ( bConvertMode ) 2734 { 2735 sStrArray[i] = pLoc->getTimeSep(); 2736 } 2737 } 2738 else if ( sStrArray[i] == sOldTime100SecSep ) 2739 { 2740 bDecSep = true; 2741 nTypeArray[i] = NF_SYMBOLTYPE_TIME100SECSEP; 2742 if ( bConvertMode ) 2743 { 2744 sStrArray[i] = pLoc->getTime100SecSep(); 2745 } 2746 } 2747 else 2748 { 2749 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2750 } 2751 } 2752 else 2753 { 2754 if ( sStrArray[i] == sOldDateSep ) 2755 { 2756 nTypeArray[i] = NF_SYMBOLTYPE_DATESEP; 2757 if (bConvertMode) 2758 sStrArray[i] = pFormatter->GetDateSep(); 2759 } 2760 else 2761 { 2762 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2763 } 2764 } 2765 i++; 2766 break; 2767 } 2768 } 2769 break; 2770 case NF_KEY_AMPM: // AM/PM 2771 case NF_KEY_AP: // A/P 2772 bTimePart = true; 2773 bExp = true; // Abuse for A/P 2774 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT 2775 nPos = nPos + sStrArray[i].getLength(); 2776 i++; 2777 break; 2778 case NF_KEY_MI: // M 2779 case NF_KEY_MMI: // MM 2780 case NF_KEY_H: // H 2781 case NF_KEY_HH: // HH 2782 case NF_KEY_S: // S 2783 case NF_KEY_SS: // SS 2784 bTimePart = true; 2785 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT 2786 nPos = nPos + sStrArray[i].getLength(); 2787 i++; 2788 break; 2789 case NF_KEY_M: // M 2790 case NF_KEY_MM: // MM 2791 case NF_KEY_MMM: // MMM 2792 case NF_KEY_MMMM: // MMMM 2793 case NF_KEY_MMMMM: // MMMMM 2794 case NF_KEY_Q: // Q 2795 case NF_KEY_QQ: // QQ 2796 case NF_KEY_D: // D 2797 case NF_KEY_DD: // DD 2798 case NF_KEY_DDD: // DDD 2799 case NF_KEY_DDDD: // DDDD 2800 case NF_KEY_YY: // YY 2801 case NF_KEY_YYYY: // YYYY 2802 case NF_KEY_NN: // NN 2803 case NF_KEY_NNN: // NNN 2804 case NF_KEY_NNNN: // NNNN 2805 case NF_KEY_WW : // WW 2806 case NF_KEY_AAA : // AAA 2807 case NF_KEY_AAAA : // AAAA 2808 case NF_KEY_EC : // E 2809 case NF_KEY_EEC : // EE 2810 case NF_KEY_G : // G 2811 case NF_KEY_GG : // GG 2812 case NF_KEY_GGG : // GGG 2813 case NF_KEY_R : // R 2814 case NF_KEY_RR : // RR 2815 bTimePart = false; 2816 sStrArray[i] = sKeyword[nTypeArray[i]]; // tTtT -> TTTT 2817 nPos = nPos + sStrArray[i].getLength(); 2818 if (bNewDateOrder) 2819 { 2820 // For simple numeric date formats record date order and 2821 // later rearrange. 2822 switch (nTypeArray[i]) 2823 { 2824 case NF_KEY_M: 2825 case NF_KEY_MM: 2826 if (nMonthPos == SAL_MAX_UINT16) 2827 nMonthPos = i; 2828 else 2829 bNewDateOrder = false; 2830 break; 2831 case NF_KEY_D: 2832 case NF_KEY_DD: 2833 if (nDayPos == SAL_MAX_UINT16) 2834 nDayPos = i; 2835 else 2836 bNewDateOrder = false; 2837 break; 2838 case NF_KEY_YY: 2839 case NF_KEY_YYYY: 2840 if (nYearPos == SAL_MAX_UINT16) 2841 nYearPos = i; 2842 else 2843 bNewDateOrder = false; 2844 break; 2845 default: 2846 ; // nothing 2847 } 2848 } 2849 i++; 2850 break; 2851 case NF_KEY_THAI_T : 2852 bThaiT = true; 2853 sStrArray[i] = sKeyword[nTypeArray[i]]; 2854 nPos = nPos + sStrArray[i].getLength(); 2855 i++; 2856 break; 2857 default: // Other keywords 2858 nTypeArray[i] = NF_SYMBOLTYPE_STRING; 2859 nPos = nPos + sStrArray[i].getLength(); 2860 i++; 2861 break; 2862 } 2863 } // of while 2864 nCntPost = nCounter; // decimals (100th seconds) 2865 if (bExp) 2866 { 2867 nCntExp = 1; // Remembers AM/PM 2868 } 2869 break; // of css::util::NumberFormat::DATETIME 2870 default: 2871 break; 2872 } 2873 if (eScannedType == css::util::NumberFormat::SCIENTIFIC && 2874 (nCntPre + nCntPost == 0 || nCntExp == 0)) 2875 { 2876 return nPos; 2877 } 2878 else if (eScannedType == css::util::NumberFormat::FRACTION && (nCntExp > 8 || nCntExp == 0)) 2879 { 2880 return nPos; 2881 } 2882 if (bThaiT && !GetNatNumModifier()) 2883 { 2884 SetNatNumModifier(1); 2885 } 2886 if ( bConvertMode ) 2887 { 2888 if (bNewDateOrder && sOldDateSep == "-") 2889 { 2890 // Keep ISO formats Y-M-D, Y-M and M-D 2891 if (IsDateFragment( nYearPos, nMonthPos)) 2892 { 2893 nTypeArray[nYearPos+1] = NF_SYMBOLTYPE_STRING; 2894 sStrArray[nYearPos+1] = sOldDateSep; 2895 bNewDateOrder = false; 2896 } 2897 if (IsDateFragment( nMonthPos, nDayPos)) 2898 { 2899 nTypeArray[nMonthPos+1] = NF_SYMBOLTYPE_STRING; 2900 sStrArray[nMonthPos+1] = sOldDateSep; 2901 bNewDateOrder = false; 2902 } 2903 } 2904 if (bNewDateOrder) 2905 { 2906 // Rearrange date order to the target locale if the original order 2907 // includes date separators and is adjacent. 2908 /* TODO: for incomplete dates trailing separators need to be 2909 * handled according to the locale's usage, e.g. en-US M/D should 2910 * be converted to de-DE D.M. and vice versa. As is, it's 2911 * M/D -> D.M and D.M. -> M/D/ where specifically the latter looks 2912 * odd. Check accepted date patterns and append/remove? */ 2913 switch (eOldDateOrder) 2914 { 2915 case DateOrder::DMY: 2916 switch (pLoc->getDateOrder()) 2917 { 2918 case DateOrder::MDY: 2919 if (IsDateFragment( nDayPos, nMonthPos)) 2920 SwapArrayElements( nDayPos, nMonthPos); 2921 break; 2922 case DateOrder::YMD: 2923 if (nYearPos != SAL_MAX_UINT16) 2924 { 2925 if (IsDateFragment( nDayPos, nMonthPos) && IsDateFragment( nMonthPos, nYearPos)) 2926 SwapArrayElements( nDayPos, nYearPos); 2927 } 2928 else 2929 { 2930 if (IsDateFragment( nDayPos, nMonthPos)) 2931 SwapArrayElements( nDayPos, nMonthPos); 2932 } 2933 break; 2934 default: 2935 ; // nothing 2936 } 2937 break; 2938 case DateOrder::MDY: 2939 switch (pLoc->getDateOrder()) 2940 { 2941 case DateOrder::DMY: 2942 if (IsDateFragment( nMonthPos, nDayPos)) 2943 SwapArrayElements( nMonthPos, nDayPos); 2944 break; 2945 case DateOrder::YMD: 2946 if (nYearPos != SAL_MAX_UINT16) 2947 { 2948 if (IsDateFragment( nMonthPos, nDayPos) && IsDateFragment( nDayPos, nYearPos)) 2949 { 2950 SwapArrayElements( nYearPos, nMonthPos); // YDM 2951 SwapArrayElements( nYearPos, nDayPos); // YMD 2952 } 2953 } 2954 break; 2955 default: 2956 ; // nothing 2957 } 2958 break; 2959 case DateOrder::YMD: 2960 switch (pLoc->getDateOrder()) 2961 { 2962 case DateOrder::DMY: 2963 if (nYearPos != SAL_MAX_UINT16) 2964 { 2965 if (IsDateFragment( nYearPos, nMonthPos) && IsDateFragment( nMonthPos, nDayPos)) 2966 SwapArrayElements( nYearPos, nDayPos); 2967 } 2968 else 2969 { 2970 if (IsDateFragment( nMonthPos, nDayPos)) 2971 SwapArrayElements( nMonthPos, nDayPos); 2972 } 2973 break; 2974 case DateOrder::MDY: 2975 if (nYearPos != SAL_MAX_UINT16) 2976 { 2977 if (IsDateFragment( nYearPos, nMonthPos) && IsDateFragment( nMonthPos, nDayPos)) 2978 { 2979 SwapArrayElements( nYearPos, nDayPos); // DMY 2980 SwapArrayElements( nYearPos, nMonthPos); // MDY 2981 } 2982 } 2983 break; 2984 default: 2985 ; // nothing 2986 } 2987 break; 2988 default: 2989 ; // nothing 2990 } 2991 } 2992 // strings containing keywords of the target locale must be quoted, so 2993 // the user sees the difference and is able to edit the format string 2994 for ( i=0; i < nStringsCnt; i++ ) 2995 { 2996 if ( nTypeArray[i] == NF_SYMBOLTYPE_STRING && 2997 sStrArray[i][0] != '\"' ) 2998 { 2999 if ( bConvertSystemToSystem && eScannedType == css::util::NumberFormat::CURRENCY ) 3000 { 3001 // don't stringize automatic currency, will be converted 3002 if ( sStrArray[i] == sOldCurSymbol ) 3003 { 3004 continue; // for 3005 } 3006 // DM might be splitted into D and M 3007 if ( sStrArray[i].getLength() < sOldCurSymbol.getLength() && 3008 pChrCls->uppercase( sStrArray[i], 0, 1 )[0] == 3009 sOldCurString[0] ) 3010 { 3011 OUString aTmp( sStrArray[i] ); 3012 sal_uInt16 j = i + 1; 3013 while ( aTmp.getLength() < sOldCurSymbol.getLength() && 3014 j < nStringsCnt && 3015 nTypeArray[j] == NF_SYMBOLTYPE_STRING ) 3016 { 3017 aTmp += sStrArray[j++]; 3018 } 3019 if ( pChrCls->uppercase( aTmp ) == sOldCurString ) 3020 { 3021 sStrArray[i++] = aTmp; 3022 for ( ; i<j; i++ ) 3023 { 3024 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 3025 nResultStringsCnt--; 3026 } 3027 i = j - 1; 3028 continue; // for 3029 } 3030 } 3031 } 3032 OUString& rStr = sStrArray[i]; 3033 sal_Int32 nLen = rStr.getLength(); 3034 for ( sal_Int32 j = 0; j < nLen; j++ ) 3035 { 3036 if ( (j == 0 || rStr[j - 1] != '\\') && GetKeyWord( rStr, j ) ) 3037 { 3038 rStr = "\"" + rStr + "\""; 3039 break; // for 3040 } 3041 } 3042 } 3043 } 3044 } 3045 // Concatenate strings, remove quotes for output, and rebuild the format string 3046 rString.clear(); 3047 i = 0; 3048 while (i < nStringsCnt) 3049 { 3050 sal_Int32 nStringPos; 3051 sal_Int32 nArrPos = 0; 3052 sal_uInt16 iPos = i; 3053 switch ( nTypeArray[i] ) 3054 { 3055 case NF_SYMBOLTYPE_STRING : 3056 case NF_SYMBOLTYPE_FRACBLANK : 3057 nStringPos = rString.getLength(); 3058 do 3059 { 3060 if (sStrArray[i].getLength() == 2 && 3061 sStrArray[i][0] == '\\') 3062 { 3063 // Unescape some simple forms of symbols even in the UI 3064 // visible string to prevent duplicates that differ 3065 // only in notation, originating from import. 3066 // e.g. YYYY-MM-DD and YYYY\-MM\-DD are identical, 3067 // but 0\ 000 0 and 0 000 0 in a French locale are not. 3068 3069 sal_Unicode c = sStrArray[i][1]; 3070 3071 switch (c) 3072 { 3073 case '+': 3074 case '-': 3075 rString += OUStringLiteral1(c); 3076 break; 3077 case ' ': 3078 case '.': 3079 case '/': 3080 if (((eScannedType & css::util::NumberFormat::DATE) == 0) && 3081 (StringEqualsChar( pFormatter->GetNumThousandSep(), c) || 3082 StringEqualsChar( pFormatter->GetNumDecimalSep(), c) || 3083 (c == ' ' && 3084 (StringEqualsChar( pFormatter->GetNumThousandSep(), cNoBreakSpace) || 3085 StringEqualsChar( pFormatter->GetNumThousandSep(), cNarrowNoBreakSpace))))) 3086 { 3087 rString += sStrArray[i]; 3088 } 3089 else if ((eScannedType & css::util::NumberFormat::DATE) && 3090 StringEqualsChar( pFormatter->GetDateSep(), c)) 3091 { 3092 rString += sStrArray[i]; 3093 } 3094 else if ((eScannedType & css::util::NumberFormat::TIME) && 3095 (StringEqualsChar( pLoc->getTimeSep(), c) || 3096 StringEqualsChar( pLoc->getTime100SecSep(), c))) 3097 { 3098 rString += sStrArray[i]; 3099 } 3100 else if (eScannedType & css::util::NumberFormat::FRACTION) 3101 { 3102 rString += sStrArray[i]; 3103 } 3104 else 3105 { 3106 rString += OUStringLiteral1(c); 3107 } 3108 break; 3109 default: 3110 rString += sStrArray[i]; 3111 } 3112 } 3113 else 3114 { 3115 rString += sStrArray[i]; 3116 } 3117 if ( RemoveQuotes( sStrArray[i] ) > 0 ) 3118 { 3119 // update currency up to quoted string 3120 if ( eScannedType == css::util::NumberFormat::CURRENCY ) 3121 { 3122 // dM -> DM or DM -> $ in old automatic 3123 // currency formats, oh my ..., why did we ever introduce them? 3124 OUString aTmp( pChrCls->uppercase( sStrArray[iPos], nArrPos, 3125 sStrArray[iPos].getLength()-nArrPos ) ); 3126 sal_Int32 nCPos = aTmp.indexOf( sOldCurString ); 3127 if ( nCPos >= 0 ) 3128 { 3129 const OUString& rCur = bConvertMode && bConvertSystemToSystem ? 3130 GetCurSymbol() : sOldCurSymbol; 3131 sStrArray[iPos] = sStrArray[iPos].replaceAt( nArrPos + nCPos, 3132 sOldCurString.getLength(), 3133 rCur ); 3134 rString = rString.replaceAt( nStringPos + nCPos, 3135 sOldCurString.getLength(), 3136 rCur ); 3137 } 3138 nStringPos = rString.getLength(); 3139 if ( iPos == i ) 3140 { 3141 nArrPos = sStrArray[iPos].getLength(); 3142 } 3143 else 3144 { 3145 nArrPos = sStrArray[iPos].getLength() + sStrArray[i].getLength(); 3146 } 3147 } 3148 } 3149 if ( iPos != i ) 3150 { 3151 sStrArray[iPos] += sStrArray[i]; 3152 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 3153 nResultStringsCnt--; 3154 } 3155 i++; 3156 } 3157 while ( i < nStringsCnt && nTypeArray[i] == NF_SYMBOLTYPE_STRING ); 3158 3159 if ( i < nStringsCnt ) 3160 { 3161 i--; // enter switch on next symbol again 3162 } 3163 if ( eScannedType == css::util::NumberFormat::CURRENCY && nStringPos < rString.getLength() ) 3164 { 3165 // same as above, since last RemoveQuotes 3166 OUString aTmp( pChrCls->uppercase( sStrArray[iPos], nArrPos, 3167 sStrArray[iPos].getLength()-nArrPos ) ); 3168 sal_Int32 nCPos = aTmp.indexOf( sOldCurString ); 3169 if ( nCPos >= 0 ) 3170 { 3171 const OUString& rCur = bConvertMode && bConvertSystemToSystem ? 3172 GetCurSymbol() : sOldCurSymbol; 3173 sStrArray[iPos] = sStrArray[iPos].replaceAt( nArrPos + nCPos, 3174 sOldCurString.getLength(), 3175 rCur ); 3176 rString = rString.replaceAt( nStringPos + nCPos, 3177 sOldCurString.getLength(), rCur ); 3178 } 3179 } 3180 break; 3181 case NF_SYMBOLTYPE_CURRENCY : 3182 rString += sStrArray[i]; 3183 RemoveQuotes( sStrArray[i] ); 3184 break; 3185 case NF_KEY_THAI_T: 3186 if (bThaiT && GetNatNumModifier() == 1) 3187 { 3188 // Remove T from format code, will be replaced with a [NatNum1] prefix. 3189 nTypeArray[i] = NF_SYMBOLTYPE_EMPTY; 3190 nResultStringsCnt--; 3191 } 3192 else 3193 { 3194 rString += sStrArray[i]; 3195 } 3196 break; 3197 case NF_SYMBOLTYPE_EMPTY : 3198 // nothing 3199 break; 3200 default: 3201 rString += sStrArray[i]; 3202 } 3203 i++; 3204 } 3205 return 0; 3206 } 3207 3208 sal_Int32 ImpSvNumberformatScan::RemoveQuotes( OUString& rStr ) 3209 { 3210 if ( rStr.getLength() > 1 ) 3211 { 3212 sal_Unicode c = rStr[0]; 3213 sal_Int32 n = rStr.getLength() - 1; 3214 if ( c == '"' && rStr[n] == '"' ) 3215 { 3216 rStr = rStr.copy( 1, n-1); 3217 return 2; 3218 } 3219 else if ( c == '\\' ) 3220 { 3221 rStr = rStr.copy(1); 3222 return 1; 3223 } 3224 } 3225 return 0; 3226 } 3227 3228 sal_Int32 ImpSvNumberformatScan::ScanFormat( OUString& rString ) 3229 { 3230 sal_Int32 res = Symbol_Division(rString); // Lexical analysis 3231 if (!res) 3232 { 3233 res = ScanType(); // Recognizing the Format type 3234 } 3235 if (!res) 3236 { 3237 res = FinalScan( rString ); // Type dependent final analysis 3238 } 3239 return res; // res = control position; res = 0 => Format ok 3240 } 3241 3242 void ImpSvNumberformatScan::CopyInfo(ImpSvNumberformatInfo* pInfo, sal_uInt16 nCnt) 3243 { 3244 size_t i,j; 3245 j = 0; 3246 i = 0; 3247 while (i < nCnt && j < NF_MAX_FORMAT_SYMBOLS) 3248 { 3249 if (nTypeArray[j] != NF_SYMBOLTYPE_EMPTY) 3250 { 3251 pInfo->sStrArray[i] = sStrArray[j]; 3252 pInfo->nTypeArray[i] = nTypeArray[j]; 3253 i++; 3254 } 3255 j++; 3256 } 3257 pInfo->eScannedType = eScannedType; 3258 pInfo->bThousand = bThousand; 3259 pInfo->nThousand = nThousand; 3260 pInfo->nCntPre = nCntPre; 3261 pInfo->nCntPost = nCntPost; 3262 pInfo->nCntExp = nCntExp; 3263 } 3264 3265 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 3266
