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