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