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