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