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