1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_i18npool.hxx"
26 
27 #include <rtl/ustrbuf.hxx>
28 #include <nativenumbersupplier.hxx>
29 #include <localedata.hxx>
30 #include <data/numberchar.h>
31 #include <i18nutil/x_rtl_ustring.h>
32 
33 using namespace ::com::sun::star::uno;
34 using namespace ::com::sun::star::lang;
35 using namespace ::com::sun::star::lang;
36 using namespace ::rtl;
37 
38 
39 typedef struct {
40     sal_Int16 number;
41     sal_Unicode *multiplierChar;
42     sal_Int16 numberFlag;
43     sal_Int16 exponentCount;
44     sal_Int16 *multiplierExponent;
45 } Number;
46 
47 
48 #define NUMBER_OMIT_ZERO (1 << 0)
49 #define NUMBER_OMIT_ONLY_ZERO  (1 << 1)
50 #define NUMBER_OMIT_ONE_1  (1 << 2)
51 #define NUMBER_OMIT_ONE_2  (1 << 3)
52 #define NUMBER_OMIT_ONE_3  (1 << 4)
53 #define NUMBER_OMIT_ONE_4  (1 << 5)
54 #define NUMBER_OMIT_ONE_5  (1 << 6)
55 #define NUMBER_OMIT_ONE_6  (1 << 7)
56 #define NUMBER_OMIT_ONE_7  (1 << 8)
57 #define NUMBER_OMIT_ONE  (NUMBER_OMIT_ONE_1|NUMBER_OMIT_ONE_2|NUMBER_OMIT_ONE_3|NUMBER_OMIT_ONE_4|NUMBER_OMIT_ONE_5|NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
58 #define NUMBER_OMIT_ONE_CHECK(bit)  (1 << (2 + bit))
59 #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
60 #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
61 #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
62 #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
63 
64 
65 #define MAX_SAL_UINT32  0xFFFFFFFF
66 #define MAX_VALUE       (MAX_SAL_UINT32 - 9) / 10
67 
68 namespace com { namespace sun { namespace star { namespace i18n {
69 
70 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh);
71 
72 OUString SAL_CALL AsciiToNativeChar( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
73         Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int16 number ) throw(RuntimeException)
74 {
75         const sal_Unicode *src = inStr.getStr() + startPos;
76         rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount);
77         if (useOffset)
78             offset.realloc(nCount);
79 
80         for (sal_Int32 i = 0; i < nCount; i++) {
81             sal_Unicode ch = src[i];
82             if (isNumber(ch))
83                 newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ];
84             else if (i+1 < nCount && isNumber(src[i+1])) {
85                 if (i > 0 && isNumber(src[i-1]) && isSeparator(ch))
86                     newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch;
87                 else
88                     newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) :
89                             isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch;
90             }
91             else
92                 newStr->buffer[i] = ch;
93             if (useOffset)
94                 offset[i] = startPos + i;
95         }
96         return OUString(newStr->buffer, nCount);
97 }
98 
99 sal_Bool SAL_CALL AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len,
100         sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int32 startPos,
101  Number *number, sal_Unicode* numberChar)
102 {
103         sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]);
104         if ( len <= number->multiplierExponent[number->exponentCount-1] ) {
105             if (number->multiplierExponent[number->exponentCount-1] > 1) {
106                 sal_Int16 i;
107                 sal_Bool notZero = false;
108                 for (i = 0; i < len; i++, begin++) {
109                     if (notZero || str[begin] != NUMBER_ZERO) {
110                         dst[count] = numberChar[str[begin] - NUMBER_ZERO];
111                         if (useOffset)
112                             offset[count] = begin + startPos;
113                         count++;
114                         notZero = sal_True;
115                     }
116                 }
117                 if (notZero && multiChar > 0) {
118                     dst[count] = multiChar;
119                     if (useOffset)
120                         offset[count] = begin + startPos;
121                     count++;
122                 }
123                 return notZero;
124             } else if (str[begin] != NUMBER_ZERO) {
125                 if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) {
126                     dst[count] = numberChar[str[begin] - NUMBER_ZERO];
127                     if (useOffset)
128                         offset[count] = begin + startPos;
129                     count++;
130                 }
131                 if (multiChar > 0) {
132                     dst[count] = multiChar;
133                     if (useOffset)
134                         offset[count] = begin + startPos;
135                     count++;
136                 }
137             } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) {
138                 dst[count] = numberChar[0];
139                 if (useOffset)
140                     offset[count] = begin + startPos;
141                 count++;
142             }
143             return str[begin] != NUMBER_ZERO;
144         } else {
145             sal_Bool printPower = sal_False;
146             // sal_Int16 last = 0;
147             for (sal_Int16 i = 1; i <= number->exponentCount; i++) {
148                 sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]);
149                 if (tmp > 0) {
150                     printPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count,
151                         (i == number->exponentCount ? -1 : i), offset, useOffset, startPos, number, numberChar);
152                     begin += tmp;
153                     len -= tmp;
154                 }
155             }
156             if (printPower) {
157                 if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
158                             dst[count-1] == numberChar[0])
159                     count--;
160                 if (multiChar > 0) {
161                     dst[count] = multiChar;
162                     if (useOffset)
163                         offset[count] = begin + startPos;
164                     count++;
165                 }
166             }
167             return printPower;
168         }
169 }
170 
171 OUString SAL_CALL AsciiToNative( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
172         Sequence< sal_Int32 >& offset, sal_Bool useOffset, Number* number ) throw(RuntimeException)
173 {
174         sal_Int32 strLen = inStr.getLength() - startPos;
175         sal_Unicode *numberChar = NumberChar[number->number];
176 
177         if (nCount > strLen)
178             nCount = strLen;
179 
180         if (nCount > 0) {
181             const sal_Unicode *str = inStr.getStr() + startPos;
182             rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount * 2);
183             rtl_uString *srcStr = x_rtl_uString_new_WithLength(nCount); // for keeping number without comma
184             sal_Int32 i, len = 0, count = 0;
185 
186             if (useOffset)
187                 offset.realloc( nCount * 2 );
188             sal_Bool doDecimal = sal_False;
189 
190             for (i = 0; i <= nCount; i++) {
191                 if (i < nCount && isNumber(str[i])) {
192                     if (doDecimal) {
193                         newStr->buffer[count] = numberChar[str[i] - NUMBER_ZERO];
194                         if (useOffset)
195                             offset[count] = i + startPos;
196                         count++;
197                     }
198                     else
199                         srcStr->buffer[len++] = str[i];
200                 } else {
201                     if (len > 0) {
202                         if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1]))
203                             continue; // skip comma inside number string
204                         sal_Bool notZero = sal_False;
205                         for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0];
206                                 end <= len; begin = end, end += number->multiplierExponent[0]) {
207                             if (end == 0) continue;
208                             sal_Int32 _count = count;
209                             notZero |= AsciiToNative_numberMaker(srcStr->buffer, begin, end - begin, newStr->buffer, count,
210                                         end == len ? -1 : 0, offset, useOffset, i - len + startPos, number, numberChar);
211                             if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
212                                         newStr->buffer[count-1] == numberChar[0])
213                                 count--;
214                             if (notZero && _count == count) {
215                                 if (end != len) {
216                                     newStr->buffer[count] = number->multiplierChar[0];
217                                     if (useOffset)
218                                         offset[count] = i - len + startPos;
219                                     count++;
220                                 }
221                             }
222                         }
223                         if (! notZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) {
224                             newStr->buffer[count] = numberChar[0];
225                             if (useOffset)
226                                 offset[count] = i - len + startPos;
227                             count++;
228                         }
229                         len = 0;
230                     }
231                     if (i < nCount) {
232                         if ((doDecimal = (!doDecimal && isDecimal(str[i]) && i < nCount-1 && isNumber(str[i+1]))) != sal_False)
233                             newStr->buffer[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]);
234                         else if (isMinus(str[i]) && i < nCount-1 && isNumber(str[i+1]))
235                             newStr->buffer[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]);
236                         else if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1]))
237                             newStr->buffer[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]);
238                         else
239                             newStr->buffer[count] = str[i];
240                         if (useOffset)
241                             offset[count] = i + startPos;
242                         count++;
243                     }
244                 }
245             }
246 
247             if (useOffset)
248                 offset.realloc(count);
249             return OUString(newStr->buffer, count);
250         }
251         return OUString();
252 }
253 static void SAL_CALL NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str,
254         sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, sal_Bool useOffset,
255         OUString& numberChar, OUString& multiplierChar)
256 {
257         sal_Int16 curr = 0, num = 0, end = 0, shift = 0;
258         while (++i < nCount) {
259             if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) {
260                 if (num > 0)
261                     break;
262                 num = curr % 10;
263             } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) {
264                 curr = MultiplierExponent_7_CJK[curr % ExponentCount_7_CJK];
265                 if (prev > curr && num == 0) num = 1; // One may be omitted in informal format
266                 shift = end = 0;
267                 if (curr >= max)
268                     max = curr;
269                 else if (curr > prev)
270                     shift = max - curr;
271                 else
272                     end = curr;
273                 while (end++ < prev) {
274                     dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
275                     if (useOffset)
276                         offset[count] = i;
277                     count++;
278                 }
279                 if (shift) {
280                     count -= max;
281                     for (sal_Int16 j = 0; j < shift; j++, count++) {
282                         dst[count] = dst[count + curr];
283                         if (useOffset)
284                             offset[count] = offset[count + curr];
285                     }
286                     max = curr;
287                 }
288                 NativeToAscii_numberMaker(max, curr, str, i, nCount, dst,
289                         count, offset, useOffset, numberChar, multiplierChar);
290                 return;
291             } else
292                 break;
293         }
294         while (end++ < prev) {
295             dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
296             if (useOffset)
297                 offset[count] = i - 1;
298             count++;
299         }
300 }
301 
302 static OUString SAL_CALL NativeToAscii(const OUString& inStr,
303         sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset, sal_Bool useOffset ) throw(RuntimeException)
304 {
305         sal_Int32 strLen = inStr.getLength() - startPos;
306 
307         if (nCount > strLen)
308             nCount = strLen;
309 
310         if (nCount > 0) {
311             const sal_Unicode *str = inStr.getStr() + startPos;
312             rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount * MultiplierExponent_7_CJK[0] + 1);
313             if (useOffset)
314                 offset.realloc( nCount * MultiplierExponent_7_CJK[0] + 1 );
315             sal_Int32 count = 0, index;
316             sal_Int32 i;
317 
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);
324 
325             for ( i = 0; i < nCount; i++) {
326                 if ((index = multiplierChar.indexOf(str[i])) >= 0) {
327                     if (count == 0 || !isNumber(newStr->buffer[count-1])) { // add 1 in front of multiplier
328                         newStr->buffer[count] = NUMBER_ONE;
329                         if (useOffset)
330                             offset[count] = i;
331                         count++;
332                     }
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->buffer, count, offset, useOffset,
337                                 numberChar, multiplierChar);
338                 } else {
339                     if ((index = numberChar.indexOf(str[i])) >= 0)
340                         newStr->buffer[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->buffer[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->buffer[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->buffer[count] = MinusChar[NumberChar_HalfWidth];
357                     else
358                         newStr->buffer[count] = str[i];
359                     if (useOffset)
360                         offset[count] = i;
361                     count++;
362                 }
363             }
364 
365             if (useOffset) {
366                 offset.realloc(count);
367                 for (i = 0; i < count; i++)
368                     offset[i] += startPos;
369             }
370             return OUString(newStr->buffer, count);
371         }
372         return OUString();
373 }
374 
375 static Number natnum4[4] = {
376         { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0,
377                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
378         { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0,
379                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
380         { NumberChar_Modern_ja, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67,
381                 ExponentCount_7_CJK, MultiplierExponent_7_CJK },
382         { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ZERO,
383                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
384 };
385 
386 static Number natnum5[4] = {
387         { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], 0,
388                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
389         { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], 0,
390                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
391         { NumberChar_Traditional_ja, MultiplierChar_7_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE_67,
392                 ExponentCount_7_CJK, MultiplierExponent_7_CJK },
393         { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ZERO,
394                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
395 };
396 
397 static Number natnum6[4] = {
398         { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0,
399                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
400         { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0,
401                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
402         { NumberChar_FullWidth, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67,
403                 ExponentCount_7_CJK, MultiplierExponent_7_CJK },
404         { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO,
405                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
406 };
407 
408 static Number natnum7[4] = {
409         { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], NUMBER_OMIT_ALL,
410                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
411         { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], NUMBER_OMIT_ALL,
412                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
413         { NumberChar_Modern_ja, MultiplierChar_2_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE,
414                 ExponentCount_2_CJK, MultiplierExponent_2_CJK },
415         { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ALL,
416                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
417 };
418 
419 static Number natnum8[4] = {
420         { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], NUMBER_OMIT_ALL,
421                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
422         { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL,
423                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
424         { NumberChar_Traditional_ja, MultiplierChar_2_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE,
425                 ExponentCount_2_CJK, MultiplierExponent_2_CJK },
426         { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL,
427                 ExponentCount_6_CJK, MultiplierExponent_6_CJK },
428 };
429 
430 static Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO,
431                 ExponentCount_6_CJK, MultiplierExponent_6_CJK };
432 static Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL,
433                 ExponentCount_6_CJK, MultiplierExponent_6_CJK };
434 
435 //! ATTENTION: Do not change order of elements!
436 //! Append new languages to the end of the list!
437 static const sal_Char *natnum1Locales[] = {
438     "zh_CN",
439     "zh_TW",
440     "ja",
441     "ko",
442     "he",
443     "ar",
444     "th",
445     "hi",
446     "or",
447     "mr",
448     "bn",
449     "pa",
450     "gu",
451     "ta",
452     "te",
453     "kn",
454     "ml",
455     "lo",
456     "bo",
457     "my",
458     "km",
459     "mn",
460     "ne",
461     "dz",
462     "fa"
463 };
464 static sal_Int16 nbOfLocale = sizeof(natnum1Locales)/sizeof(natnum1Locales[0]);
465 
466 //! ATTENTION: Do not change order of elements!
467 //! Number and order must match elements of natnum1Locales!
468 static sal_Int16 natnum1[] = {
469     NumberChar_Lower_zh,
470     NumberChar_Lower_zh,
471     NumberChar_Modern_ja,
472     NumberChar_Lower_ko,
473     NumberChar_he,
474     NumberChar_Indic_ar,
475     NumberChar_th,
476     NumberChar_hi,
477     NumberChar_or,
478     NumberChar_mr,
479     NumberChar_bn,
480     NumberChar_pa,
481     NumberChar_gu,
482     NumberChar_ta,
483     NumberChar_te,
484     NumberChar_kn,
485     NumberChar_ml,
486     NumberChar_lo,
487     NumberChar_bo,
488     NumberChar_my,
489     NumberChar_km,
490     NumberChar_mn,
491     NumberChar_ne,
492     NumberChar_dz,
493     NumberChar_EastIndic_ar
494 };
495 static sal_Int16 sizeof_natnum1 = sizeof(natnum1)/sizeof(natnum1[0]);
496 
497 //! ATTENTION: Do not change order of elements!
498 //! Order must match first elements of natnum1Locales!
499 static sal_Int16 natnum2[] = {
500     NumberChar_Upper_zh,
501     NumberChar_Upper_zh_TW,
502     NumberChar_Traditional_ja,
503     NumberChar_Upper_ko,
504     NumberChar_he
505 };
506 static sal_Int16 sizeof_natnum2 = sizeof(natnum2)/sizeof(natnum2[0]);
507 
508 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2)
509 #define isCtry(ctry) rLocale.Country.equalsAsciiL(ctry, 2)
510 
511 static sal_Int16 SAL_CALL getLanguageNumber( const Locale& rLocale)
512 {
513     // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
514     if (isLang("zh")) return (isCtry("TW") || isCtry("HK") || isCtry("MO")) ? 1 : 0;
515 
516     for (sal_Int16 i = 2; i < nbOfLocale; i++)
517         if (isLang(natnum1Locales[i]))
518             return i;
519 
520     return -1;
521 }
522 
523 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
524                 sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) throw (RuntimeException)
525 {
526         Number *number = 0;
527         sal_Int16 num = -1;
528 
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;
569             }
570         }
571 
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;
588             }
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);
596         }
597         else
598             return aNumberString;
599 }
600 
601 OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
602                 sal_Int16 nNativeNumberMode) throw (RuntimeException)
603 {
604     Sequence< sal_Int32 > offset;
605     return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, offset);
606 }
607 
608 sal_Unicode SAL_CALL NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw(com::sun::star::uno::RuntimeException)
609 {
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;
616         }
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;
637             }
638         }
639         return inChar;
640 }
641 
642 sal_Bool SAL_CALL NativeNumberSupplier::isValidNatNum( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException)
643 {
644         sal_Int16 langnum = getLanguageNumber(rLocale);
645 
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
665         }
666         return sal_False;
667 }
668 
669 NativeNumberXmlAttributes SAL_CALL NativeNumberSupplier::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException)
670 {
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" };
675 
676         sal_Int16 number = NumberChar_HalfWidth, type = attShort;
677 
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;
731             }
732         }
733         return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1),
734                                             OUString::createFromAscii(attType[type]));
735 }
736 
737 static sal_Bool natNumIn(sal_Int16 num, sal_Int16 natnum[], sal_Int16 len)
738 {
739         for (sal_Int16 i = 0; i < len; i++)
740             if (natnum[i] == num)
741                 return sal_True;
742         return sal_False;
743 }
744 
745 sal_Int16 SAL_CALL NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr ) throw (RuntimeException)
746 {
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);
751 
752         sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) );
753 
754         if (aAttr.Style.equalsAscii("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.equalsAscii("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.equalsAscii("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();
783         }
784         return NativeNumberMode::NATNUM0;
785 }
786 
787 
788 // Following code generates Hebrew Number,
789 // see numerical system in the Hebrew Numbering System in following link for details,
790 // http://people.netscape.com/smontagu/writings/HebrewNumbers.html
791 
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 }
819 };
820 
821 static sal_Int16 nbOfHebrewNumberChar = sizeof(HebrewNumberCharArray)/sizeof(HebrewNumberChar);
822 
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;
828 
829 void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, sal_Bool isLast, sal_Bool useGeresh)
830 {
831     sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
832 
833     if (value > 1000) {
834         makeHebrewNumber(value / 1000, output, num != 0, useGeresh);
835         output.appendAscii(" ");
836     }
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);
848             }
849         }
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);
855         }
856     }
857 }
858 
859 OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh)
860 {
861     sal_Int64 value = 0;
862     sal_Int32 i, count = 0, len = aNumberString.getLength();
863     const sal_Unicode *src = aNumberString.getStr();
864     sal_Bool neg = sal_False;
865 
866     for (i = 0; i < len; i++) {
867         sal_Unicode ch = src[i];
868         if (isNumber(ch)) {
869             if (++count >= 20) // Number is too long, could not be handled.
870                 return aNumberString;
871             value = value * 10 + (ch - NUMBER_ZERO);
872         }
873         else if (isSeparator(ch) && count > 0) continue;
874         else if (isMinus(ch) && count == 0) neg = sal_True;
875         else break;
876     }
877 
878     if (value > 0) {
879         OUStringBuffer output(count*2 + 2 + len - i);
880 
881         makeHebrewNumber(value, output, sal_True, useGeresh);
882 
883         if (i < len)
884             output.append(aNumberString.copy(i));
885 
886         return output.makeStringAndClear();
887     }
888     else
889         return aNumberString;
890 }
891 
892 static const sal_Char* implementationName = "com.sun.star.i18n.NativeNumberSupplier";
893 
894 OUString SAL_CALL NativeNumberSupplier::getImplementationName() throw( RuntimeException )
895 {
896     return OUString::createFromAscii( implementationName );
897 }
898 
899 sal_Bool SAL_CALL
900 NativeNumberSupplier::supportsService(const OUString& rServiceName) throw( RuntimeException )
901 {
902     return rServiceName.compareToAscii(implementationName) == 0;
903 }
904 
905 Sequence< OUString > SAL_CALL
906 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException )
907 {
908     Sequence< OUString > aRet(1);
909     aRet[0] = OUString::createFromAscii( implementationName );
910     return aRet;
911 }
912 
913 } } } }
914