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