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 ); // defined in x_rtl_ustring.h 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, SAL_NO_ACQUIRE); // take over ownership of <newStr> 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 OUString resultStr( newStr->buffer, count ); 250 x_rtl_uString_release( newStr ); 251 x_rtl_uString_release( srcStr ); 252 return resultStr; 253 } 254 return OUString(); 255 } 256 static void SAL_CALL NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str, 257 sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, sal_Bool useOffset, 258 OUString& numberChar, OUString& multiplierChar) 259 { 260 sal_Int16 curr = 0, num = 0, end = 0, shift = 0; 261 while (++i < nCount) { 262 if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) { 263 if (num > 0) 264 break; 265 num = curr % 10; 266 } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) { 267 curr = MultiplierExponent_7_CJK[curr % ExponentCount_7_CJK]; 268 if (prev > curr && num == 0) num = 1; // One may be omitted in informal format 269 shift = end = 0; 270 if (curr >= max) 271 max = curr; 272 else if (curr > prev) 273 shift = max - curr; 274 else 275 end = curr; 276 while (end++ < prev) { 277 dst[count] = NUMBER_ZERO + (end == prev ? num : 0); 278 if (useOffset) 279 offset[count] = i; 280 count++; 281 } 282 if (shift) { 283 count -= max; 284 for (sal_Int16 j = 0; j < shift; j++, count++) { 285 dst[count] = dst[count + curr]; 286 if (useOffset) 287 offset[count] = offset[count + curr]; 288 } 289 max = curr; 290 } 291 NativeToAscii_numberMaker(max, curr, str, i, nCount, dst, 292 count, offset, useOffset, numberChar, multiplierChar); 293 return; 294 } else 295 break; 296 } 297 while (end++ < prev) { 298 dst[count] = NUMBER_ZERO + (end == prev ? num : 0); 299 if (useOffset) 300 offset[count] = i - 1; 301 count++; 302 } 303 } 304 305 static OUString SAL_CALL NativeToAscii(const OUString& inStr, 306 sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset, sal_Bool useOffset ) throw(RuntimeException) 307 { 308 sal_Int32 strLen = inStr.getLength() - startPos; 309 310 if (nCount > strLen) 311 nCount = strLen; 312 313 if (nCount > 0) { 314 const sal_Unicode *str = inStr.getStr() + startPos; 315 rtl_uString *newStr = x_rtl_uString_new_WithLength( nCount * MultiplierExponent_7_CJK[0] + 1 ); 316 if (useOffset) 317 offset.realloc( nCount * MultiplierExponent_7_CJK[0] + 1 ); 318 sal_Int32 count = 0, index; 319 sal_Int32 i; 320 321 OUString numberChar, multiplierChar, decimalChar, minusChar, separatorChar; 322 numberChar = OUString((sal_Unicode*)NumberChar, 10*NumberChar_Count); 323 multiplierChar = OUString((sal_Unicode*) MultiplierChar_7_CJK, ExponentCount_7_CJK*Multiplier_Count); 324 decimalChar = OUString(DecimalChar, NumberChar_Count); 325 minusChar = OUString(MinusChar, NumberChar_Count); 326 separatorChar = OUString(SeparatorChar, NumberChar_Count); 327 328 for ( i = 0; i < nCount; i++) { 329 if ((index = multiplierChar.indexOf(str[i])) >= 0) { 330 if (count == 0 || !isNumber(newStr->buffer[count-1])) { // add 1 in front of multiplier 331 newStr->buffer[count] = NUMBER_ONE; 332 if (useOffset) 333 offset[count] = i; 334 count++; 335 } 336 index = MultiplierExponent_7_CJK[index % ExponentCount_7_CJK]; 337 NativeToAscii_numberMaker( 338 sal::static_int_cast<sal_Int16>( index ), sal::static_int_cast<sal_Int16>( index ), 339 str, i, nCount, newStr->buffer, count, offset, useOffset, 340 numberChar, multiplierChar); 341 } else { 342 if ((index = numberChar.indexOf(str[i])) >= 0) 343 newStr->buffer[count] = sal::static_int_cast<sal_Unicode>( (index % 10) + NUMBER_ZERO ); 344 else if ((index = separatorChar.indexOf(str[i])) >= 0 && 345 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || 346 multiplierChar.indexOf(str[i+1]) >= 0))) 347 newStr->buffer[count] = SeparatorChar[NumberChar_HalfWidth]; 348 else if ((index = decimalChar.indexOf(str[i])) >= 0 && 349 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || 350 multiplierChar.indexOf(str[i+1]) >= 0))) 351 // Only when decimal point is followed by numbers, 352 // it will be convert to ASCII decimal point 353 newStr->buffer[count] = DecimalChar[NumberChar_HalfWidth]; 354 else if ((index = minusChar.indexOf(str[i])) >= 0 && 355 (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || 356 multiplierChar.indexOf(str[i+1]) >= 0))) 357 // Only when minus is followed by numbers, 358 // it will be convert to ASCII minus sign 359 newStr->buffer[count] = MinusChar[NumberChar_HalfWidth]; 360 else 361 newStr->buffer[count] = str[i]; 362 if (useOffset) 363 offset[count] = i; 364 count++; 365 } 366 } 367 368 if (useOffset) { 369 offset.realloc(count); 370 for (i = 0; i < count; i++) 371 offset[i] += startPos; 372 } 373 OUString resultStr( newStr->buffer, count ); 374 x_rtl_uString_release( newStr ); 375 return resultStr; 376 } 377 return OUString(); 378 } 379 380 static Number natnum4[4] = { 381 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, 382 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 383 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, 384 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 385 { NumberChar_Modern_ja, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67, 386 ExponentCount_7_CJK, MultiplierExponent_7_CJK }, 387 { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ZERO, 388 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 389 }; 390 391 static Number natnum5[4] = { 392 { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], 0, 393 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 394 { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], 0, 395 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 396 { NumberChar_Traditional_ja, MultiplierChar_7_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE_67, 397 ExponentCount_7_CJK, MultiplierExponent_7_CJK }, 398 { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ZERO, 399 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 400 }; 401 402 static Number natnum6[4] = { 403 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, 404 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 405 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, 406 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 407 { NumberChar_FullWidth, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67, 408 ExponentCount_7_CJK, MultiplierExponent_7_CJK }, 409 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, 410 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 411 }; 412 413 static Number natnum7[4] = { 414 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], NUMBER_OMIT_ALL, 415 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 416 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], NUMBER_OMIT_ALL, 417 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 418 { NumberChar_Modern_ja, MultiplierChar_2_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE, 419 ExponentCount_2_CJK, MultiplierExponent_2_CJK }, 420 { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ALL, 421 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 422 }; 423 424 static Number natnum8[4] = { 425 { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], NUMBER_OMIT_ALL, 426 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 427 { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, 428 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 429 { NumberChar_Traditional_ja, MultiplierChar_2_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE, 430 ExponentCount_2_CJK, MultiplierExponent_2_CJK }, 431 { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, 432 ExponentCount_6_CJK, MultiplierExponent_6_CJK }, 433 }; 434 435 static Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, 436 ExponentCount_6_CJK, MultiplierExponent_6_CJK }; 437 static Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL, 438 ExponentCount_6_CJK, MultiplierExponent_6_CJK }; 439 440 //! ATTENTION: Do not change order of elements! 441 //! Append new languages to the end of the list! 442 static const sal_Char *natnum1Locales[] = { 443 "zh_CN", 444 "zh_TW", 445 "ja", 446 "ko", 447 "he", 448 "ar", 449 "th", 450 "hi", 451 "or", 452 "mr", 453 "bn", 454 "pa", 455 "gu", 456 "ta", 457 "te", 458 "kn", 459 "ml", 460 "lo", 461 "bo", 462 "my", 463 "km", 464 "mn", 465 "ne", 466 "dz", 467 "fa" 468 }; 469 static sal_Int16 nbOfLocale = sizeof(natnum1Locales)/sizeof(natnum1Locales[0]); 470 471 //! ATTENTION: Do not change order of elements! 472 //! Number and order must match elements of natnum1Locales! 473 static sal_Int16 natnum1[] = { 474 NumberChar_Lower_zh, 475 NumberChar_Lower_zh, 476 NumberChar_Modern_ja, 477 NumberChar_Lower_ko, 478 NumberChar_he, 479 NumberChar_Indic_ar, 480 NumberChar_th, 481 NumberChar_hi, 482 NumberChar_or, 483 NumberChar_mr, 484 NumberChar_bn, 485 NumberChar_pa, 486 NumberChar_gu, 487 NumberChar_ta, 488 NumberChar_te, 489 NumberChar_kn, 490 NumberChar_ml, 491 NumberChar_lo, 492 NumberChar_bo, 493 NumberChar_my, 494 NumberChar_km, 495 NumberChar_mn, 496 NumberChar_ne, 497 NumberChar_dz, 498 NumberChar_EastIndic_ar 499 }; 500 static sal_Int16 sizeof_natnum1 = sizeof(natnum1)/sizeof(natnum1[0]); 501 502 //! ATTENTION: Do not change order of elements! 503 //! Order must match first elements of natnum1Locales! 504 static sal_Int16 natnum2[] = { 505 NumberChar_Upper_zh, 506 NumberChar_Upper_zh_TW, 507 NumberChar_Traditional_ja, 508 NumberChar_Upper_ko, 509 NumberChar_he 510 }; 511 static sal_Int16 sizeof_natnum2 = sizeof(natnum2)/sizeof(natnum2[0]); 512 513 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2) 514 #define isCtry(ctry) rLocale.Country.equalsAsciiL(ctry, 2) 515 516 static sal_Int16 SAL_CALL getLanguageNumber( const Locale& rLocale) 517 { 518 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales. 519 if (isLang("zh")) return (isCtry("TW") || isCtry("HK") || isCtry("MO")) ? 1 : 0; 520 521 for (sal_Int16 i = 2; i < nbOfLocale; i++) 522 if (isLang(natnum1Locales[i])) 523 return i; 524 525 return -1; 526 } 527 528 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, 529 sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) throw (RuntimeException) 530 { 531 Number *number = 0; 532 sal_Int16 num = -1; 533 534 if (isValidNatNum(rLocale, nNativeNumberMode)) { 535 sal_Int16 langnum = getLanguageNumber(rLocale); 536 switch (nNativeNumberMode) { 537 case NativeNumberMode::NATNUM0: // Ascii 538 return NativeToAscii(aNumberString, 0, aNumberString.getLength(), offset, useOffset); 539 case NativeNumberMode::NATNUM1: // Char, Lower 540 num = natnum1[langnum]; 541 break; 542 case NativeNumberMode::NATNUM2: // Char, Upper 543 num = natnum2[langnum]; 544 break; 545 case NativeNumberMode::NATNUM3: // Char, FullWidth 546 num = NumberChar_FullWidth; 547 break; 548 case NativeNumberMode::NATNUM4: // Text, Lower, Long 549 number = &natnum4[langnum]; 550 break; 551 case NativeNumberMode::NATNUM5: // Text, Upper, Long 552 number = &natnum5[langnum]; 553 break; 554 case NativeNumberMode::NATNUM6: // Text, FullWidth 555 number = &natnum6[langnum]; 556 break; 557 case NativeNumberMode::NATNUM7: // Text. Lower, Short 558 number = &natnum7[langnum]; 559 break; 560 case NativeNumberMode::NATNUM8: // Text, Upper, Short 561 number = &natnum8[langnum]; 562 break; 563 case NativeNumberMode::NATNUM9: // Char, Hangul 564 num = NumberChar_Hangul_ko; 565 break; 566 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 567 number = &natnum10; 568 break; 569 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 570 number = &natnum11; 571 break; 572 default: 573 break; 574 } 575 } 576 577 if (number || num >= 0) { 578 if (!aLocale.Language.equals(rLocale.Language) || 579 !aLocale.Country.equals(rLocale.Country) || 580 !aLocale.Variant.equals(rLocale.Variant)) { 581 LocaleDataItem item = LocaleData().getLocaleItem( rLocale ); 582 aLocale = rLocale; 583 DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar(); 584 if (DecimalChar[NumberChar_HalfWidth] > 0x7E || DecimalChar[NumberChar_HalfWidth] < 0x21) 585 DecimalChar[NumberChar_FullWidth]=0xFF0E; 586 else 587 DecimalChar[NumberChar_FullWidth]=DecimalChar[NumberChar_HalfWidth]+0xFEE0; 588 SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar(); 589 if (SeparatorChar[NumberChar_HalfWidth] > 0x7E || SeparatorChar[NumberChar_HalfWidth] < 0x21) 590 SeparatorChar[NumberChar_FullWidth]=0xFF0C; 591 else 592 SeparatorChar[NumberChar_FullWidth]=SeparatorChar[NumberChar_HalfWidth]+0xFEE0; 593 } 594 if (number) 595 return AsciiToNative( aNumberString, 0, aNumberString.getLength(), offset, useOffset, number ); 596 else if (num == NumberChar_he) 597 return getHebrewNativeNumberString(aNumberString, 598 nNativeNumberMode == NativeNumberMode::NATNUM2); 599 else 600 return AsciiToNativeChar(aNumberString, 0, aNumberString.getLength(), offset, useOffset, num); 601 } 602 else 603 return aNumberString; 604 } 605 606 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, 607 sal_Int16 nNativeNumberMode) throw (RuntimeException) 608 { 609 Sequence< sal_Int32 > offset; 610 return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, offset); 611 } 612 613 sal_Unicode SAL_CALL NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw(com::sun::star::uno::RuntimeException) 614 { 615 if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii 616 for (sal_Int16 i = 0; i < NumberChar_Count; i++) 617 for (sal_Int16 j = 0; j < 10; j++) 618 if (inChar == NumberChar[i][j]) 619 return j; 620 return inChar; 621 } 622 else if (isNumber(inChar) && isValidNatNum(rLocale, nNativeNumberMode)) { 623 sal_Int16 langnum = getLanguageNumber(rLocale); 624 switch (nNativeNumberMode) { 625 case NativeNumberMode::NATNUM1: // Char, Lower 626 case NativeNumberMode::NATNUM4: // Text, Lower, Long 627 case NativeNumberMode::NATNUM7: // Text. Lower, Short 628 return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO]; 629 case NativeNumberMode::NATNUM2: // Char, Upper 630 case NativeNumberMode::NATNUM5: // Text, Upper, Long 631 case NativeNumberMode::NATNUM8: // Text, Upper, Short 632 return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO]; 633 case NativeNumberMode::NATNUM3: // Char, FullWidth 634 case NativeNumberMode::NATNUM6: // Text, FullWidth 635 return NumberChar[NumberChar_FullWidth][inChar - NUMBER_ZERO]; 636 case NativeNumberMode::NATNUM9: // Char, Hangul 637 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 638 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 639 return NumberChar[NumberChar_Hangul_ko][inChar - NUMBER_ZERO]; 640 default: 641 break; 642 } 643 } 644 return inChar; 645 } 646 647 sal_Bool SAL_CALL NativeNumberSupplier::isValidNatNum( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException) 648 { 649 sal_Int16 langnum = getLanguageNumber(rLocale); 650 651 switch (nNativeNumberMode) { 652 case NativeNumberMode::NATNUM0: // Ascii 653 case NativeNumberMode::NATNUM3: // Char, FullWidth 654 return sal_True; 655 case NativeNumberMode::NATNUM1: // Char, Lower 656 return (langnum >= 0); 657 case NativeNumberMode::NATNUM2: // Char, Upper 658 if (langnum == 4) // Hebrew numbering 659 return sal_True; 660 case NativeNumberMode::NATNUM4: // Text, Lower, Long 661 case NativeNumberMode::NATNUM5: // Text, Upper, Long 662 case NativeNumberMode::NATNUM6: // Text, FullWidth 663 case NativeNumberMode::NATNUM7: // Text. Lower, Short 664 case NativeNumberMode::NATNUM8: // Text, Upper, Short 665 return (langnum >= 0 && langnum < 4); // CJK numbering 666 case NativeNumberMode::NATNUM9: // Char, Hangul 667 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 668 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 669 return (langnum == 3); // Korean numbering 670 } 671 return sal_False; 672 } 673 674 NativeNumberXmlAttributes SAL_CALL NativeNumberSupplier::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException) 675 { 676 static const sal_Int16 attShort = 0; 677 static const sal_Int16 attMedium = 1; 678 static const sal_Int16 attLong = 2; 679 static const sal_Char *attType[] = { "short", "medium", "long" }; 680 681 sal_Int16 number = NumberChar_HalfWidth, type = attShort; 682 683 if (isValidNatNum(rLocale, nNativeNumberMode)) { 684 sal_Int16 langnum = getLanguageNumber(rLocale); 685 switch (nNativeNumberMode) { 686 case NativeNumberMode::NATNUM0: // Ascii 687 number = NumberChar_HalfWidth; 688 type = attShort; 689 break; 690 case NativeNumberMode::NATNUM1: // Char, Lower 691 number = natnum1[langnum]; 692 type = attShort; 693 break; 694 case NativeNumberMode::NATNUM2: // Char, Upper 695 number = natnum2[langnum]; 696 type = number == NumberChar_he ? attMedium : attShort; 697 break; 698 case NativeNumberMode::NATNUM3: // Char, FullWidth 699 number = NumberChar_FullWidth; 700 type = attShort; 701 break; 702 case NativeNumberMode::NATNUM4: // Text, Lower, Long 703 number = natnum1[langnum]; 704 type = attLong; 705 break; 706 case NativeNumberMode::NATNUM5: // Text, Upper, Long 707 number = natnum2[langnum]; 708 type = attLong; 709 break; 710 case NativeNumberMode::NATNUM6: // Text, FullWidth 711 number = NumberChar_FullWidth; 712 type = attLong; 713 break; 714 case NativeNumberMode::NATNUM7: // Text. Lower, Short 715 number = natnum1[langnum]; 716 type = attMedium; 717 break; 718 case NativeNumberMode::NATNUM8: // Text, Upper, Short 719 number = natnum2[langnum]; 720 type = attMedium; 721 break; 722 case NativeNumberMode::NATNUM9: // Char, Hangul 723 number = NumberChar_Hangul_ko; 724 type = attShort; 725 break; 726 case NativeNumberMode::NATNUM10: // Text, Hangul, Long 727 number = NumberChar_Hangul_ko; 728 type = attLong; 729 break; 730 case NativeNumberMode::NATNUM11: // Text, Hangul, Short 731 number = NumberChar_Hangul_ko; 732 type = attMedium; 733 break; 734 default: 735 break; 736 } 737 } 738 return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1), 739 OUString::createFromAscii(attType[type])); 740 } 741 742 static sal_Bool natNumIn(sal_Int16 num, sal_Int16 natnum[], sal_Int16 len) 743 { 744 for (sal_Int16 i = 0; i < len; i++) 745 if (natnum[i] == num) 746 return sal_True; 747 return sal_False; 748 } 749 750 sal_Int16 SAL_CALL NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr ) throw (RuntimeException) 751 { 752 sal_Unicode numberChar[NumberChar_Count]; 753 for (sal_Int16 i = 0; i < NumberChar_Count; i++) 754 numberChar[i] = NumberChar[i][1]; 755 OUString number(numberChar, NumberChar_Count); 756 757 sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) ); 758 759 if (aAttr.Style.equalsAscii("short")) { 760 if (num == NumberChar_FullWidth) 761 return NativeNumberMode::NATNUM3; 762 else if (num == NumberChar_Hangul_ko) 763 return NativeNumberMode::NATNUM9; 764 else if (natNumIn(num, natnum1, sizeof_natnum1)) 765 return NativeNumberMode::NATNUM1; 766 else if (natNumIn(num, natnum2, sizeof_natnum2)) 767 return NativeNumberMode::NATNUM2; 768 } else if (aAttr.Style.equalsAscii("medium")) { 769 if (num == NumberChar_Hangul_ko) 770 return NativeNumberMode::NATNUM11; 771 else if (num == NumberChar_he) 772 return NativeNumberMode::NATNUM2; 773 else if (natNumIn(num, natnum1, sizeof_natnum1)) 774 return NativeNumberMode::NATNUM7; 775 else if (natNumIn(num, natnum2, sizeof_natnum2)) 776 return NativeNumberMode::NATNUM8; 777 } else if (aAttr.Style.equalsAscii("long")) { 778 if (num == NumberChar_FullWidth) 779 return NativeNumberMode::NATNUM6; 780 else if (num == NumberChar_Hangul_ko) 781 return NativeNumberMode::NATNUM10; 782 else if (natNumIn(num, natnum1, sizeof_natnum1)) 783 return NativeNumberMode::NATNUM4; 784 else if (natNumIn(num, natnum2, sizeof_natnum2)) 785 return NativeNumberMode::NATNUM5; 786 } else { 787 throw RuntimeException(); 788 } 789 return NativeNumberMode::NATNUM0; 790 } 791 792 793 // Following code generates Hebrew Number, 794 // see numerical system in the Hebrew Numbering System in following link for details, 795 // http://people.netscape.com/smontagu/writings/HebrewNumbers.html 796 797 struct HebrewNumberChar { 798 sal_Unicode code; 799 sal_Int16 value; 800 } HebrewNumberCharArray[] = { 801 { 0x05ea, 400 }, 802 { 0x05ea, 400 }, 803 { 0x05e9, 300 }, 804 { 0x05e8, 200 }, 805 { 0x05e7, 100 }, 806 { 0x05e6, 90 }, 807 { 0x05e4, 80 }, 808 { 0x05e2, 70 }, 809 { 0x05e1, 60 }, 810 { 0x05e0, 50 }, 811 { 0x05de, 40 }, 812 { 0x05dc, 30 }, 813 { 0x05db, 20 }, 814 { 0x05d9, 10 }, 815 { 0x05d8, 9 }, 816 { 0x05d7, 8 }, 817 { 0x05d6, 7 }, 818 { 0x05d5, 6 }, 819 { 0x05d4, 5 }, 820 { 0x05d3, 4 }, 821 { 0x05d2, 3 }, 822 { 0x05d1, 2 }, 823 { 0x05d0, 1 } 824 }; 825 826 static sal_Int16 nbOfHebrewNumberChar = sizeof(HebrewNumberCharArray)/sizeof(HebrewNumberChar); 827 828 static sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0}; 829 static sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0}; 830 static sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0}; 831 static sal_Unicode geresh = 0x05f3; 832 static sal_Unicode gershayim = 0x05f4; 833 834 void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, sal_Bool isLast, sal_Bool useGeresh) 835 { 836 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000); 837 838 if (value > 1000) { 839 makeHebrewNumber(value / 1000, output, num != 0, useGeresh); 840 output.appendAscii(" "); 841 } 842 if (num == 0) { 843 output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands); 844 } else { 845 sal_Int16 nbOfChar = 0; 846 for (sal_Int32 j = 0; num > 0 && j < nbOfHebrewNumberChar; j++) { 847 if (num - HebrewNumberCharArray[j].value >= 0) { 848 nbOfChar++; 849 if (num == 15 || num == 16) // substitution for 15 and 16 850 j++; 851 num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value ); 852 output.append(HebrewNumberCharArray[j].code); 853 } 854 } 855 if (useGeresh) { 856 if (nbOfChar > 1) // a number is written as more than one character 857 output.insert(output.getLength() - 1, gershayim); 858 else if (nbOfChar == 1) // a number is written as a single character 859 output.append(geresh); 860 } 861 } 862 } 863 864 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh) 865 { 866 sal_Int64 value = 0; 867 sal_Int32 i, count = 0, len = aNumberString.getLength(); 868 const sal_Unicode *src = aNumberString.getStr(); 869 sal_Bool neg = sal_False; 870 871 for (i = 0; i < len; i++) { 872 sal_Unicode ch = src[i]; 873 if (isNumber(ch)) { 874 if (++count >= 20) // Number is too long, could not be handled. 875 return aNumberString; 876 value = value * 10 + (ch - NUMBER_ZERO); 877 } 878 else if (isSeparator(ch) && count > 0) continue; 879 else if (isMinus(ch) && count == 0) neg = sal_True; 880 else break; 881 } 882 883 if (value > 0) { 884 OUStringBuffer output(count*2 + 2 + len - i); 885 886 makeHebrewNumber(value, output, sal_True, useGeresh); 887 888 if (i < len) 889 output.append(aNumberString.copy(i)); 890 891 return output.makeStringAndClear(); 892 } 893 else 894 return aNumberString; 895 } 896 897 static const sal_Char* implementationName = "com.sun.star.i18n.NativeNumberSupplier"; 898 899 OUString SAL_CALL NativeNumberSupplier::getImplementationName() throw( RuntimeException ) 900 { 901 return OUString::createFromAscii( implementationName ); 902 } 903 904 sal_Bool SAL_CALL 905 NativeNumberSupplier::supportsService(const OUString& rServiceName) throw( RuntimeException ) 906 { 907 return rServiceName.compareToAscii(implementationName) == 0; 908 } 909 910 Sequence< OUString > SAL_CALL 911 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException ) 912 { 913 Sequence< OUString > aRet(1); 914 aRet[0] = OUString::createFromAscii( implementationName ); 915 return aRet; 916 } 917 918 } } } } 919