1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_i18npool.hxx" 30 31 #include <rtl/ustrbuf.hxx> 32 #include <nativenumbersupplier.hxx> 33 #include <localedata.hxx> 34 #include <data/numberchar.h> 35 #include <i18nutil/x_rtl_ustring.h> 36 37 using namespace ::com::sun::star::uno; 38 using namespace ::com::sun::star::lang; 39 using namespace ::com::sun::star::lang; 40 using namespace ::rtl; 41 42 43 typedef struct { 44 sal_Int16 number; 45 sal_Unicode *multiplierChar; 46 sal_Int16 numberFlag; 47 sal_Int16 exponentCount; 48 sal_Int16 *multiplierExponent; 49 } Number; 50 51 52 #define NUMBER_OMIT_ZERO (1 << 0) 53 #define NUMBER_OMIT_ONLY_ZERO (1 << 1) 54 #define NUMBER_OMIT_ONE_1 (1 << 2) 55 #define NUMBER_OMIT_ONE_2 (1 << 3) 56 #define NUMBER_OMIT_ONE_3 (1 << 4) 57 #define NUMBER_OMIT_ONE_4 (1 << 5) 58 #define NUMBER_OMIT_ONE_5 (1 << 6) 59 #define NUMBER_OMIT_ONE_6 (1 << 7) 60 #define NUMBER_OMIT_ONE_7 (1 << 8) 61 #define NUMBER_OMIT_ONE (NUMBER_OMIT_ONE_1|NUMBER_OMIT_ONE_2|NUMBER_OMIT_ONE_3|NUMBER_OMIT_ONE_4|NUMBER_OMIT_ONE_5|NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7) 62 #define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit)) 63 #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO ) 64 #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE ) 65 #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7) 66 #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 ) 67 68 69 #define MAX_SAL_UINT32 0xFFFFFFFF 70 #define MAX_VALUE (MAX_SAL_UINT32 - 9) / 10 71 72 namespace com { namespace sun { namespace star { namespace i18n { 73 74 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh); 75 76 OUString SAL_CALL AsciiToNativeChar( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount, 77 Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int16 number ) throw(RuntimeException) 78 { 79 const sal_Unicode *src = inStr.getStr() + startPos; 80 rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount); 81 if (useOffset) 82 offset.realloc(nCount); 83 84 for (sal_Int32 i = 0; i < nCount; i++) { 85 sal_Unicode ch = src[i]; 86 if (isNumber(ch)) 87 newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ]; 88 else if (i+1 < nCount && isNumber(src[i+1])) { 89 if (i > 0 && isNumber(src[i-1]) && isSeparator(ch)) 90 newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch; 91 else 92 newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) : 93 isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch; 94 } 95 else 96 newStr->buffer[i] = ch; 97 if (useOffset) 98 offset[i] = startPos + i; 99 } 100 return OUString(newStr->buffer, nCount); 101 } 102 103 sal_Bool SAL_CALL AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len, 104 sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int32 startPos, 105 Number *number, sal_Unicode* numberChar) 106 { 107 sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]); 108 if ( len <= number->multiplierExponent[number->exponentCount-1] ) { 109 if (number->multiplierExponent[number->exponentCount-1] > 1) { 110 sal_Int16 i; 111 sal_Bool notZero = false; 112 for (i = 0; i < len; i++, begin++) { 113 if (notZero || str[begin] != NUMBER_ZERO) { 114 dst[count] = numberChar[str[begin] - NUMBER_ZERO]; 115 if (useOffset) 116 offset[count] = begin + startPos; 117 count++; 118 notZero = sal_True; 119 } 120 } 121 if (notZero && multiChar > 0) { 122 dst[count] = multiChar; 123 if (useOffset) 124 offset[count] = begin + startPos; 125 count++; 126 } 127 return notZero; 128 } else if (str[begin] != NUMBER_ZERO) { 129 if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) { 130 dst[count] = numberChar[str[begin] - NUMBER_ZERO]; 131 if (useOffset) 132 offset[count] = begin + startPos; 133 count++; 134 } 135 if (multiChar > 0) { 136 dst[count] = multiChar; 137 if (useOffset) 138 offset[count] = begin + startPos; 139 count++; 140 } 141 } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) { 142 dst[count] = numberChar[0]; 143 if (useOffset) 144 offset[count] = begin + startPos; 145 count++; 146 } 147 return str[begin] != NUMBER_ZERO; 148 } else { 149 sal_Bool printPower = sal_False; 150 // sal_Int16 last = 0; 151 for (sal_Int16 i = 1; i <= number->exponentCount; i++) { 152 sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]); 153 if (tmp > 0) { 154 printPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count, 155 (i == number->exponentCount ? -1 : i), offset, useOffset, startPos, number, numberChar); 156 begin += tmp; 157 len -= tmp; 158 } 159 } 160 if (printPower) { 161 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 && 162 dst[count-1] == numberChar[0]) 163 count--; 164 if (multiChar > 0) { 165 dst[count] = multiChar; 166 if (useOffset) 167 offset[count] = begin + startPos; 168 count++; 169 } 170 } 171 return printPower; 172 } 173 } 174 175 OUString SAL_CALL AsciiToNative( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount, 176 Sequence< sal_Int32 >& offset, sal_Bool useOffset, Number* number ) throw(RuntimeException) 177 { 178 sal_Int32 strLen = inStr.getLength() - startPos; 179 sal_Unicode *numberChar = NumberChar[number->number]; 180 181 if (nCount > strLen) 182 nCount = strLen; 183 184 if (nCount > 0) { 185 const sal_Unicode *str = inStr.getStr() + startPos; 186 rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount * 2); 187 rtl_uString *srcStr = x_rtl_uString_new_WithLength(nCount); // for keeping number without comma 188 sal_Int32 i, len = 0, count = 0; 189 190 if (useOffset) 191 offset.realloc( nCount * 2 ); 192 sal_Bool doDecimal = sal_False; 193 194 for (i = 0; i <= nCount; i++) { 195 if (i < nCount && isNumber(str[i])) { 196 if (doDecimal) { 197 newStr->buffer[count] = numberChar[str[i] - NUMBER_ZERO]; 198 if (useOffset) 199 offset[count] = i + startPos; 200 count++; 201 } 202 else 203 srcStr->buffer[len++] = str[i]; 204 } else { 205 if (len > 0) { 206 if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1])) 207 continue; // skip comma inside number string 208 sal_Bool notZero = sal_False; 209 for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0]; 210 end <= len; begin = end, end += number->multiplierExponent[0]) { 211 if (end == 0) continue; 212 sal_Int32 _count = count; 213 notZero |= AsciiToNative_numberMaker(srcStr->buffer, begin, end - begin, newStr->buffer, count, 214 end == len ? -1 : 0, offset, useOffset, i - len + startPos, number, numberChar); 215 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 && 216 newStr->buffer[count-1] == numberChar[0]) 217 count--; 218 if (notZero && _count == count) { 219 if (end != len) { 220 newStr->buffer[count] = number->multiplierChar[0]; 221 if (useOffset) 222 offset[count] = i - len + startPos; 223 count++; 224 } 225 } 226 } 227 if (! notZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) { 228 newStr->buffer[count] = numberChar[0]; 229 if (useOffset) 230 offset[count] = i - len + startPos; 231 count++; 232 } 233 len = 0; 234 } 235 if (i < nCount) { 236 if ((doDecimal = (!doDecimal && isDecimal(str[i]) && i < nCount-1 && isNumber(str[i+1]))) != sal_False) 237 newStr->buffer[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]); 238 else if (isMinus(str[i]) && i < nCount-1 && isNumber(str[i+1])) 239 newStr->buffer[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]); 240 else if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1])) 241 newStr->buffer[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]); 242 else 243 newStr->buffer[count] = str[i]; 244 if (useOffset) 245 offset[count] = i + startPos; 246 count++; 247 } 248 } 249 } 250 251 if (useOffset) 252 offset.realloc(count); 253 return OUString(newStr->buffer, count); 254 } 255 return OUString(); 256 } 257 static void SAL_CALL NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str, 258 sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, sal_Bool useOffset, 259 OUString& numberChar, OUString& multiplierChar) 260 { 261 sal_Int16 curr = 0, num = 0, end = 0, shift = 0; 262 while (++i < nCount) { 263 if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) { 264 if (num > 0) 265 break; 266 num = curr % 10; 267 } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) { 268 curr = MultiplierExponent_7_CJK[curr % ExponentCount_7_CJK]; 269 if (prev > curr && num == 0) num = 1; // One may be omitted in informal format 270 shift = end = 0; 271 if (curr >= max) 272 max = curr; 273 else if (curr > prev) 274 shift = max - curr; 275 else 276 end = curr; 277 while (end++ < prev) { 278 dst[count] = NUMBER_ZERO + (end == prev ? num : 0); 279 if (useOffset) 280 offset[count] = i; 281 count++; 282 } 283 if (shift) { 284 count -= max; 285 for (sal_Int16 j = 0; j < shift; j++, count++) { 286 dst[count] = dst[count + curr]; 287 if (useOffset) 288 offset[count] = offset[count + curr]; 289 } 290 max = curr; 291 } 292 NativeToAscii_numberMaker(max, curr, str, i, nCount, dst, 293 count, offset, useOffset, numberChar, multiplierChar); 294 return; 295 } else 296 break; 297 } 298 while (end++ < prev) { 299 dst[count] = NUMBER_ZERO + (end == prev ? num : 0); 300 if (useOffset) 301 offset[count] = i - 1; 302 count++; 303 } 304 } 305 306 static OUString SAL_CALL NativeToAscii(const OUString& inStr, 307 sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset, sal_Bool useOffset ) throw(RuntimeException) 308 { 309 sal_Int32 strLen = inStr.getLength() - startPos; 310 311 if (nCount > strLen) 312 nCount = strLen; 313 314 if (nCount > 0) { 315 const sal_Unicode *str = inStr.getStr() + startPos; 316 rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount * MultiplierExponent_7_CJK[0] + 1); 317 if (useOffset) 318 offset.realloc( nCount * MultiplierExponent_7_CJK[0] + 1 ); 319 sal_Int32 count = 0, index; 320 sal_Int32 i; 321 322 OUString numberChar, multiplierChar, decimalChar, minusChar, separatorChar; 323 numberChar = OUString((sal_Unicode*)NumberChar, 10*NumberChar_Count); 324 multiplierChar = OUString((sal_Unicode*) MultiplierChar_7_CJK, ExponentCount_7_CJK*Multiplier_Count); 325 decimalChar = OUString(DecimalChar, NumberChar_Count); 326 minusChar = OUString(MinusChar, NumberChar_Count); 327 separatorChar = OUString(SeparatorChar, NumberChar_Count); 328 329 for ( i = 0; i < nCount; i++) { 330 if ((index = multiplierChar.indexOf(str[i])) >= 0) { 331 if (count == 0 || !isNumber(newStr->buffer[count-1])) { // add 1 in front of multiplier 332 newStr->buffer[count] = NUMBER_ONE; 333 if (useOffset) 334 offset[count] = i; 335 count++; 336 } 337 index = MultiplierExponent_7_CJK[index % ExponentCount_7_CJK]; 338 NativeToAscii_numberMaker( 339 sal::static_int_cast<sal_Int16>( index ), sal::static_int_cast<sal_Int16>( index ), 340 str, i, nCount, newStr->buffer, count, offset, useOffset, 341 numberChar, multiplierChar); 342 } else { 343 if ((index = numberChar.indexOf(str[i])) >= 0) 344 newStr->buffer[count] = sal::static_int_cast<sal_Unicode>( (index % 10) + NUMBER_ZERO ); 345 else if ((index = separatorChar.indexOf(str[i])) >= 0 && 346 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || 347 multiplierChar.indexOf(str[i+1]) >= 0))) 348 newStr->buffer[count] = SeparatorChar[NumberChar_HalfWidth]; 349 else if ((index = decimalChar.indexOf(str[i])) >= 0 && 350 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || 351 multiplierChar.indexOf(str[i+1]) >= 0))) 352 // Only when decimal point is followed by numbers, 353 // it will be convert to ASCII decimal point 354 newStr->buffer[count] = DecimalChar[NumberChar_HalfWidth]; 355 else if ((index = minusChar.indexOf(str[i])) >= 0 && 356 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || 357 multiplierChar.indexOf(str[i+1]) >= 0))) 358 // Only when minus is followed by numbers, 359 // it will be convert to ASCII minus sign 360 newStr->buffer[count] = MinusChar[NumberChar_HalfWidth]; 361 else 362 newStr->buffer[count] = str[i]; 363 if (useOffset) 364 offset[count] = i; 365 count++; 366 } 367 } 368 369 if (useOffset) { 370 offset.realloc(count); 371 for (i = 0; i < count; i++) 372 offset[i] += startPos; 373 } 374 return OUString(newStr->buffer, count); 375 } 376 return OUString(); 377 } 378 379 static Number natnum4[4] = { 380 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, 381 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 382 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, 383 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 384 { NumberChar_Modern_ja, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67, 385 ExponentCount_7_CJK, MultiplierExponent_7_CJK }, 386 { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ZERO, 387 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 388 }; 389 390 static Number natnum5[4] = { 391 { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], 0, 392 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 393 { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], 0, 394 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 395 { NumberChar_Traditional_ja, MultiplierChar_7_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE_67, 396 ExponentCount_7_CJK, MultiplierExponent_7_CJK }, 397 { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ZERO, 398 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 399 }; 400 401 static Number natnum6[4] = { 402 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, 403 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 404 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, 405 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 406 { NumberChar_FullWidth, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67, 407 ExponentCount_7_CJK, MultiplierExponent_7_CJK }, 408 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, 409 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 410 }; 411 412 static Number natnum7[4] = { 413 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], NUMBER_OMIT_ALL, 414 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 415 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], NUMBER_OMIT_ALL, 416 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 417 { NumberChar_Modern_ja, MultiplierChar_2_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE, 418 ExponentCount_2_CJK, MultiplierExponent_2_CJK }, 419 { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ALL, 420 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 421 }; 422 423 static Number natnum8[4] = { 424 { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], NUMBER_OMIT_ALL, 425 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 426 { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, 427 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 428 { NumberChar_Traditional_ja, MultiplierChar_2_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE, 429 ExponentCount_2_CJK, MultiplierExponent_2_CJK }, 430 { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, 431 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 432 }; 433 434 static Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, 435 ExponentCount_6_CJK, MultiplierExponent_6_CJK }; 436 static Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL, 437 ExponentCount_6_CJK, MultiplierExponent_6_CJK }; 438 439 //! ATTENTION: Do not change order of elements! 440 //! Append new languages to the end of the list! 441 static const sal_Char *natnum1Locales[] = { 442 "zh_CN", 443 "zh_TW", 444 "ja", 445 "ko", 446 "he", 447 "ar", 448 "th", 449 "hi", 450 "or", 451 "mr", 452 "bn", 453 "pa", 454 "gu", 455 "ta", 456 "te", 457 "kn", 458 "ml", 459 "lo", 460 "bo", 461 "my", 462 "km", 463 "mn", 464 "ne", 465 "dz", 466 "fa" 467 }; 468 static sal_Int16 nbOfLocale = sizeof(natnum1Locales)/sizeof(natnum1Locales[0]); 469 470 //! ATTENTION: Do not change order of elements! 471 //! Number and order must match elements of natnum1Locales! 472 static sal_Int16 natnum1[] = { 473 NumberChar_Lower_zh, 474 NumberChar_Lower_zh, 475 NumberChar_Modern_ja, 476 NumberChar_Lower_ko, 477 NumberChar_he, 478 NumberChar_Indic_ar, 479 NumberChar_th, 480 NumberChar_hi, 481 NumberChar_or, 482 NumberChar_mr, 483 NumberChar_bn, 484 NumberChar_pa, 485 NumberChar_gu, 486 NumberChar_ta, 487 NumberChar_te, 488 NumberChar_kn, 489 NumberChar_ml, 490 NumberChar_lo, 491 NumberChar_bo, 492 NumberChar_my, 493 NumberChar_km, 494 NumberChar_mn, 495 NumberChar_ne, 496 NumberChar_dz, 497 NumberChar_EastIndic_ar 498 }; 499 static sal_Int16 sizeof_natnum1 = sizeof(natnum1)/sizeof(natnum1[0]); 500 501 //! ATTENTION: Do not change order of elements! 502 //! Order must match first elements of natnum1Locales! 503 static sal_Int16 natnum2[] = { 504 NumberChar_Upper_zh, 505 NumberChar_Upper_zh_TW, 506 NumberChar_Traditional_ja, 507 NumberChar_Upper_ko, 508 NumberChar_he 509 }; 510 static sal_Int16 sizeof_natnum2 = sizeof(natnum2)/sizeof(natnum2[0]); 511 512 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2) 513 #define isCtry(ctry) rLocale.Country.equalsAsciiL(ctry, 2) 514 515 static sal_Int16 SAL_CALL getLanguageNumber( const Locale& rLocale) 516 { 517 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales. 518 if (isLang("zh")) return (isCtry("TW") || isCtry("HK") || isCtry("MO")) ? 1 : 0; 519 520 for (sal_Int16 i = 2; i < nbOfLocale; i++) 521 if (isLang(natnum1Locales[i])) 522 return i; 523 524 return -1; 525 } 526 527 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, 528 sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) throw (RuntimeException) 529 { 530 Number *number = 0; 531 sal_Int16 num = -1; 532 533 if (isValidNatNum(rLocale, nNativeNumberMode)) { 534 sal_Int16 langnum = getLanguageNumber(rLocale); 535 switch (nNativeNumberMode) { 536 case NativeNumberMode::NATNUM0: // Ascii 537 return NativeToAscii(aNumberString, 0, aNumberString.getLength(), offset, useOffset); 538 case NativeNumberMode::NATNUM1: // Char, Lower 539 num = natnum1[langnum]; 540 break; 541 case NativeNumberMode::NATNUM2: // Char, Upper 542 num = natnum2[langnum]; 543 break; 544 case NativeNumberMode::NATNUM3: // Char, FullWidth 545 num = NumberChar_FullWidth; 546 break; 547 case NativeNumberMode::NATNUM4: // Text, Lower, Long 548 number = &natnum4[langnum]; 549 break; 550 case NativeNumberMode::NATNUM5: // Text, Upper, Long 551 number = &natnum5[langnum]; 552 break; 553 case NativeNumberMode::NATNUM6: // Text, FullWidth 554 number = &natnum6[langnum]; 555 break; 556 case NativeNumberMode::NATNUM7: // Text. Lower, Short 557 number = &natnum7[langnum]; 558 break; 559 case NativeNumberMode::NATNUM8: // Text, Upper, Short 560 number = &natnum8[langnum]; 561 break; 562 case NativeNumberMode::NATNUM9: // Char, Hangul 563 num = NumberChar_Hangul_ko; 564 break; 565 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 566 number = &natnum10; 567 break; 568 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 569 number = &natnum11; 570 break; 571 default: 572 break; 573 } 574 } 575 576 if (number || num >= 0) { 577 if (!aLocale.Language.equals(rLocale.Language) || 578 !aLocale.Country.equals(rLocale.Country) || 579 !aLocale.Variant.equals(rLocale.Variant)) { 580 LocaleDataItem item = LocaleData().getLocaleItem( rLocale ); 581 aLocale = rLocale; 582 DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar(); 583 if (DecimalChar[NumberChar_HalfWidth] > 0x7E || DecimalChar[NumberChar_HalfWidth] < 0x21) 584 DecimalChar[NumberChar_FullWidth]=0xFF0E; 585 else 586 DecimalChar[NumberChar_FullWidth]=DecimalChar[NumberChar_HalfWidth]+0xFEE0; 587 SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar(); 588 if (SeparatorChar[NumberChar_HalfWidth] > 0x7E || SeparatorChar[NumberChar_HalfWidth] < 0x21) 589 SeparatorChar[NumberChar_FullWidth]=0xFF0C; 590 else 591 SeparatorChar[NumberChar_FullWidth]=SeparatorChar[NumberChar_HalfWidth]+0xFEE0; 592 } 593 if (number) 594 return AsciiToNative( aNumberString, 0, aNumberString.getLength(), offset, useOffset, number ); 595 else if (num == NumberChar_he) 596 return getHebrewNativeNumberString(aNumberString, 597 nNativeNumberMode == NativeNumberMode::NATNUM2); 598 else 599 return AsciiToNativeChar(aNumberString, 0, aNumberString.getLength(), offset, useOffset, num); 600 } 601 else 602 return aNumberString; 603 } 604 605 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, 606 sal_Int16 nNativeNumberMode) throw (RuntimeException) 607 { 608 Sequence< sal_Int32 > offset; 609 return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, offset); 610 } 611 612 sal_Unicode SAL_CALL NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw(com::sun::star::uno::RuntimeException) 613 { 614 if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii 615 for (sal_Int16 i = 0; i < NumberChar_Count; i++) 616 for (sal_Int16 j = 0; j < 10; j++) 617 if (inChar == NumberChar[i][j]) 618 return j; 619 return inChar; 620 } 621 else if (isNumber(inChar) && isValidNatNum(rLocale, nNativeNumberMode)) { 622 sal_Int16 langnum = getLanguageNumber(rLocale); 623 switch (nNativeNumberMode) { 624 case NativeNumberMode::NATNUM1: // Char, Lower 625 case NativeNumberMode::NATNUM4: // Text, Lower, Long 626 case NativeNumberMode::NATNUM7: // Text. Lower, Short 627 return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO]; 628 case NativeNumberMode::NATNUM2: // Char, Upper 629 case NativeNumberMode::NATNUM5: // Text, Upper, Long 630 case NativeNumberMode::NATNUM8: // Text, Upper, Short 631 return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO]; 632 case NativeNumberMode::NATNUM3: // Char, FullWidth 633 case NativeNumberMode::NATNUM6: // Text, FullWidth 634 return NumberChar[NumberChar_FullWidth][inChar - NUMBER_ZERO]; 635 case NativeNumberMode::NATNUM9: // Char, Hangul 636 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 637 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 638 return NumberChar[NumberChar_Hangul_ko][inChar - NUMBER_ZERO]; 639 default: 640 break; 641 } 642 } 643 return inChar; 644 } 645 646 sal_Bool SAL_CALL NativeNumberSupplier::isValidNatNum( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException) 647 { 648 sal_Int16 langnum = getLanguageNumber(rLocale); 649 650 switch (nNativeNumberMode) { 651 case NativeNumberMode::NATNUM0: // Ascii 652 case NativeNumberMode::NATNUM3: // Char, FullWidth 653 return sal_True; 654 case NativeNumberMode::NATNUM1: // Char, Lower 655 return (langnum >= 0); 656 case NativeNumberMode::NATNUM2: // Char, Upper 657 if (langnum == 4) // Hebrew numbering 658 return sal_True; 659 case NativeNumberMode::NATNUM4: // Text, Lower, Long 660 case NativeNumberMode::NATNUM5: // Text, Upper, Long 661 case NativeNumberMode::NATNUM6: // Text, FullWidth 662 case NativeNumberMode::NATNUM7: // Text. Lower, Short 663 case NativeNumberMode::NATNUM8: // Text, Upper, Short 664 return (langnum >= 0 && langnum < 4); // CJK numbering 665 case NativeNumberMode::NATNUM9: // Char, Hangul 666 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 667 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 668 return (langnum == 3); // Korean numbering 669 } 670 return sal_False; 671 } 672 673 NativeNumberXmlAttributes SAL_CALL NativeNumberSupplier::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException) 674 { 675 static const sal_Int16 attShort = 0; 676 static const sal_Int16 attMedium = 1; 677 static const sal_Int16 attLong = 2; 678 static const sal_Char *attType[] = { "short", "medium", "long" }; 679 680 sal_Int16 number = NumberChar_HalfWidth, type = attShort; 681 682 if (isValidNatNum(rLocale, nNativeNumberMode)) { 683 sal_Int16 langnum = getLanguageNumber(rLocale); 684 switch (nNativeNumberMode) { 685 case NativeNumberMode::NATNUM0: // Ascii 686 number = NumberChar_HalfWidth; 687 type = attShort; 688 break; 689 case NativeNumberMode::NATNUM1: // Char, Lower 690 number = natnum1[langnum]; 691 type = attShort; 692 break; 693 case NativeNumberMode::NATNUM2: // Char, Upper 694 number = natnum2[langnum]; 695 type = number == NumberChar_he ? attMedium : attShort; 696 break; 697 case NativeNumberMode::NATNUM3: // Char, FullWidth 698 number = NumberChar_FullWidth; 699 type = attShort; 700 break; 701 case NativeNumberMode::NATNUM4: // Text, Lower, Long 702 number = natnum1[langnum]; 703 type = attLong; 704 break; 705 case NativeNumberMode::NATNUM5: // Text, Upper, Long 706 number = natnum2[langnum]; 707 type = attLong; 708 break; 709 case NativeNumberMode::NATNUM6: // Text, FullWidth 710 number = NumberChar_FullWidth; 711 type = attLong; 712 break; 713 case NativeNumberMode::NATNUM7: // Text. Lower, Short 714 number = natnum1[langnum]; 715 type = attMedium; 716 break; 717 case NativeNumberMode::NATNUM8: // Text, Upper, Short 718 number = natnum2[langnum]; 719 type = attMedium; 720 break; 721 case NativeNumberMode::NATNUM9: // Char, Hangul 722 number = NumberChar_Hangul_ko; 723 type = attShort; 724 break; 725 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 726 number = NumberChar_Hangul_ko; 727 type = attLong; 728 break; 729 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 730 number = NumberChar_Hangul_ko; 731 type = attMedium; 732 break; 733 default: 734 break; 735 } 736 } 737 return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1), 738 OUString::createFromAscii(attType[type])); 739 } 740 741 static sal_Bool natNumIn(sal_Int16 num, sal_Int16 natnum[], sal_Int16 len) 742 { 743 for (sal_Int16 i = 0; i < len; i++) 744 if (natnum[i] == num) 745 return sal_True; 746 return sal_False; 747 } 748 749 sal_Int16 SAL_CALL NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr ) throw (RuntimeException) 750 { 751 sal_Unicode numberChar[NumberChar_Count]; 752 for (sal_Int16 i = 0; i < NumberChar_Count; i++) 753 numberChar[i] = NumberChar[i][1]; 754 OUString number(numberChar, NumberChar_Count); 755 756 sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) ); 757 758 if (aAttr.Style.equalsAscii("short")) { 759 if (num == NumberChar_FullWidth) 760 return NativeNumberMode::NATNUM3; 761 else if (num == NumberChar_Hangul_ko) 762 return NativeNumberMode::NATNUM9; 763 else if (natNumIn(num, natnum1, sizeof_natnum1)) 764 return NativeNumberMode::NATNUM1; 765 else if (natNumIn(num, natnum2, sizeof_natnum2)) 766 return NativeNumberMode::NATNUM2; 767 } else if (aAttr.Style.equalsAscii("medium")) { 768 if (num == NumberChar_Hangul_ko) 769 return NativeNumberMode::NATNUM11; 770 else if (num == NumberChar_he) 771 return NativeNumberMode::NATNUM2; 772 else if (natNumIn(num, natnum1, sizeof_natnum1)) 773 return NativeNumberMode::NATNUM7; 774 else if (natNumIn(num, natnum2, sizeof_natnum2)) 775 return NativeNumberMode::NATNUM8; 776 } else if (aAttr.Style.equalsAscii("long")) { 777 if (num == NumberChar_FullWidth) 778 return NativeNumberMode::NATNUM6; 779 else if (num == NumberChar_Hangul_ko) 780 return NativeNumberMode::NATNUM10; 781 else if (natNumIn(num, natnum1, sizeof_natnum1)) 782 return NativeNumberMode::NATNUM4; 783 else if (natNumIn(num, natnum2, sizeof_natnum2)) 784 return NativeNumberMode::NATNUM5; 785 } else { 786 throw RuntimeException(); 787 } 788 return NativeNumberMode::NATNUM0; 789 } 790 791 792 // Following code generates Hebrew Number, 793 // see numerical system in the Hebrew Numbering System in following link for details, 794 // http://people.netscape.com/smontagu/writings/HebrewNumbers.html 795 796 struct HebrewNumberChar { 797 sal_Unicode code; 798 sal_Int16 value; 799 } HebrewNumberCharArray[] = { 800 { 0x05ea, 400 }, 801 { 0x05ea, 400 }, 802 { 0x05e9, 300 }, 803 { 0x05e8, 200 }, 804 { 0x05e7, 100 }, 805 { 0x05e6, 90 }, 806 { 0x05e4, 80 }, 807 { 0x05e2, 70 }, 808 { 0x05e1, 60 }, 809 { 0x05e0, 50 }, 810 { 0x05de, 40 }, 811 { 0x05dc, 30 }, 812 { 0x05db, 20 }, 813 { 0x05d9, 10 }, 814 { 0x05d8, 9 }, 815 { 0x05d7, 8 }, 816 { 0x05d6, 7 }, 817 { 0x05d5, 6 }, 818 { 0x05d4, 5 }, 819 { 0x05d3, 4 }, 820 { 0x05d2, 3 }, 821 { 0x05d1, 2 }, 822 { 0x05d0, 1 } 823 }; 824 825 static sal_Int16 nbOfHebrewNumberChar = sizeof(HebrewNumberCharArray)/sizeof(HebrewNumberChar); 826 827 static sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0}; 828 static sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0}; 829 static sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0}; 830 static sal_Unicode geresh = 0x05f3; 831 static sal_Unicode gershayim = 0x05f4; 832 833 void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, sal_Bool isLast, sal_Bool useGeresh) 834 { 835 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000); 836 837 if (value > 1000) { 838 makeHebrewNumber(value / 1000, output, num != 0, useGeresh); 839 output.appendAscii(" "); 840 } 841 if (num == 0) { 842 output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands); 843 } else { 844 sal_Int16 nbOfChar = 0; 845 for (sal_Int32 j = 0; num > 0 && j < nbOfHebrewNumberChar; j++) { 846 if (num - HebrewNumberCharArray[j].value >= 0) { 847 nbOfChar++; 848 if (num == 15 || num == 16) // substitution for 15 and 16 849 j++; 850 num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value ); 851 output.append(HebrewNumberCharArray[j].code); 852 } 853 } 854 if (useGeresh) { 855 if (nbOfChar > 1) // a number is written as more than one character 856 output.insert(output.getLength() - 1, gershayim); 857 else if (nbOfChar == 1) // a number is written as a single character 858 output.append(geresh); 859 } 860 } 861 } 862 863 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh) 864 { 865 sal_Int64 value = 0; 866 sal_Int32 i, count = 0, len = aNumberString.getLength(); 867 const sal_Unicode *src = aNumberString.getStr(); 868 sal_Bool neg = sal_False; 869 870 for (i = 0; i < len; i++) { 871 sal_Unicode ch = src[i]; 872 if (isNumber(ch)) { 873 if (++count >= 20) // Number is too long, could not be handled. 874 return aNumberString; 875 value = value * 10 + (ch - NUMBER_ZERO); 876 } 877 else if (isSeparator(ch) && count > 0) continue; 878 else if (isMinus(ch) && count == 0) neg = sal_True; 879 else break; 880 } 881 882 if (value > 0) { 883 OUStringBuffer output(count*2 + 2 + len - i); 884 885 makeHebrewNumber(value, output, sal_True, useGeresh); 886 887 if (i < len) 888 output.append(aNumberString.copy(i)); 889 890 return output.makeStringAndClear(); 891 } 892 else 893 return aNumberString; 894 } 895 896 static const sal_Char* implementationName = "com.sun.star.i18n.NativeNumberSupplier"; 897 898 OUString SAL_CALL NativeNumberSupplier::getImplementationName() throw( RuntimeException ) 899 { 900 return OUString::createFromAscii( implementationName ); 901 } 902 903 sal_Bool SAL_CALL 904 NativeNumberSupplier::supportsService(const OUString& rServiceName) throw( RuntimeException ) 905 { 906 return rServiceName.compareToAscii(implementationName) == 0; 907 } 908 909 Sequence< OUString > SAL_CALL 910 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException ) 911 { 912 Sequence< OUString > aRet(1); 913 aRet[0] = OUString::createFromAscii( implementationName ); 914 return aRet; 915 } 916 917 } } } } 918