1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
30 using namespace ::com::sun::star::uno
;
31 using namespace ::com::sun::star::lang
;
35 const sal_Unicode
*multiplierChar
;
37 sal_Int16 exponentCount
;
38 const sal_Int16
*multiplierExponent
;
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 )
58 namespace com
{ namespace sun
{ namespace star
{ namespace i18n
{
60 OUString SAL_CALL
getHebrewNativeNumberString(const OUString
& aNumberString
, bool useGeresh
);
62 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
)
65 const sal_Unicode
*src
= inStr
.getStr() + startPos
;
66 rtl_uString
*newStr
= rtl_uString_alloc(nCount
);
68 offset
.realloc(nCount
);
70 for (sal_Int32 i
= 0; i
< nCount
; i
++)
72 sal_Unicode ch
= src
[i
];
74 newStr
->buffer
[i
] = NumberChar
[number
][ ch
- NUMBER_ZERO
];
75 else if (i
+1 < nCount
&& isNumber(src
[i
+1])) {
76 if (i
> 0 && isNumber(src
[i
-1]) && isSeparator(ch
))
77 newStr
->buffer
[i
] = SeparatorChar
[number
] ? SeparatorChar
[number
] : ch
;
79 newStr
->buffer
[i
] = isDecimal(ch
) ? (DecimalChar
[number
] ? DecimalChar
[number
] : ch
) :
80 isMinus(ch
) ? (MinusChar
[number
] ? MinusChar
[number
] : ch
) : ch
;
83 newStr
->buffer
[i
] = ch
;
85 offset
[i
] = startPos
+ i
;
87 return OUString(newStr
, SAL_NO_ACQUIRE
); // take ownership
90 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
)
94 sal_Unicode multiChar
= (multiChar_index
== -1 ? 0 : number
->multiplierChar
[multiChar_index
]);
95 if ( len
<= number
->multiplierExponent
[number
->exponentCount
-1] ) {
96 if (number
->multiplierExponent
[number
->exponentCount
-1] > 1) {
99 for (i
= 0; i
< len
; i
++, begin
++) {
100 if (notZero
|| str
[begin
] != NUMBER_ZERO
) {
101 dst
[count
] = numberChar
[str
[begin
] - NUMBER_ZERO
];
103 offset
[count
] = begin
+ startPos
;
108 if (notZero
&& multiChar
> 0) {
109 dst
[count
] = multiChar
;
111 offset
[count
] = begin
+ startPos
;
115 } else if (str
[begin
] != NUMBER_ZERO
) {
116 if (!(number
->numberFlag
& (multiChar_index
< 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index
))) || str
[begin
] != NUMBER_ONE
) {
117 dst
[count
] = numberChar
[str
[begin
] - NUMBER_ZERO
];
119 offset
[count
] = begin
+ startPos
;
123 dst
[count
] = multiChar
;
125 offset
[count
] = begin
+ startPos
;
128 } else if (!(number
->numberFlag
& NUMBER_OMIT_ZERO
) && count
> 0 && dst
[count
-1] != numberChar
[0]) {
129 dst
[count
] = numberChar
[0];
131 offset
[count
] = begin
+ startPos
;
134 return str
[begin
] != NUMBER_ZERO
;
136 bool printPower
= false;
137 // sal_Int16 last = 0;
138 for (sal_Int16 i
= 1; i
<= number
->exponentCount
; i
++) {
139 sal_Int32 tmp
= len
- (i
== number
->exponentCount
? 0 : number
->multiplierExponent
[i
]);
141 printPower
|= AsciiToNative_numberMaker(str
, begin
, tmp
, dst
, count
,
142 (i
== number
->exponentCount
? -1 : i
), offset
, useOffset
, startPos
, number
, numberChar
);
148 if (count
> 0 && number
->multiplierExponent
[number
->exponentCount
-1] == 1 &&
149 dst
[count
-1] == numberChar
[0])
152 dst
[count
] = multiChar
;
154 offset
[count
] = begin
+ startPos
;
162 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
)
167 sal_Int32 strLen
= inStr
.getLength() - startPos
;
168 const sal_Unicode
*numberChar
= NumberChar
[number
->number
];
175 const sal_Unicode
*str
= inStr
.getStr() + startPos
;
176 boost::scoped_array
<sal_Unicode
> newStr(new sal_Unicode
[nCount
* 2 + 1]);
177 boost::scoped_array
<sal_Unicode
> srcStr(new sal_Unicode
[nCount
+ 1]); // for keeping number without comma
178 sal_Int32 i
, len
= 0, count
= 0;
181 offset
.realloc( nCount
* 2 );
182 bool doDecimal
= false;
184 for (i
= 0; i
<= nCount
; i
++)
186 if (i
< nCount
&& isNumber(str
[i
])) {
188 newStr
[count
] = numberChar
[str
[i
] - NUMBER_ZERO
];
190 offset
[count
] = i
+ startPos
;
194 srcStr
[len
++] = str
[i
];
197 if (i
< nCount
-1 && isSeparator(str
[i
]) && isNumber(str
[i
+1]))
198 continue; // skip comma inside number string
199 bool notZero
= false;
200 for (sal_Int32 begin
= 0, end
= len
% number
->multiplierExponent
[0];
201 end
<= len
; begin
= end
, end
+= number
->multiplierExponent
[0]) {
202 if (end
== 0) continue;
203 sal_Int32 _count
= count
;
204 notZero
|= AsciiToNative_numberMaker(srcStr
.get(), begin
, end
- begin
, newStr
.get(), count
,
205 end
== len
? -1 : 0, offset
, useOffset
, i
- len
+ startPos
, number
, numberChar
);
206 if (count
> 0 && number
->multiplierExponent
[number
->exponentCount
-1] == 1 &&
207 newStr
[count
-1] == numberChar
[0])
209 if (notZero
&& _count
== count
) {
211 newStr
[count
] = number
->multiplierChar
[0];
213 offset
[count
] = i
- len
+ startPos
;
218 if (! notZero
&& ! (number
->numberFlag
& NUMBER_OMIT_ONLY_ZERO
)) {
219 newStr
[count
] = numberChar
[0];
221 offset
[count
] = i
- len
+ startPos
;
227 doDecimal
= (!doDecimal
&& i
< nCount
-1 && isDecimal(str
[i
]) && isNumber(str
[i
+1]));
229 newStr
[count
] = (DecimalChar
[number
->number
] ? DecimalChar
[number
->number
] : str
[i
]);
230 else if (i
< nCount
-1 && isMinus(str
[i
]) && isNumber(str
[i
+1]))
231 newStr
[count
] = (MinusChar
[number
->number
] ? MinusChar
[number
->number
] : str
[i
]);
232 else if (i
< nCount
-1 && isSeparator(str
[i
]) && isNumber(str
[i
+1]))
233 newStr
[count
] = (SeparatorChar
[number
->number
] ? SeparatorChar
[number
->number
] : str
[i
]);
235 newStr
[count
] = str
[i
];
237 offset
[count
] = i
+ startPos
;
244 offset
.realloc(count
);
245 aRet
= OUString(newStr
.get(), count
);
249 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
)
253 sal_Int16 curr
= 0, num
= 0, end
= 0, shift
= 0;
254 while (++i
< nCount
) {
255 if ((curr
= sal::static_int_cast
<sal_Int16
>( numberChar
.indexOf(str
[i
]) )) >= 0) {
259 } else if ((curr
= sal::static_int_cast
<sal_Int16
>( multiplierChar
.indexOf(str
[i
]) )) >= 0) {
260 curr
= MultiplierExponent_7_CJK
[curr
% ExponentCount_7_CJK
];
261 if (prev
> curr
&& num
== 0) num
= 1; // One may be omitted in informal format
265 else if (curr
> prev
)
269 while (end
++ < prev
) {
270 dst
[count
] = NUMBER_ZERO
+ (end
== prev
? num
: 0);
277 for (sal_Int16 j
= 0; j
< shift
; j
++, count
++) {
278 dst
[count
] = dst
[count
+ curr
];
280 offset
[count
] = offset
[count
+ curr
];
284 NativeToAscii_numberMaker(max
, curr
, str
, i
, nCount
, dst
,
285 count
, offset
, useOffset
, numberChar
, multiplierChar
);
290 while (end
++ < prev
) {
291 dst
[count
] = NUMBER_ZERO
+ (end
== prev
? num
: 0);
293 offset
[count
] = i
- 1;
298 static OUString SAL_CALL
NativeToAscii(const OUString
& inStr
,
299 sal_Int32 startPos
, sal_Int32 nCount
, Sequence
< sal_Int32
>& offset
, bool useOffset
) throw(RuntimeException
)
303 sal_Int32 strLen
= inStr
.getLength() - startPos
;
309 const sal_Unicode
*str
= inStr
.getStr() + startPos
;
310 boost::scoped_array
<sal_Unicode
> newStr(new sal_Unicode
[nCount
* MultiplierExponent_7_CJK
[0] + 2]);
312 offset
.realloc( nCount
* MultiplierExponent_7_CJK
[0] + 1 );
313 sal_Int32 count
= 0, index
;
316 OUString numberChar
, multiplierChar
, decimalChar
, minusChar
, separatorChar
;
317 numberChar
= OUString((sal_Unicode
*)NumberChar
, 10*NumberChar_Count
);
318 multiplierChar
= OUString((sal_Unicode
*) MultiplierChar_7_CJK
, ExponentCount_7_CJK
*Multiplier_Count
);
319 decimalChar
= OUString(DecimalChar
, NumberChar_Count
);
320 minusChar
= OUString(MinusChar
, NumberChar_Count
);
321 separatorChar
= OUString(SeparatorChar
, NumberChar_Count
);
323 for ( i
= 0; i
< nCount
; i
++) {
324 if ((index
= multiplierChar
.indexOf(str
[i
])) >= 0) {
325 if (count
== 0 || !isNumber(newStr
[count
-1])) { // add 1 in front of multiplier
326 newStr
[count
] = NUMBER_ONE
;
331 index
= MultiplierExponent_7_CJK
[index
% ExponentCount_7_CJK
];
332 NativeToAscii_numberMaker(
333 sal::static_int_cast
<sal_Int16
>( index
), sal::static_int_cast
<sal_Int16
>( index
),
334 str
, i
, nCount
, newStr
.get(), count
, offset
, useOffset
,
335 numberChar
, multiplierChar
);
337 if ((index
= numberChar
.indexOf(str
[i
])) >= 0)
338 newStr
[count
] = sal::static_int_cast
<sal_Unicode
>( (index
% 10) + NUMBER_ZERO
);
339 else if ((index
= separatorChar
.indexOf(str
[i
])) >= 0 &&
340 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
341 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
342 newStr
[count
] = SeparatorChar
[NumberChar_HalfWidth
];
343 else if ((index
= decimalChar
.indexOf(str
[i
])) >= 0 &&
344 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
345 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 newStr
[count
] = DecimalChar
[NumberChar_HalfWidth
];
349 else if ((index
= minusChar
.indexOf(str
[i
])) >= 0 &&
350 (i
< nCount
-1 && (numberChar
.indexOf(str
[i
+1]) >= 0 ||
351 multiplierChar
.indexOf(str
[i
+1]) >= 0)))
352 // Only when minus is followed by numbers,
353 // it will be convert to ASCII minus sign
354 newStr
[count
] = MinusChar
[NumberChar_HalfWidth
];
356 newStr
[count
] = str
[i
];
364 offset
.realloc(count
);
365 for (i
= 0; i
< count
; i
++)
366 offset
[i
] += startPos
;
368 aRet
= OUString(newStr
.get(), count
);
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
},
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
},
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
},
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
},
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
},
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
};
433 //! ATTENTION: Do not change order of elements!
434 //! Append new languages to the end of the list!
435 static const sal_Char
*natnum1Locales
[] = {
462 static sal_Int16 nbOfLocale
= SAL_N_ELEMENTS(natnum1Locales
);
464 //! ATTENTION: Do not change order of elements!
465 //! Number and order must match elements of natnum1Locales!
466 static const sal_Int16 natnum1
[] = {
469 NumberChar_Modern_ja
,
491 NumberChar_EastIndic_ar
493 static const sal_Int16 sizeof_natnum1
= SAL_N_ELEMENTS(natnum1
);
495 //! ATTENTION: Do not change order of elements!
496 //! Order must match first elements of natnum1Locales!
497 static const sal_Int16 natnum2
[] = {
499 NumberChar_Upper_zh_TW
,
500 NumberChar_Traditional_ja
,
504 static const sal_Int16 sizeof_natnum2
= SAL_N_ELEMENTS(natnum2
);
506 #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2)
508 static sal_Int16 SAL_CALL
getLanguageNumber( const Locale
& rLocale
)
510 // return zh_TW for TW, HK and MO, return zh_CN for other zh locales.
511 if (isLang("zh")) return MsLangId::isTraditionalChinese(rLocale
) ? 1 : 0;
513 for (sal_Int16 i
= 2; i
< nbOfLocale
; i
++)
514 if (isLang(natnum1Locales
[i
]))
520 OUString SAL_CALL
NativeNumberSupplier::getNativeNumberString(const OUString
& aNumberString
, const Locale
& rLocale
,
521 sal_Int16 nNativeNumberMode
, Sequence
< sal_Int32
>& offset
) throw (RuntimeException
)
523 const Number
*number
= 0;
526 if (isValidNatNum(rLocale
, nNativeNumberMode
)) {
527 sal_Int16 langnum
= getLanguageNumber(rLocale
);
528 switch (nNativeNumberMode
) {
529 case NativeNumberMode::NATNUM0
: // Ascii
530 return NativeToAscii(aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
);
531 case NativeNumberMode::NATNUM1
: // Char, Lower
532 num
= natnum1
[langnum
];
534 case NativeNumberMode::NATNUM2
: // Char, Upper
535 num
= natnum2
[langnum
];
537 case NativeNumberMode::NATNUM3
: // Char, FullWidth
538 num
= NumberChar_FullWidth
;
540 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
541 number
= &natnum4
[langnum
];
543 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
544 number
= &natnum5
[langnum
];
546 case NativeNumberMode::NATNUM6
: // Text, FullWidth
547 number
= &natnum6
[langnum
];
549 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
550 number
= &natnum7
[langnum
];
552 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
553 number
= &natnum8
[langnum
];
555 case NativeNumberMode::NATNUM9
: // Char, Hangul
556 num
= NumberChar_Hangul_ko
;
558 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
561 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
569 if (number
|| num
>= 0) {
570 if (!aLocale
.Language
.equals(rLocale
.Language
) ||
571 !aLocale
.Country
.equals(rLocale
.Country
) ||
572 !aLocale
.Variant
.equals(rLocale
.Variant
)) {
573 LocaleDataItem item
= LocaleDataImpl().getLocaleItem( rLocale
);
575 DecimalChar
[NumberChar_HalfWidth
]=item
.decimalSeparator
.toChar();
576 if (DecimalChar
[NumberChar_HalfWidth
] > 0x7E || DecimalChar
[NumberChar_HalfWidth
] < 0x21)
577 DecimalChar
[NumberChar_FullWidth
]=0xFF0E;
579 DecimalChar
[NumberChar_FullWidth
]=DecimalChar
[NumberChar_HalfWidth
]+0xFEE0;
580 SeparatorChar
[NumberChar_HalfWidth
]=item
.thousandSeparator
.toChar();
581 if (SeparatorChar
[NumberChar_HalfWidth
] > 0x7E || SeparatorChar
[NumberChar_HalfWidth
] < 0x21)
582 SeparatorChar
[NumberChar_FullWidth
]=0xFF0C;
584 SeparatorChar
[NumberChar_FullWidth
]=SeparatorChar
[NumberChar_HalfWidth
]+0xFEE0;
587 return AsciiToNative( aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
, number
);
588 else if (num
== NumberChar_he
)
589 return getHebrewNativeNumberString(aNumberString
,
590 nNativeNumberMode
== NativeNumberMode::NATNUM2
);
592 return AsciiToNativeChar(aNumberString
, 0, aNumberString
.getLength(), offset
, useOffset
, num
);
595 return aNumberString
;
598 OUString SAL_CALL
NativeNumberSupplier::getNativeNumberString(const OUString
& aNumberString
, const Locale
& rLocale
,
599 sal_Int16 nNativeNumberMode
) throw (RuntimeException
, std::exception
)
601 Sequence
< sal_Int32
> offset
;
602 return getNativeNumberString(aNumberString
, rLocale
, nNativeNumberMode
, offset
);
605 sal_Unicode SAL_CALL
NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar
, const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw(com::sun::star::uno::RuntimeException
)
607 if (nNativeNumberMode
== NativeNumberMode::NATNUM0
) { // Ascii
608 for (sal_Int16 i
= 0; i
< NumberChar_Count
; i
++)
609 for (sal_Int16 j
= 0; j
< 10; j
++)
610 if (inChar
== NumberChar
[i
][j
])
614 else if (isNumber(inChar
) && isValidNatNum(rLocale
, nNativeNumberMode
)) {
615 sal_Int16 langnum
= getLanguageNumber(rLocale
);
616 switch (nNativeNumberMode
) {
617 case NativeNumberMode::NATNUM1
: // Char, Lower
618 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
619 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
620 return NumberChar
[natnum1
[langnum
]][inChar
- NUMBER_ZERO
];
621 case NativeNumberMode::NATNUM2
: // Char, Upper
622 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
623 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
624 return NumberChar
[natnum2
[langnum
]][inChar
- NUMBER_ZERO
];
625 case NativeNumberMode::NATNUM3
: // Char, FullWidth
626 case NativeNumberMode::NATNUM6
: // Text, FullWidth
627 return NumberChar
[NumberChar_FullWidth
][inChar
- NUMBER_ZERO
];
628 case NativeNumberMode::NATNUM9
: // Char, Hangul
629 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
630 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
631 return NumberChar
[NumberChar_Hangul_ko
][inChar
- NUMBER_ZERO
];
639 sal_Bool SAL_CALL
NativeNumberSupplier::isValidNatNum( const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw (RuntimeException
, std::exception
)
641 sal_Int16 langnum
= getLanguageNumber(rLocale
);
643 switch (nNativeNumberMode
) {
644 case NativeNumberMode::NATNUM0
: // Ascii
645 case NativeNumberMode::NATNUM3
: // Char, FullWidth
647 case NativeNumberMode::NATNUM1
: // Char, Lower
648 return (langnum
>= 0);
649 case NativeNumberMode::NATNUM2
: // Char, Upper
650 if (langnum
== 4) // Hebrew numbering
652 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
653 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
654 case NativeNumberMode::NATNUM6
: // Text, FullWidth
655 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
656 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
657 return (langnum
>= 0 && langnum
< 4); // CJK numbering
658 case NativeNumberMode::NATNUM9
: // Char, Hangul
659 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
660 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
661 return (langnum
== 3); // Korean numbering
666 NativeNumberXmlAttributes SAL_CALL
NativeNumberSupplier::convertToXmlAttributes( const Locale
& rLocale
, sal_Int16 nNativeNumberMode
) throw (RuntimeException
, std::exception
)
668 static const sal_Int16 attShort
= 0;
669 static const sal_Int16 attMedium
= 1;
670 static const sal_Int16 attLong
= 2;
671 static const sal_Char
*attType
[] = { "short", "medium", "long" };
673 sal_Int16 number
= NumberChar_HalfWidth
, type
= attShort
;
675 if (isValidNatNum(rLocale
, nNativeNumberMode
)) {
676 sal_Int16 langnum
= getLanguageNumber(rLocale
);
677 switch (nNativeNumberMode
) {
678 case NativeNumberMode::NATNUM0
: // Ascii
679 number
= NumberChar_HalfWidth
;
682 case NativeNumberMode::NATNUM1
: // Char, Lower
683 number
= natnum1
[langnum
];
686 case NativeNumberMode::NATNUM2
: // Char, Upper
687 number
= natnum2
[langnum
];
688 type
= number
== NumberChar_he
? attMedium
: attShort
;
690 case NativeNumberMode::NATNUM3
: // Char, FullWidth
691 number
= NumberChar_FullWidth
;
694 case NativeNumberMode::NATNUM4
: // Text, Lower, Long
695 number
= natnum1
[langnum
];
698 case NativeNumberMode::NATNUM5
: // Text, Upper, Long
699 number
= natnum2
[langnum
];
702 case NativeNumberMode::NATNUM6
: // Text, FullWidth
703 number
= NumberChar_FullWidth
;
706 case NativeNumberMode::NATNUM7
: // Text. Lower, Short
707 number
= natnum1
[langnum
];
710 case NativeNumberMode::NATNUM8
: // Text, Upper, Short
711 number
= natnum2
[langnum
];
714 case NativeNumberMode::NATNUM9
: // Char, Hangul
715 number
= NumberChar_Hangul_ko
;
718 case NativeNumberMode::NATNUM10
: // Text, Hangul, Long
719 number
= NumberChar_Hangul_ko
;
722 case NativeNumberMode::NATNUM11
: // Text, Hangul, Short
723 number
= NumberChar_Hangul_ko
;
730 return NativeNumberXmlAttributes(rLocale
, OUString(&NumberChar
[number
][1], 1),
731 OUString::createFromAscii(attType
[type
]));
734 static bool natNumIn(sal_Int16 num
, const sal_Int16 natnum
[], sal_Int16 len
)
736 for (sal_Int16 i
= 0; i
< len
; i
++)
737 if (natnum
[i
] == num
)
742 sal_Int16 SAL_CALL
NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes
& aAttr
) throw (RuntimeException
, std::exception
)
744 sal_Unicode numberChar
[NumberChar_Count
];
745 for (sal_Int16 i
= 0; i
< NumberChar_Count
; i
++)
746 numberChar
[i
] = NumberChar
[i
][1];
747 OUString
number(numberChar
, NumberChar_Count
);
749 sal_Int16 num
= sal::static_int_cast
<sal_Int16
>( number
.indexOf(aAttr
.Format
) );
751 if ( aAttr
.Style
== "short" ) {
752 if (num
== NumberChar_FullWidth
)
753 return NativeNumberMode::NATNUM3
;
754 else if (num
== NumberChar_Hangul_ko
)
755 return NativeNumberMode::NATNUM9
;
756 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
757 return NativeNumberMode::NATNUM1
;
758 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
759 return NativeNumberMode::NATNUM2
;
760 } else if ( aAttr
.Style
== "medium" ) {
761 if (num
== NumberChar_Hangul_ko
)
762 return NativeNumberMode::NATNUM11
;
763 else if (num
== NumberChar_he
)
764 return NativeNumberMode::NATNUM2
;
765 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
766 return NativeNumberMode::NATNUM7
;
767 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
768 return NativeNumberMode::NATNUM8
;
769 } else if ( aAttr
.Style
== "long" ) {
770 if (num
== NumberChar_FullWidth
)
771 return NativeNumberMode::NATNUM6
;
772 else if (num
== NumberChar_Hangul_ko
)
773 return NativeNumberMode::NATNUM10
;
774 else if (natNumIn(num
, natnum1
, sizeof_natnum1
))
775 return NativeNumberMode::NATNUM4
;
776 else if (natNumIn(num
, natnum2
, sizeof_natnum2
))
777 return NativeNumberMode::NATNUM5
;
779 throw RuntimeException();
781 return NativeNumberMode::NATNUM0
;
785 // Following code generates Hebrew Number,
786 // see numerical system in the Hebrew Numbering System in following link for details,
787 // http://smontagu.org/writings/HebrewNumbers.html
789 struct HebrewNumberChar
{
792 } HebrewNumberCharArray
[] = {
818 static sal_Int16 nbOfHebrewNumberChar
= sizeof(HebrewNumberCharArray
)/sizeof(HebrewNumberChar
);
820 static sal_Unicode thousand
[] = {0x05d0, 0x05dc, 0x05e3, 0x0};
821 static sal_Unicode thousands
[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0};
822 static sal_Unicode thousands_last
[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0};
823 static sal_Unicode geresh
= 0x05f3;
824 static sal_Unicode gershayim
= 0x05f4;
826 void makeHebrewNumber(sal_Int64 value
, OUStringBuffer
& output
, bool isLast
, bool useGeresh
)
828 sal_Int16 num
= sal::static_int_cast
<sal_Int16
>(value
% 1000);
831 makeHebrewNumber(value
/ 1000, output
, num
!= 0, useGeresh
);
832 output
.appendAscii(" ");
835 output
.append(value
== 1000 ? thousand
: isLast
? thousands_last
: thousands
);
837 sal_Int16 nbOfChar
= 0;
838 for (sal_Int32 j
= 0; num
> 0 && j
< nbOfHebrewNumberChar
; j
++) {
839 if (num
- HebrewNumberCharArray
[j
].value
>= 0) {
841 if (num
== 15 || num
== 16) // substitution for 15 and 16
843 num
= sal::static_int_cast
<sal_Int16
>( num
- HebrewNumberCharArray
[j
].value
);
844 output
.append(HebrewNumberCharArray
[j
].code
);
848 if (nbOfChar
> 1) // a number is written as more than one character
849 output
.insert(output
.getLength() - 1, gershayim
);
850 else if (nbOfChar
== 1) // a number is written as a single character
851 output
.append(geresh
);
856 OUString SAL_CALL
getHebrewNativeNumberString(const OUString
& aNumberString
, bool useGeresh
)
859 sal_Int32 i
, count
= 0, len
= aNumberString
.getLength();
860 const sal_Unicode
*src
= aNumberString
.getStr();
862 for (i
= 0; i
< len
; i
++) {
863 sal_Unicode ch
= src
[i
];
865 if (++count
>= 20) // Number is too long, could not be handled.
866 return aNumberString
;
867 value
= value
* 10 + (ch
- NUMBER_ZERO
);
869 else if (isSeparator(ch
) && count
> 0) continue;
870 else if (isMinus(ch
) && count
== 0) continue;
875 OUStringBuffer
output(count
*2 + 2 + len
- i
);
877 makeHebrewNumber(value
, output
, true, useGeresh
);
880 output
.append(aNumberString
.copy(i
));
882 return output
.makeStringAndClear();
885 return aNumberString
;
888 static const sal_Char
* implementationName
= "com.sun.star.i18n.NativeNumberSupplier";
890 OUString SAL_CALL
NativeNumberSupplier::getImplementationName() throw( RuntimeException
, std::exception
)
892 return OUString::createFromAscii( implementationName
);
896 NativeNumberSupplier::supportsService(const OUString
& rServiceName
) throw( RuntimeException
, std::exception
)
898 return cppu::supportsService(this, rServiceName
);
901 Sequence
< OUString
> SAL_CALL
902 NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException
, std::exception
)
904 Sequence
< OUString
> aRet(1);
905 aRet
[0] = OUString::createFromAscii( implementationName
);
911 extern "C" SAL_DLLPUBLIC_EXPORT
css::uno::XInterface
* SAL_CALL
912 com_sun_star_i18n_NativeNumberSupplier_get_implementation(
913 css::uno::XComponentContext
*,
914 css::uno::Sequence
<css::uno::Any
> const &)
916 return cppu::acquire(new css::i18n::NativeNumberSupplier());
919 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */