bump product version to 4.1.6.2
[LibreOffice.git] / i18npool / source / nativenumber / nativenumbersupplier.cxx
blobe73c0c31a600b84debec38575aaf1872d162f9a7
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <i18nlangtag/mslangid.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <sal/macros.h>
23 #include <nativenumbersupplier.hxx>
24 #include <localedata.hxx>
25 #include <data/numberchar.h>
26 #include <comphelper/string.hxx>
28 using namespace ::com::sun::star::uno;
29 using namespace ::com::sun::star::lang;
30 using namespace ::rtl;
33 typedef struct {
34 sal_Int16 number;
35 sal_Unicode *multiplierChar;
36 sal_Int16 numberFlag;
37 sal_Int16 exponentCount;
38 sal_Int16 *multiplierExponent;
39 } Number;
42 #define NUMBER_OMIT_ZERO (1 << 0)
43 #define NUMBER_OMIT_ONLY_ZERO (1 << 1)
44 #define NUMBER_OMIT_ONE_1 (1 << 2)
45 #define NUMBER_OMIT_ONE_2 (1 << 3)
46 #define NUMBER_OMIT_ONE_3 (1 << 4)
47 #define NUMBER_OMIT_ONE_4 (1 << 5)
48 #define NUMBER_OMIT_ONE_5 (1 << 6)
49 #define NUMBER_OMIT_ONE_6 (1 << 7)
50 #define NUMBER_OMIT_ONE_7 (1 << 8)
51 #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)
52 #define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit))
53 #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
54 #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
55 #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
56 #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
58 namespace com { namespace sun { namespace star { namespace i18n {
60 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh);
62 OUString SAL_CALL AsciiToNativeChar( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
63 Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int16 number ) throw(RuntimeException)
65 const sal_Unicode *src = inStr.getStr() + startPos;
66 rtl_uString *newStr = rtl_uString_alloc(nCount);
67 if (useOffset)
68 offset.realloc(nCount);
70 for (sal_Int32 i = 0; i < nCount; i++)
72 sal_Unicode ch = src[i];
73 if (isNumber(ch))
74 newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ];
75 else if (i+1 < nCount && isNumber(src[i+1])) {
76 if (i > 0 && isNumber(src[i-1]) && isSeparator(ch))
77 newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch;
78 else
79 newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) :
80 isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch;
82 else
83 newStr->buffer[i] = ch;
84 if (useOffset)
85 offset[i] = startPos + i;
87 return OUString(newStr, SAL_NO_ACQUIRE); // take ownership
90 sal_Bool SAL_CALL AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len,
91 sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int32 startPos,
92 Number *number, sal_Unicode* numberChar)
94 sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]);
95 if ( len <= number->multiplierExponent[number->exponentCount-1] ) {
96 if (number->multiplierExponent[number->exponentCount-1] > 1) {
97 sal_Int16 i;
98 sal_Bool notZero = false;
99 for (i = 0; i < len; i++, begin++) {
100 if (notZero || str[begin] != NUMBER_ZERO) {
101 dst[count] = numberChar[str[begin] - NUMBER_ZERO];
102 if (useOffset)
103 offset[count] = begin + startPos;
104 count++;
105 notZero = sal_True;
108 if (notZero && multiChar > 0) {
109 dst[count] = multiChar;
110 if (useOffset)
111 offset[count] = begin + startPos;
112 count++;
114 return notZero;
115 } else if (str[begin] != NUMBER_ZERO) {
116 if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) {
117 dst[count] = numberChar[str[begin] - NUMBER_ZERO];
118 if (useOffset)
119 offset[count] = begin + startPos;
120 count++;
122 if (multiChar > 0) {
123 dst[count] = multiChar;
124 if (useOffset)
125 offset[count] = begin + startPos;
126 count++;
128 } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) {
129 dst[count] = numberChar[0];
130 if (useOffset)
131 offset[count] = begin + startPos;
132 count++;
134 return str[begin] != NUMBER_ZERO;
135 } else {
136 sal_Bool printPower = sal_False;
137 // sal_Int16 last = 0;
138 for (sal_Int16 i = 1; i <= number->exponentCount; i++) {
139 sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]);
140 if (tmp > 0) {
141 printPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count,
142 (i == number->exponentCount ? -1 : i), offset, useOffset, startPos, number, numberChar);
143 begin += tmp;
144 len -= tmp;
147 if (printPower) {
148 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
149 dst[count-1] == numberChar[0])
150 count--;
151 if (multiChar > 0) {
152 dst[count] = multiChar;
153 if (useOffset)
154 offset[count] = begin + startPos;
155 count++;
158 return printPower;
162 OUString SAL_CALL AsciiToNative( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
163 Sequence< sal_Int32 >& offset, sal_Bool useOffset, Number* number ) throw(RuntimeException)
165 OUString aRet;
167 sal_Int32 strLen = inStr.getLength() - startPos;
168 sal_Unicode *numberChar = NumberChar[number->number];
170 if (nCount > strLen)
171 nCount = strLen;
173 if (nCount > 0)
175 const sal_Unicode *str = inStr.getStr() + startPos;
176 sal_Unicode *newStr = new sal_Unicode[nCount * 2 + 1];
177 sal_Unicode *srcStr = new sal_Unicode[nCount + 1]; // for keeping number without comma
178 sal_Int32 i, len = 0, count = 0;
180 if (useOffset)
181 offset.realloc( nCount * 2 );
182 sal_Bool doDecimal = sal_False;
184 for (i = 0; i <= nCount; i++)
186 if (i < nCount && isNumber(str[i])) {
187 if (doDecimal) {
188 newStr[count] = numberChar[str[i] - NUMBER_ZERO];
189 if (useOffset)
190 offset[count] = i + startPos;
191 count++;
193 else
194 srcStr[len++] = str[i];
195 } else {
196 if (len > 0) {
197 if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1]))
198 continue; // skip comma inside number string
199 sal_Bool notZero = sal_False;
200 for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0];
201 end <= len; begin = end, end += number->multiplierExponent[0]) {
202 if (end == 0) continue;
203 sal_Int32 _count = count;
204 notZero |= AsciiToNative_numberMaker(srcStr, begin, end - begin, newStr, count,
205 end == len ? -1 : 0, offset, useOffset, i - len + startPos, number, numberChar);
206 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
207 newStr[count-1] == numberChar[0])
208 count--;
209 if (notZero && _count == count) {
210 if (end != len) {
211 newStr[count] = number->multiplierChar[0];
212 if (useOffset)
213 offset[count] = i - len + startPos;
214 count++;
218 if (! notZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) {
219 newStr[count] = numberChar[0];
220 if (useOffset)
221 offset[count] = i - len + startPos;
222 count++;
224 len = 0;
226 if (i < nCount) {
227 if ((doDecimal = (!doDecimal && isDecimal(str[i]) && i < nCount-1 && isNumber(str[i+1]))) != sal_False)
228 newStr[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]);
229 else if (isMinus(str[i]) && i < nCount-1 && isNumber(str[i+1]))
230 newStr[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]);
231 else if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1]))
232 newStr[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]);
233 else
234 newStr[count] = str[i];
235 if (useOffset)
236 offset[count] = i + startPos;
237 count++;
242 delete[] srcStr;
244 if (useOffset)
245 offset.realloc(count);
246 aRet = OUString(newStr, count);
247 delete[] newStr;
249 return aRet;
251 static void SAL_CALL NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str,
252 sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, sal_Bool useOffset,
253 OUString& numberChar, OUString& multiplierChar)
255 sal_Int16 curr = 0, num = 0, end = 0, shift = 0;
256 while (++i < nCount) {
257 if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) {
258 if (num > 0)
259 break;
260 num = curr % 10;
261 } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) {
262 curr = MultiplierExponent_7_CJK[curr % ExponentCount_7_CJK];
263 if (prev > curr && num == 0) num = 1; // One may be omitted in informal format
264 shift = end = 0;
265 if (curr >= max)
266 max = curr;
267 else if (curr > prev)
268 shift = max - curr;
269 else
270 end = curr;
271 while (end++ < prev) {
272 dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
273 if (useOffset)
274 offset[count] = i;
275 count++;
277 if (shift) {
278 count -= max;
279 for (sal_Int16 j = 0; j < shift; j++, count++) {
280 dst[count] = dst[count + curr];
281 if (useOffset)
282 offset[count] = offset[count + curr];
284 max = curr;
286 NativeToAscii_numberMaker(max, curr, str, i, nCount, dst,
287 count, offset, useOffset, numberChar, multiplierChar);
288 return;
289 } else
290 break;
292 while (end++ < prev) {
293 dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
294 if (useOffset)
295 offset[count] = i - 1;
296 count++;
300 static OUString SAL_CALL NativeToAscii(const OUString& inStr,
301 sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset, sal_Bool useOffset ) throw(RuntimeException)
303 OUString aRet;
305 sal_Int32 strLen = inStr.getLength() - startPos;
307 if (nCount > strLen)
308 nCount = strLen;
310 if (nCount > 0) {
311 const sal_Unicode *str = inStr.getStr() + startPos;
312 sal_Unicode *newStr = new sal_Unicode[nCount * MultiplierExponent_7_CJK[0] + 2];
313 if (useOffset)
314 offset.realloc( nCount * MultiplierExponent_7_CJK[0] + 1 );
315 sal_Int32 count = 0, index;
316 sal_Int32 i;
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);
325 for ( i = 0; i < nCount; i++) {
326 if ((index = multiplierChar.indexOf(str[i])) >= 0) {
327 if (count == 0 || !isNumber(newStr[count-1])) { // add 1 in front of multiplier
328 newStr[count] = NUMBER_ONE;
329 if (useOffset)
330 offset[count] = i;
331 count++;
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, count, offset, useOffset,
337 numberChar, multiplierChar);
338 } else {
339 if ((index = numberChar.indexOf(str[i])) >= 0)
340 newStr[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[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[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[count] = MinusChar[NumberChar_HalfWidth];
357 else
358 newStr[count] = str[i];
359 if (useOffset)
360 offset[count] = i;
361 count++;
365 if (useOffset) {
366 offset.realloc(count);
367 for (i = 0; i < count; i++)
368 offset[i] += startPos;
370 aRet = OUString(newStr, count);
371 delete[] newStr;
373 return aRet;
376 static Number natnum4[4] = {
377 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0,
378 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
379 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0,
380 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
381 { NumberChar_Modern_ja, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67,
382 ExponentCount_7_CJK, MultiplierExponent_7_CJK },
383 { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ZERO,
384 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
387 static Number natnum5[4] = {
388 { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], 0,
389 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
390 { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], 0,
391 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
392 { NumberChar_Traditional_ja, MultiplierChar_7_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE_67,
393 ExponentCount_7_CJK, MultiplierExponent_7_CJK },
394 { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ZERO,
395 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
398 static Number natnum6[4] = {
399 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0,
400 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
401 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0,
402 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
403 { NumberChar_FullWidth, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67,
404 ExponentCount_7_CJK, MultiplierExponent_7_CJK },
405 { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO,
406 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
409 static Number natnum7[4] = {
410 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], NUMBER_OMIT_ALL,
411 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
412 { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], NUMBER_OMIT_ALL,
413 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
414 { NumberChar_Modern_ja, MultiplierChar_2_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE,
415 ExponentCount_2_CJK, MultiplierExponent_2_CJK },
416 { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ALL,
417 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
420 static Number natnum8[4] = {
421 { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], NUMBER_OMIT_ALL,
422 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
423 { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL,
424 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
425 { NumberChar_Traditional_ja, MultiplierChar_2_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE,
426 ExponentCount_2_CJK, MultiplierExponent_2_CJK },
427 { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL,
428 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
431 static Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO,
432 ExponentCount_6_CJK, MultiplierExponent_6_CJK };
433 static Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL,
434 ExponentCount_6_CJK, MultiplierExponent_6_CJK };
436 //! ATTENTION: Do not change order of elements!
437 //! Append new languages to the end of the list!
438 static const sal_Char *natnum1Locales[] = {
439 "zh_CN",
440 "zh_TW",
441 "ja",
442 "ko",
443 "he",
444 "ar",
445 "th",
446 "hi",
447 "or",
448 "mr",
449 "bn",
450 "pa",
451 "gu",
452 "ta",
453 "te",
454 "kn",
455 "ml",
456 "lo",
457 "bo",
458 "my",
459 "km",
460 "mn",
461 "ne",
462 "dz",
463 "fa"
465 static sal_Int16 nbOfLocale = SAL_N_ELEMENTS(natnum1Locales);
467 //! ATTENTION: Do not change order of elements!
468 //! Number and order must match elements of natnum1Locales!
469 static sal_Int16 natnum1[] = {
470 NumberChar_Lower_zh,
471 NumberChar_Lower_zh,
472 NumberChar_Modern_ja,
473 NumberChar_Lower_ko,
474 NumberChar_he,
475 NumberChar_Indic_ar,
476 NumberChar_th,
477 NumberChar_hi,
478 NumberChar_or,
479 NumberChar_mr,
480 NumberChar_bn,
481 NumberChar_pa,
482 NumberChar_gu,
483 NumberChar_ta,
484 NumberChar_te,
485 NumberChar_kn,
486 NumberChar_ml,
487 NumberChar_lo,
488 NumberChar_bo,
489 NumberChar_my,
490 NumberChar_km,
491 NumberChar_mn,
492 NumberChar_ne,
493 NumberChar_dz,
494 NumberChar_EastIndic_ar
496 static sal_Int16 sizeof_natnum1 = SAL_N_ELEMENTS(natnum1);
498 //! ATTENTION: Do not change order of elements!
499 //! Order must match first elements of natnum1Locales!
500 static sal_Int16 natnum2[] = {
501 NumberChar_Upper_zh,
502 NumberChar_Upper_zh_TW,
503 NumberChar_Traditional_ja,
504 NumberChar_Upper_ko,
505 NumberChar_he
507 static sal_Int16 sizeof_natnum2 = SAL_N_ELEMENTS(natnum2);
509 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2)
511 static sal_Int16 SAL_CALL getLanguageNumber( const Locale& rLocale)
513 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
514 if (isLang("zh")) return MsLangId::isTraditionalChinese(rLocale) ? 1 : 0;
516 for (sal_Int16 i = 2; i < nbOfLocale; i++)
517 if (isLang(natnum1Locales[i]))
518 return i;
520 return -1;
523 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
524 sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) throw (RuntimeException)
526 Number *number = 0;
527 sal_Int16 num = -1;
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;
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;
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);
597 else
598 return aNumberString;
601 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
602 sal_Int16 nNativeNumberMode) throw (RuntimeException)
604 Sequence< sal_Int32 > offset;
605 return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, offset);
608 sal_Unicode SAL_CALL NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw(com::sun::star::uno::RuntimeException)
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;
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;
639 return inChar;
642 sal_Bool SAL_CALL NativeNumberSupplier::isValidNatNum( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException)
644 sal_Int16 langnum = getLanguageNumber(rLocale);
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
666 return sal_False;
669 NativeNumberXmlAttributes SAL_CALL NativeNumberSupplier::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException)
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" };
676 sal_Int16 number = NumberChar_HalfWidth, type = attShort;
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;
733 return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1),
734 OUString::createFromAscii(attType[type]));
737 static sal_Bool natNumIn(sal_Int16 num, sal_Int16 natnum[], sal_Int16 len)
739 for (sal_Int16 i = 0; i < len; i++)
740 if (natnum[i] == num)
741 return sal_True;
742 return sal_False;
745 sal_Int16 SAL_CALL NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr ) throw (RuntimeException)
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);
752 sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) );
754 if ( aAttr.Style == "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 == "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 == "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();
784 return NativeNumberMode::NATNUM0;
788 // Following code generates Hebrew Number,
789 // see numerical system in the Hebrew Numbering System in following link for details,
790 // http://smontagu.org/writings/HebrewNumbers.html
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 }
821 static sal_Int16 nbOfHebrewNumberChar = sizeof(HebrewNumberCharArray)/sizeof(HebrewNumberChar);
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;
829 void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, sal_Bool isLast, sal_Bool useGeresh)
831 sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
833 if (value > 1000) {
834 makeHebrewNumber(value / 1000, output, num != 0, useGeresh);
835 output.appendAscii(" ");
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);
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);
859 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh)
861 sal_Int64 value = 0;
862 sal_Int32 i, count = 0, len = aNumberString.getLength();
863 const sal_Unicode *src = aNumberString.getStr();
865 for (i = 0; i < len; i++) {
866 sal_Unicode ch = src[i];
867 if (isNumber(ch)) {
868 if (++count >= 20) // Number is too long, could not be handled.
869 return aNumberString;
870 value = value * 10 + (ch - NUMBER_ZERO);
872 else if (isSeparator(ch) && count > 0) continue;
873 else if (isMinus(ch) && count == 0) continue;
874 else break;
877 if (value > 0) {
878 OUStringBuffer output(count*2 + 2 + len - i);
880 makeHebrewNumber(value, output, sal_True, useGeresh);
882 if (i < len)
883 output.append(aNumberString.copy(i));
885 return output.makeStringAndClear();
887 else
888 return aNumberString;
891 static const sal_Char* implementationName = "com.sun.star.i18n.NativeNumberSupplier";
893 OUString SAL_CALL NativeNumberSupplier::getImplementationName() throw( RuntimeException )
895 return OUString::createFromAscii( implementationName );
898 sal_Bool SAL_CALL
899 NativeNumberSupplier::supportsService(const OUString& rServiceName) throw( RuntimeException )
901 return rServiceName.compareToAscii(implementationName) == 0;
904 Sequence< OUString > SAL_CALL
905 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException )
907 Sequence< OUString > aRet(1);
908 aRet[0] = OUString::createFromAscii( implementationName );
909 return aRet;
912 } } } }
914 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */