Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <i18nlangtag/mslangid.hxx>
21 : #include <rtl/ustrbuf.hxx>
22 : #include <sal/macros.h>
23 : #include <nativenumbersupplier.hxx>
24 : #include <localedata.hxx>
25 : #include <data/numberchar.h>
26 : #include <comphelper/string.hxx>
27 : #include <cppuhelper/supportsservice.hxx>
28 :
29 : using namespace ::com::sun::star::uno;
30 : using namespace ::com::sun::star::lang;
31 :
32 : typedef struct {
33 : sal_Int16 number;
34 : const sal_Unicode *multiplierChar;
35 : sal_Int16 numberFlag;
36 : sal_Int16 exponentCount;
37 : const sal_Int16 *multiplierExponent;
38 : } Number;
39 :
40 :
41 : #define NUMBER_OMIT_ZERO (1 << 0)
42 : #define NUMBER_OMIT_ONLY_ZERO (1 << 1)
43 : #define NUMBER_OMIT_ONE_1 (1 << 2)
44 : #define NUMBER_OMIT_ONE_2 (1 << 3)
45 : #define NUMBER_OMIT_ONE_3 (1 << 4)
46 : #define NUMBER_OMIT_ONE_4 (1 << 5)
47 : #define NUMBER_OMIT_ONE_5 (1 << 6)
48 : #define NUMBER_OMIT_ONE_6 (1 << 7)
49 : #define NUMBER_OMIT_ONE_7 (1 << 8)
50 : #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)
51 : #define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit))
52 : #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO )
53 : #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE )
54 : #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7)
55 : #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 )
56 :
57 : namespace com { namespace sun { namespace star { namespace i18n {
58 :
59 : OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh);
60 :
61 0 : OUString SAL_CALL AsciiToNativeChar( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
62 : Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int16 number ) throw(RuntimeException)
63 : {
64 0 : const sal_Unicode *src = inStr.getStr() + startPos;
65 0 : rtl_uString *newStr = rtl_uString_alloc(nCount);
66 0 : if (useOffset)
67 0 : offset.realloc(nCount);
68 :
69 0 : for (sal_Int32 i = 0; i < nCount; i++)
70 : {
71 0 : sal_Unicode ch = src[i];
72 0 : if (isNumber(ch))
73 0 : newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ];
74 0 : else if (i+1 < nCount && isNumber(src[i+1])) {
75 0 : if (i > 0 && isNumber(src[i-1]) && isSeparator(ch))
76 0 : newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch;
77 : else
78 0 : newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) :
79 0 : isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch;
80 : }
81 : else
82 0 : newStr->buffer[i] = ch;
83 0 : if (useOffset)
84 0 : offset[i] = startPos + i;
85 : }
86 0 : return OUString(newStr, SAL_NO_ACQUIRE); // take ownership
87 : }
88 :
89 0 : sal_Bool SAL_CALL AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len,
90 : sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int32 startPos,
91 : const Number *number, const sal_Unicode* numberChar)
92 : {
93 0 : sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]);
94 0 : if ( len <= number->multiplierExponent[number->exponentCount-1] ) {
95 0 : if (number->multiplierExponent[number->exponentCount-1] > 1) {
96 : sal_Int16 i;
97 0 : sal_Bool notZero = false;
98 0 : for (i = 0; i < len; i++, begin++) {
99 0 : if (notZero || str[begin] != NUMBER_ZERO) {
100 0 : dst[count] = numberChar[str[begin] - NUMBER_ZERO];
101 0 : if (useOffset)
102 0 : offset[count] = begin + startPos;
103 0 : count++;
104 0 : notZero = sal_True;
105 : }
106 : }
107 0 : if (notZero && multiChar > 0) {
108 0 : dst[count] = multiChar;
109 0 : if (useOffset)
110 0 : offset[count] = begin + startPos;
111 0 : count++;
112 : }
113 0 : return notZero;
114 0 : } else if (str[begin] != NUMBER_ZERO) {
115 0 : if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) {
116 0 : dst[count] = numberChar[str[begin] - NUMBER_ZERO];
117 0 : if (useOffset)
118 0 : offset[count] = begin + startPos;
119 0 : count++;
120 : }
121 0 : if (multiChar > 0) {
122 0 : dst[count] = multiChar;
123 0 : if (useOffset)
124 0 : offset[count] = begin + startPos;
125 0 : count++;
126 : }
127 0 : } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) {
128 0 : dst[count] = numberChar[0];
129 0 : if (useOffset)
130 0 : offset[count] = begin + startPos;
131 0 : count++;
132 : }
133 0 : return str[begin] != NUMBER_ZERO;
134 : } else {
135 0 : sal_Bool printPower = sal_False;
136 : // sal_Int16 last = 0;
137 0 : for (sal_Int16 i = 1; i <= number->exponentCount; i++) {
138 0 : sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]);
139 0 : if (tmp > 0) {
140 : printPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count,
141 0 : (i == number->exponentCount ? -1 : i), offset, useOffset, startPos, number, numberChar);
142 0 : begin += tmp;
143 0 : len -= tmp;
144 : }
145 : }
146 0 : if (printPower) {
147 0 : if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
148 0 : dst[count-1] == numberChar[0])
149 0 : count--;
150 0 : if (multiChar > 0) {
151 0 : dst[count] = multiChar;
152 0 : if (useOffset)
153 0 : offset[count] = begin + startPos;
154 0 : count++;
155 : }
156 : }
157 0 : return printPower;
158 : }
159 : }
160 :
161 0 : OUString SAL_CALL AsciiToNative( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount,
162 : Sequence< sal_Int32 >& offset, sal_Bool useOffset, const Number* number ) throw(RuntimeException)
163 : {
164 0 : OUString aRet;
165 :
166 0 : sal_Int32 strLen = inStr.getLength() - startPos;
167 0 : const sal_Unicode *numberChar = NumberChar[number->number];
168 :
169 0 : if (nCount > strLen)
170 0 : nCount = strLen;
171 :
172 0 : if (nCount > 0)
173 : {
174 0 : const sal_Unicode *str = inStr.getStr() + startPos;
175 0 : sal_Unicode *newStr = new sal_Unicode[nCount * 2 + 1];
176 0 : sal_Unicode *srcStr = new sal_Unicode[nCount + 1]; // for keeping number without comma
177 0 : sal_Int32 i, len = 0, count = 0;
178 :
179 0 : if (useOffset)
180 0 : offset.realloc( nCount * 2 );
181 0 : sal_Bool doDecimal = sal_False;
182 :
183 0 : for (i = 0; i <= nCount; i++)
184 : {
185 0 : if (i < nCount && isNumber(str[i])) {
186 0 : if (doDecimal) {
187 0 : newStr[count] = numberChar[str[i] - NUMBER_ZERO];
188 0 : if (useOffset)
189 0 : offset[count] = i + startPos;
190 0 : count++;
191 : }
192 : else
193 0 : srcStr[len++] = str[i];
194 : } else {
195 0 : if (len > 0) {
196 0 : if (i < nCount-1 && isSeparator(str[i]) && isNumber(str[i+1]))
197 0 : continue; // skip comma inside number string
198 0 : sal_Bool notZero = sal_False;
199 0 : for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0];
200 0 : end <= len; begin = end, end += number->multiplierExponent[0]) {
201 0 : if (end == 0) continue;
202 0 : sal_Int32 _count = count;
203 : notZero |= AsciiToNative_numberMaker(srcStr, begin, end - begin, newStr, count,
204 0 : end == len ? -1 : 0, offset, useOffset, i - len + startPos, number, numberChar);
205 0 : if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 &&
206 0 : newStr[count-1] == numberChar[0])
207 0 : count--;
208 0 : if (notZero && _count == count) {
209 0 : if (end != len) {
210 0 : newStr[count] = number->multiplierChar[0];
211 0 : if (useOffset)
212 0 : offset[count] = i - len + startPos;
213 0 : count++;
214 : }
215 : }
216 : }
217 0 : if (! notZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) {
218 0 : newStr[count] = numberChar[0];
219 0 : if (useOffset)
220 0 : offset[count] = i - len + startPos;
221 0 : count++;
222 : }
223 0 : len = 0;
224 : }
225 0 : if (i < nCount) {
226 0 : if ((doDecimal = (!doDecimal && i < nCount-1 && isDecimal(str[i]) && isNumber(str[i+1]))) != sal_False)
227 0 : newStr[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]);
228 0 : else if (i < nCount-1 && isMinus(str[i]) && isNumber(str[i+1]))
229 0 : newStr[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]);
230 0 : else if (i < nCount-1 && isSeparator(str[i]) && isNumber(str[i+1]))
231 0 : newStr[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]);
232 : else
233 0 : newStr[count] = str[i];
234 0 : if (useOffset)
235 0 : offset[count] = i + startPos;
236 0 : count++;
237 : }
238 : }
239 : }
240 :
241 0 : delete[] srcStr;
242 :
243 0 : if (useOffset)
244 0 : offset.realloc(count);
245 0 : aRet = OUString(newStr, count);
246 0 : delete[] newStr;
247 : }
248 0 : return aRet;
249 : }
250 0 : static void SAL_CALL NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str,
251 : sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, sal_Bool useOffset,
252 : OUString& numberChar, OUString& multiplierChar)
253 : {
254 0 : sal_Int16 curr = 0, num = 0, end = 0, shift = 0;
255 0 : while (++i < nCount) {
256 0 : if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) {
257 0 : if (num > 0)
258 0 : break;
259 0 : num = curr % 10;
260 0 : } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) {
261 0 : curr = MultiplierExponent_7_CJK[curr % ExponentCount_7_CJK];
262 0 : if (prev > curr && num == 0) num = 1; // One may be omitted in informal format
263 0 : shift = end = 0;
264 0 : if (curr >= max)
265 0 : max = curr;
266 0 : else if (curr > prev)
267 0 : shift = max - curr;
268 : else
269 0 : end = curr;
270 0 : while (end++ < prev) {
271 0 : dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
272 0 : if (useOffset)
273 0 : offset[count] = i;
274 0 : count++;
275 : }
276 0 : if (shift) {
277 0 : count -= max;
278 0 : for (sal_Int16 j = 0; j < shift; j++, count++) {
279 0 : dst[count] = dst[count + curr];
280 0 : if (useOffset)
281 0 : offset[count] = offset[count + curr];
282 : }
283 0 : max = curr;
284 : }
285 : NativeToAscii_numberMaker(max, curr, str, i, nCount, dst,
286 0 : count, offset, useOffset, numberChar, multiplierChar);
287 0 : return;
288 : } else
289 0 : break;
290 : }
291 0 : while (end++ < prev) {
292 0 : dst[count] = NUMBER_ZERO + (end == prev ? num : 0);
293 0 : if (useOffset)
294 0 : offset[count] = i - 1;
295 0 : count++;
296 : }
297 : }
298 :
299 0 : static OUString SAL_CALL NativeToAscii(const OUString& inStr,
300 : sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset, sal_Bool useOffset ) throw(RuntimeException)
301 : {
302 0 : OUString aRet;
303 :
304 0 : sal_Int32 strLen = inStr.getLength() - startPos;
305 :
306 0 : if (nCount > strLen)
307 0 : nCount = strLen;
308 :
309 0 : if (nCount > 0) {
310 0 : const sal_Unicode *str = inStr.getStr() + startPos;
311 0 : sal_Unicode *newStr = new sal_Unicode[nCount * MultiplierExponent_7_CJK[0] + 2];
312 0 : if (useOffset)
313 0 : offset.realloc( nCount * MultiplierExponent_7_CJK[0] + 1 );
314 0 : sal_Int32 count = 0, index;
315 : sal_Int32 i;
316 :
317 0 : OUString numberChar, multiplierChar, decimalChar, minusChar, separatorChar;
318 0 : numberChar = OUString((sal_Unicode*)NumberChar, 10*NumberChar_Count);
319 0 : multiplierChar = OUString((sal_Unicode*) MultiplierChar_7_CJK, ExponentCount_7_CJK*Multiplier_Count);
320 0 : decimalChar = OUString(DecimalChar, NumberChar_Count);
321 0 : minusChar = OUString(MinusChar, NumberChar_Count);
322 0 : separatorChar = OUString(SeparatorChar, NumberChar_Count);
323 :
324 0 : for ( i = 0; i < nCount; i++) {
325 0 : if ((index = multiplierChar.indexOf(str[i])) >= 0) {
326 0 : if (count == 0 || !isNumber(newStr[count-1])) { // add 1 in front of multiplier
327 0 : newStr[count] = NUMBER_ONE;
328 0 : if (useOffset)
329 0 : offset[count] = i;
330 0 : count++;
331 : }
332 0 : index = MultiplierExponent_7_CJK[index % ExponentCount_7_CJK];
333 : NativeToAscii_numberMaker(
334 0 : sal::static_int_cast<sal_Int16>( index ), sal::static_int_cast<sal_Int16>( index ),
335 : str, i, nCount, newStr, count, offset, useOffset,
336 0 : numberChar, multiplierChar);
337 : } else {
338 0 : if ((index = numberChar.indexOf(str[i])) >= 0)
339 0 : newStr[count] = sal::static_int_cast<sal_Unicode>( (index % 10) + NUMBER_ZERO );
340 0 : else if ((index = separatorChar.indexOf(str[i])) >= 0 &&
341 0 : (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
342 0 : multiplierChar.indexOf(str[i+1]) >= 0)))
343 0 : newStr[count] = SeparatorChar[NumberChar_HalfWidth];
344 0 : else if ((index = decimalChar.indexOf(str[i])) >= 0 &&
345 0 : (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
346 0 : multiplierChar.indexOf(str[i+1]) >= 0)))
347 : // Only when decimal point is followed by numbers,
348 : // it will be convert to ASCII decimal point
349 0 : newStr[count] = DecimalChar[NumberChar_HalfWidth];
350 0 : else if ((index = minusChar.indexOf(str[i])) >= 0 &&
351 0 : (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 ||
352 0 : multiplierChar.indexOf(str[i+1]) >= 0)))
353 : // Only when minus is followed by numbers,
354 : // it will be convert to ASCII minus sign
355 0 : newStr[count] = MinusChar[NumberChar_HalfWidth];
356 : else
357 0 : newStr[count] = str[i];
358 0 : if (useOffset)
359 0 : offset[count] = i;
360 0 : count++;
361 : }
362 : }
363 :
364 0 : if (useOffset) {
365 0 : offset.realloc(count);
366 0 : for (i = 0; i < count; i++)
367 0 : offset[i] += startPos;
368 : }
369 0 : aRet = OUString(newStr, count);
370 0 : delete[] newStr;
371 : }
372 0 : return aRet;
373 : }
374 :
375 : static const 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 const 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 const 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 const 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 const 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 const Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO,
431 : ExponentCount_6_CJK, MultiplierExponent_6_CJK };
432 : static const 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 = SAL_N_ELEMENTS(natnum1Locales);
465 :
466 : //! ATTENTION: Do not change order of elements!
467 : //! Number and order must match elements of natnum1Locales!
468 : static const 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 const sal_Int16 sizeof_natnum1 = SAL_N_ELEMENTS(natnum1);
496 :
497 : //! ATTENTION: Do not change order of elements!
498 : //! Order must match first elements of natnum1Locales!
499 : static const 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 const sal_Int16 sizeof_natnum2 = SAL_N_ELEMENTS(natnum2);
507 :
508 : #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2)
509 :
510 0 : static sal_Int16 SAL_CALL getLanguageNumber( const Locale& rLocale)
511 : {
512 : // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
513 0 : if (isLang("zh")) return MsLangId::isTraditionalChinese(rLocale) ? 1 : 0;
514 :
515 0 : for (sal_Int16 i = 2; i < nbOfLocale; i++)
516 0 : if (isLang(natnum1Locales[i]))
517 0 : return i;
518 :
519 0 : return -1;
520 : }
521 :
522 0 : OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
523 : sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) throw (RuntimeException)
524 : {
525 0 : const Number *number = 0;
526 0 : sal_Int16 num = -1;
527 :
528 0 : if (isValidNatNum(rLocale, nNativeNumberMode)) {
529 0 : sal_Int16 langnum = getLanguageNumber(rLocale);
530 0 : switch (nNativeNumberMode) {
531 : case NativeNumberMode::NATNUM0: // Ascii
532 0 : return NativeToAscii(aNumberString, 0, aNumberString.getLength(), offset, useOffset);
533 : case NativeNumberMode::NATNUM1: // Char, Lower
534 0 : num = natnum1[langnum];
535 0 : break;
536 : case NativeNumberMode::NATNUM2: // Char, Upper
537 0 : num = natnum2[langnum];
538 0 : break;
539 : case NativeNumberMode::NATNUM3: // Char, FullWidth
540 0 : num = NumberChar_FullWidth;
541 0 : break;
542 : case NativeNumberMode::NATNUM4: // Text, Lower, Long
543 0 : number = &natnum4[langnum];
544 0 : break;
545 : case NativeNumberMode::NATNUM5: // Text, Upper, Long
546 0 : number = &natnum5[langnum];
547 0 : break;
548 : case NativeNumberMode::NATNUM6: // Text, FullWidth
549 0 : number = &natnum6[langnum];
550 0 : break;
551 : case NativeNumberMode::NATNUM7: // Text. Lower, Short
552 0 : number = &natnum7[langnum];
553 0 : break;
554 : case NativeNumberMode::NATNUM8: // Text, Upper, Short
555 0 : number = &natnum8[langnum];
556 0 : break;
557 : case NativeNumberMode::NATNUM9: // Char, Hangul
558 0 : num = NumberChar_Hangul_ko;
559 0 : break;
560 : case NativeNumberMode::NATNUM10: // Text, Hangul, Long
561 0 : number = &natnum10;
562 0 : break;
563 : case NativeNumberMode::NATNUM11: // Text, Hangul, Short
564 0 : number = &natnum11;
565 0 : break;
566 : default:
567 0 : break;
568 : }
569 : }
570 :
571 0 : if (number || num >= 0) {
572 0 : if (!aLocale.Language.equals(rLocale.Language) ||
573 0 : !aLocale.Country.equals(rLocale.Country) ||
574 0 : !aLocale.Variant.equals(rLocale.Variant)) {
575 0 : LocaleDataItem item = LocaleDataImpl().getLocaleItem( rLocale );
576 0 : aLocale = rLocale;
577 0 : DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar();
578 0 : if (DecimalChar[NumberChar_HalfWidth] > 0x7E || DecimalChar[NumberChar_HalfWidth] < 0x21)
579 0 : DecimalChar[NumberChar_FullWidth]=0xFF0E;
580 : else
581 0 : DecimalChar[NumberChar_FullWidth]=DecimalChar[NumberChar_HalfWidth]+0xFEE0;
582 0 : SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar();
583 0 : if (SeparatorChar[NumberChar_HalfWidth] > 0x7E || SeparatorChar[NumberChar_HalfWidth] < 0x21)
584 0 : SeparatorChar[NumberChar_FullWidth]=0xFF0C;
585 : else
586 0 : SeparatorChar[NumberChar_FullWidth]=SeparatorChar[NumberChar_HalfWidth]+0xFEE0;
587 : }
588 0 : if (number)
589 0 : return AsciiToNative( aNumberString, 0, aNumberString.getLength(), offset, useOffset, number );
590 0 : else if (num == NumberChar_he)
591 : return getHebrewNativeNumberString(aNumberString,
592 0 : nNativeNumberMode == NativeNumberMode::NATNUM2);
593 : else
594 0 : return AsciiToNativeChar(aNumberString, 0, aNumberString.getLength(), offset, useOffset, num);
595 : }
596 : else
597 0 : return aNumberString;
598 : }
599 :
600 0 : OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale,
601 : sal_Int16 nNativeNumberMode) throw (RuntimeException, std::exception)
602 : {
603 0 : Sequence< sal_Int32 > offset;
604 0 : return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, offset);
605 : }
606 :
607 0 : sal_Unicode SAL_CALL NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw(com::sun::star::uno::RuntimeException)
608 : {
609 0 : if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii
610 0 : for (sal_Int16 i = 0; i < NumberChar_Count; i++)
611 0 : for (sal_Int16 j = 0; j < 10; j++)
612 0 : if (inChar == NumberChar[i][j])
613 0 : return j;
614 0 : return inChar;
615 : }
616 0 : else if (isNumber(inChar) && isValidNatNum(rLocale, nNativeNumberMode)) {
617 0 : sal_Int16 langnum = getLanguageNumber(rLocale);
618 0 : switch (nNativeNumberMode) {
619 : case NativeNumberMode::NATNUM1: // Char, Lower
620 : case NativeNumberMode::NATNUM4: // Text, Lower, Long
621 : case NativeNumberMode::NATNUM7: // Text. Lower, Short
622 0 : return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO];
623 : case NativeNumberMode::NATNUM2: // Char, Upper
624 : case NativeNumberMode::NATNUM5: // Text, Upper, Long
625 : case NativeNumberMode::NATNUM8: // Text, Upper, Short
626 0 : return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO];
627 : case NativeNumberMode::NATNUM3: // Char, FullWidth
628 : case NativeNumberMode::NATNUM6: // Text, FullWidth
629 0 : return NumberChar[NumberChar_FullWidth][inChar - NUMBER_ZERO];
630 : case NativeNumberMode::NATNUM9: // Char, Hangul
631 : case NativeNumberMode::NATNUM10: // Text, Hangul, Long
632 : case NativeNumberMode::NATNUM11: // Text, Hangul, Short
633 0 : return NumberChar[NumberChar_Hangul_ko][inChar - NUMBER_ZERO];
634 : default:
635 0 : break;
636 : }
637 : }
638 0 : return inChar;
639 : }
640 :
641 0 : sal_Bool SAL_CALL NativeNumberSupplier::isValidNatNum( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException, std::exception)
642 : {
643 0 : sal_Int16 langnum = getLanguageNumber(rLocale);
644 :
645 0 : switch (nNativeNumberMode) {
646 : case NativeNumberMode::NATNUM0: // Ascii
647 : case NativeNumberMode::NATNUM3: // Char, FullWidth
648 0 : return sal_True;
649 : case NativeNumberMode::NATNUM1: // Char, Lower
650 0 : return (langnum >= 0);
651 : case NativeNumberMode::NATNUM2: // Char, Upper
652 0 : if (langnum == 4) // Hebrew numbering
653 0 : return sal_True;
654 : case NativeNumberMode::NATNUM4: // Text, Lower, Long
655 : case NativeNumberMode::NATNUM5: // Text, Upper, Long
656 : case NativeNumberMode::NATNUM6: // Text, FullWidth
657 : case NativeNumberMode::NATNUM7: // Text. Lower, Short
658 : case NativeNumberMode::NATNUM8: // Text, Upper, Short
659 0 : return (langnum >= 0 && langnum < 4); // CJK numbering
660 : case NativeNumberMode::NATNUM9: // Char, Hangul
661 : case NativeNumberMode::NATNUM10: // Text, Hangul, Long
662 : case NativeNumberMode::NATNUM11: // Text, Hangul, Short
663 0 : return (langnum == 3); // Korean numbering
664 : }
665 0 : return sal_False;
666 : }
667 :
668 0 : NativeNumberXmlAttributes SAL_CALL NativeNumberSupplier::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException, std::exception)
669 : {
670 : static const sal_Int16 attShort = 0;
671 : static const sal_Int16 attMedium = 1;
672 : static const sal_Int16 attLong = 2;
673 : static const sal_Char *attType[] = { "short", "medium", "long" };
674 :
675 0 : sal_Int16 number = NumberChar_HalfWidth, type = attShort;
676 :
677 0 : if (isValidNatNum(rLocale, nNativeNumberMode)) {
678 0 : sal_Int16 langnum = getLanguageNumber(rLocale);
679 0 : switch (nNativeNumberMode) {
680 : case NativeNumberMode::NATNUM0: // Ascii
681 0 : number = NumberChar_HalfWidth;
682 0 : type = attShort;
683 0 : break;
684 : case NativeNumberMode::NATNUM1: // Char, Lower
685 0 : number = natnum1[langnum];
686 0 : type = attShort;
687 0 : break;
688 : case NativeNumberMode::NATNUM2: // Char, Upper
689 0 : number = natnum2[langnum];
690 0 : type = number == NumberChar_he ? attMedium : attShort;
691 0 : break;
692 : case NativeNumberMode::NATNUM3: // Char, FullWidth
693 0 : number = NumberChar_FullWidth;
694 0 : type = attShort;
695 0 : break;
696 : case NativeNumberMode::NATNUM4: // Text, Lower, Long
697 0 : number = natnum1[langnum];
698 0 : type = attLong;
699 0 : break;
700 : case NativeNumberMode::NATNUM5: // Text, Upper, Long
701 0 : number = natnum2[langnum];
702 0 : type = attLong;
703 0 : break;
704 : case NativeNumberMode::NATNUM6: // Text, FullWidth
705 0 : number = NumberChar_FullWidth;
706 0 : type = attLong;
707 0 : break;
708 : case NativeNumberMode::NATNUM7: // Text. Lower, Short
709 0 : number = natnum1[langnum];
710 0 : type = attMedium;
711 0 : break;
712 : case NativeNumberMode::NATNUM8: // Text, Upper, Short
713 0 : number = natnum2[langnum];
714 0 : type = attMedium;
715 0 : break;
716 : case NativeNumberMode::NATNUM9: // Char, Hangul
717 0 : number = NumberChar_Hangul_ko;
718 0 : type = attShort;
719 0 : break;
720 : case NativeNumberMode::NATNUM10: // Text, Hangul, Long
721 0 : number = NumberChar_Hangul_ko;
722 0 : type = attLong;
723 0 : break;
724 : case NativeNumberMode::NATNUM11: // Text, Hangul, Short
725 0 : number = NumberChar_Hangul_ko;
726 0 : type = attMedium;
727 0 : break;
728 : default:
729 0 : break;
730 : }
731 : }
732 0 : return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1),
733 0 : OUString::createFromAscii(attType[type]));
734 : }
735 :
736 0 : static sal_Bool natNumIn(sal_Int16 num, const sal_Int16 natnum[], sal_Int16 len)
737 : {
738 0 : for (sal_Int16 i = 0; i < len; i++)
739 0 : if (natnum[i] == num)
740 0 : return sal_True;
741 0 : return sal_False;
742 : }
743 :
744 0 : sal_Int16 SAL_CALL NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr ) throw (RuntimeException, std::exception)
745 : {
746 : sal_Unicode numberChar[NumberChar_Count];
747 0 : for (sal_Int16 i = 0; i < NumberChar_Count; i++)
748 0 : numberChar[i] = NumberChar[i][1];
749 0 : OUString number(numberChar, NumberChar_Count);
750 :
751 0 : sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) );
752 :
753 0 : if ( aAttr.Style == "short" ) {
754 0 : if (num == NumberChar_FullWidth)
755 0 : return NativeNumberMode::NATNUM3;
756 0 : else if (num == NumberChar_Hangul_ko)
757 0 : return NativeNumberMode::NATNUM9;
758 0 : else if (natNumIn(num, natnum1, sizeof_natnum1))
759 0 : return NativeNumberMode::NATNUM1;
760 0 : else if (natNumIn(num, natnum2, sizeof_natnum2))
761 0 : return NativeNumberMode::NATNUM2;
762 0 : } else if ( aAttr.Style == "medium" ) {
763 0 : if (num == NumberChar_Hangul_ko)
764 0 : return NativeNumberMode::NATNUM11;
765 0 : else if (num == NumberChar_he)
766 0 : return NativeNumberMode::NATNUM2;
767 0 : else if (natNumIn(num, natnum1, sizeof_natnum1))
768 0 : return NativeNumberMode::NATNUM7;
769 0 : else if (natNumIn(num, natnum2, sizeof_natnum2))
770 0 : return NativeNumberMode::NATNUM8;
771 0 : } else if ( aAttr.Style == "long" ) {
772 0 : if (num == NumberChar_FullWidth)
773 0 : return NativeNumberMode::NATNUM6;
774 0 : else if (num == NumberChar_Hangul_ko)
775 0 : return NativeNumberMode::NATNUM10;
776 0 : else if (natNumIn(num, natnum1, sizeof_natnum1))
777 0 : return NativeNumberMode::NATNUM4;
778 0 : else if (natNumIn(num, natnum2, sizeof_natnum2))
779 0 : return NativeNumberMode::NATNUM5;
780 : } else {
781 0 : throw RuntimeException();
782 : }
783 0 : return NativeNumberMode::NATNUM0;
784 : }
785 :
786 :
787 : // Following code generates Hebrew Number,
788 : // see numerical system in the Hebrew Numbering System in following link for details,
789 : // http://smontagu.org/writings/HebrewNumbers.html
790 :
791 : struct HebrewNumberChar {
792 : sal_Unicode code;
793 : sal_Int16 value;
794 : } HebrewNumberCharArray[] = {
795 : { 0x05ea, 400 },
796 : { 0x05ea, 400 },
797 : { 0x05e9, 300 },
798 : { 0x05e8, 200 },
799 : { 0x05e7, 100 },
800 : { 0x05e6, 90 },
801 : { 0x05e4, 80 },
802 : { 0x05e2, 70 },
803 : { 0x05e1, 60 },
804 : { 0x05e0, 50 },
805 : { 0x05de, 40 },
806 : { 0x05dc, 30 },
807 : { 0x05db, 20 },
808 : { 0x05d9, 10 },
809 : { 0x05d8, 9 },
810 : { 0x05d7, 8 },
811 : { 0x05d6, 7 },
812 : { 0x05d5, 6 },
813 : { 0x05d4, 5 },
814 : { 0x05d3, 4 },
815 : { 0x05d2, 3 },
816 : { 0x05d1, 2 },
817 : { 0x05d0, 1 }
818 : };
819 :
820 : static sal_Int16 nbOfHebrewNumberChar = sizeof(HebrewNumberCharArray)/sizeof(HebrewNumberChar);
821 :
822 : static sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
823 : static sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
824 : static sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
825 : static sal_Unicode geresh = 0x05f3;
826 : static sal_Unicode gershayim = 0x05f4;
827 :
828 0 : void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, sal_Bool isLast, sal_Bool useGeresh)
829 : {
830 0 : sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000);
831 :
832 0 : if (value > 1000) {
833 0 : makeHebrewNumber(value / 1000, output, num != 0, useGeresh);
834 0 : output.appendAscii(" ");
835 : }
836 0 : if (num == 0) {
837 0 : output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands);
838 : } else {
839 0 : sal_Int16 nbOfChar = 0;
840 0 : for (sal_Int32 j = 0; num > 0 && j < nbOfHebrewNumberChar; j++) {
841 0 : if (num - HebrewNumberCharArray[j].value >= 0) {
842 0 : nbOfChar++;
843 0 : if (num == 15 || num == 16) // substitution for 15 and 16
844 0 : j++;
845 0 : num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value );
846 0 : output.append(HebrewNumberCharArray[j].code);
847 : }
848 : }
849 0 : if (useGeresh) {
850 0 : if (nbOfChar > 1) // a number is written as more than one character
851 0 : output.insert(output.getLength() - 1, gershayim);
852 0 : else if (nbOfChar == 1) // a number is written as a single character
853 0 : output.append(geresh);
854 : }
855 : }
856 0 : }
857 :
858 0 : OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh)
859 : {
860 0 : sal_Int64 value = 0;
861 0 : sal_Int32 i, count = 0, len = aNumberString.getLength();
862 0 : const sal_Unicode *src = aNumberString.getStr();
863 :
864 0 : for (i = 0; i < len; i++) {
865 0 : sal_Unicode ch = src[i];
866 0 : if (isNumber(ch)) {
867 0 : if (++count >= 20) // Number is too long, could not be handled.
868 0 : return aNumberString;
869 0 : value = value * 10 + (ch - NUMBER_ZERO);
870 : }
871 0 : else if (isSeparator(ch) && count > 0) continue;
872 0 : else if (isMinus(ch) && count == 0) continue;
873 : else break;
874 : }
875 :
876 0 : if (value > 0) {
877 0 : OUStringBuffer output(count*2 + 2 + len - i);
878 :
879 0 : makeHebrewNumber(value, output, sal_True, useGeresh);
880 :
881 0 : if (i < len)
882 0 : output.append(aNumberString.copy(i));
883 :
884 0 : return output.makeStringAndClear();
885 : }
886 : else
887 0 : return aNumberString;
888 : }
889 :
890 : static const sal_Char* implementationName = "com.sun.star.i18n.NativeNumberSupplier";
891 :
892 0 : OUString SAL_CALL NativeNumberSupplier::getImplementationName() throw( RuntimeException, std::exception )
893 : {
894 0 : return OUString::createFromAscii( implementationName );
895 : }
896 :
897 : sal_Bool SAL_CALL
898 0 : NativeNumberSupplier::supportsService(const OUString& rServiceName) throw( RuntimeException, std::exception )
899 : {
900 0 : return cppu::supportsService(this, rServiceName);
901 : }
902 :
903 : Sequence< OUString > SAL_CALL
904 0 : NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException, std::exception )
905 : {
906 0 : Sequence< OUString > aRet(1);
907 0 : aRet[0] = OUString::createFromAscii( implementationName );
908 0 : return aRet;
909 : }
910 :
911 : } } } }
912 :
913 : extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * SAL_CALL
914 0 : com_sun_star_i18n_NativeNumberSupplier_get_implementation(
915 : css::uno::XComponentContext *,
916 : css::uno::Sequence<css::uno::Any> const &)
917 : {
918 0 : return cppu::acquire(new css::i18n::NativeNumberSupplier());
919 : }
920 :
921 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|