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