| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_i18npool.hxx" |
| |
| #include <rtl/ustrbuf.hxx> |
| #include <nativenumbersupplier.hxx> |
| #include <localedata.hxx> |
| #include <data/numberchar.h> |
| #include <i18nutil/x_rtl_ustring.h> |
| |
| using namespace ::com::sun::star::uno; |
| using namespace ::com::sun::star::lang; |
| using namespace ::com::sun::star::lang; |
| using namespace ::rtl; |
| |
| |
| typedef struct { |
| sal_Int16 number; |
| sal_Unicode *multiplierChar; |
| sal_Int16 numberFlag; |
| sal_Int16 exponentCount; |
| sal_Int16 *multiplierExponent; |
| } Number; |
| |
| |
| #define NUMBER_OMIT_ZERO (1 << 0) |
| #define NUMBER_OMIT_ONLY_ZERO (1 << 1) |
| #define NUMBER_OMIT_ONE_1 (1 << 2) |
| #define NUMBER_OMIT_ONE_2 (1 << 3) |
| #define NUMBER_OMIT_ONE_3 (1 << 4) |
| #define NUMBER_OMIT_ONE_4 (1 << 5) |
| #define NUMBER_OMIT_ONE_5 (1 << 6) |
| #define NUMBER_OMIT_ONE_6 (1 << 7) |
| #define NUMBER_OMIT_ONE_7 (1 << 8) |
| #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) |
| #define NUMBER_OMIT_ONE_CHECK(bit) (1 << (2 + bit)) |
| #define NUMBER_OMIT_ALL ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE|NUMBER_OMIT_ONLY_ZERO ) |
| #define NUMBER_OMIT_ZERO_ONE ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE ) |
| #define NUMBER_OMIT_ONE_67 (NUMBER_OMIT_ONE_6|NUMBER_OMIT_ONE_7) |
| #define NUMBER_OMIT_ZERO_ONE_67 ( NUMBER_OMIT_ZERO|NUMBER_OMIT_ONE_67 ) |
| |
| |
| #define MAX_SAL_UINT32 0xFFFFFFFF |
| #define MAX_VALUE (MAX_SAL_UINT32 - 9) / 10 |
| |
| namespace com { namespace sun { namespace star { namespace i18n { |
| |
| OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh); |
| |
| OUString SAL_CALL AsciiToNativeChar( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount, |
| Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int16 number ) throw(RuntimeException) |
| { |
| const sal_Unicode *src = inStr.getStr() + startPos; |
| rtl_uString *newStr = x_rtl_uString_new_WithLength( nCount ); // defined in x_rtl_ustring.h |
| if (useOffset) |
| offset.realloc(nCount); |
| |
| for (sal_Int32 i = 0; i < nCount; i++) { |
| sal_Unicode ch = src[i]; |
| if (isNumber(ch)) |
| newStr->buffer[i] = NumberChar[number][ ch - NUMBER_ZERO ]; |
| else if (i+1 < nCount && isNumber(src[i+1])) { |
| if (i > 0 && isNumber(src[i-1]) && isSeparator(ch)) |
| newStr->buffer[i] = SeparatorChar[number] ? SeparatorChar[number] : ch; |
| else |
| newStr->buffer[i] = isDecimal(ch) ? (DecimalChar[number] ? DecimalChar[number] : ch) : |
| isMinus(ch) ? (MinusChar[number] ? MinusChar[number] : ch) : ch; |
| } |
| else |
| newStr->buffer[i] = ch; |
| if (useOffset) |
| offset[i] = startPos + i; |
| } |
| return OUString( newStr, SAL_NO_ACQUIRE); // take over ownership of <newStr> |
| } |
| |
| sal_Bool SAL_CALL AsciiToNative_numberMaker(const sal_Unicode *str, sal_Int32 begin, sal_Int32 len, |
| sal_Unicode *dst, sal_Int32& count, sal_Int16 multiChar_index, Sequence< sal_Int32 >& offset, sal_Bool useOffset, sal_Int32 startPos, |
| Number *number, sal_Unicode* numberChar) |
| { |
| sal_Unicode multiChar = (multiChar_index == -1 ? 0 : number->multiplierChar[multiChar_index]); |
| if ( len <= number->multiplierExponent[number->exponentCount-1] ) { |
| if (number->multiplierExponent[number->exponentCount-1] > 1) { |
| sal_Int16 i; |
| sal_Bool notZero = false; |
| for (i = 0; i < len; i++, begin++) { |
| if (notZero || str[begin] != NUMBER_ZERO) { |
| dst[count] = numberChar[str[begin] - NUMBER_ZERO]; |
| if (useOffset) |
| offset[count] = begin + startPos; |
| count++; |
| notZero = sal_True; |
| } |
| } |
| if (notZero && multiChar > 0) { |
| dst[count] = multiChar; |
| if (useOffset) |
| offset[count] = begin + startPos; |
| count++; |
| } |
| return notZero; |
| } else if (str[begin] != NUMBER_ZERO) { |
| if (!(number->numberFlag & (multiChar_index < 0 ? 0 : NUMBER_OMIT_ONE_CHECK(multiChar_index))) || str[begin] != NUMBER_ONE) { |
| dst[count] = numberChar[str[begin] - NUMBER_ZERO]; |
| if (useOffset) |
| offset[count] = begin + startPos; |
| count++; |
| } |
| if (multiChar > 0) { |
| dst[count] = multiChar; |
| if (useOffset) |
| offset[count] = begin + startPos; |
| count++; |
| } |
| } else if (!(number->numberFlag & NUMBER_OMIT_ZERO) && count > 0 && dst[count-1] != numberChar[0]) { |
| dst[count] = numberChar[0]; |
| if (useOffset) |
| offset[count] = begin + startPos; |
| count++; |
| } |
| return str[begin] != NUMBER_ZERO; |
| } else { |
| sal_Bool printPower = sal_False; |
| // sal_Int16 last = 0; |
| for (sal_Int16 i = 1; i <= number->exponentCount; i++) { |
| sal_Int32 tmp = len - (i == number->exponentCount ? 0 : number->multiplierExponent[i]); |
| if (tmp > 0) { |
| printPower |= AsciiToNative_numberMaker(str, begin, tmp, dst, count, |
| (i == number->exponentCount ? -1 : i), offset, useOffset, startPos, number, numberChar); |
| begin += tmp; |
| len -= tmp; |
| } |
| } |
| if (printPower) { |
| if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 && |
| dst[count-1] == numberChar[0]) |
| count--; |
| if (multiChar > 0) { |
| dst[count] = multiChar; |
| if (useOffset) |
| offset[count] = begin + startPos; |
| count++; |
| } |
| } |
| return printPower; |
| } |
| } |
| |
| OUString SAL_CALL AsciiToNative( const OUString& inStr, sal_Int32 startPos, sal_Int32 nCount, |
| Sequence< sal_Int32 >& offset, sal_Bool useOffset, Number* number ) throw(RuntimeException) |
| { |
| sal_Int32 strLen = inStr.getLength() - startPos; |
| sal_Unicode *numberChar = NumberChar[number->number]; |
| |
| if (nCount > strLen) |
| nCount = strLen; |
| |
| if (nCount > 0) { |
| const sal_Unicode *str = inStr.getStr() + startPos; |
| rtl_uString *newStr = x_rtl_uString_new_WithLength(nCount * 2); |
| rtl_uString *srcStr = x_rtl_uString_new_WithLength(nCount); // for keeping number without comma |
| sal_Int32 i, len = 0, count = 0; |
| |
| if (useOffset) |
| offset.realloc( nCount * 2 ); |
| sal_Bool doDecimal = sal_False; |
| |
| for (i = 0; i <= nCount; i++) { |
| if (i < nCount && isNumber(str[i])) { |
| if (doDecimal) { |
| newStr->buffer[count] = numberChar[str[i] - NUMBER_ZERO]; |
| if (useOffset) |
| offset[count] = i + startPos; |
| count++; |
| } |
| else |
| srcStr->buffer[len++] = str[i]; |
| } else { |
| if (len > 0) { |
| if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1])) |
| continue; // skip comma inside number string |
| sal_Bool notZero = sal_False; |
| for (sal_Int32 begin = 0, end = len % number->multiplierExponent[0]; |
| end <= len; begin = end, end += number->multiplierExponent[0]) { |
| if (end == 0) continue; |
| sal_Int32 _count = count; |
| notZero |= AsciiToNative_numberMaker(srcStr->buffer, begin, end - begin, newStr->buffer, count, |
| end == len ? -1 : 0, offset, useOffset, i - len + startPos, number, numberChar); |
| if (count > 0 && number->multiplierExponent[number->exponentCount-1] == 1 && |
| newStr->buffer[count-1] == numberChar[0]) |
| count--; |
| if (notZero && _count == count) { |
| if (end != len) { |
| newStr->buffer[count] = number->multiplierChar[0]; |
| if (useOffset) |
| offset[count] = i - len + startPos; |
| count++; |
| } |
| } |
| } |
| if (! notZero && ! (number->numberFlag & NUMBER_OMIT_ONLY_ZERO)) { |
| newStr->buffer[count] = numberChar[0]; |
| if (useOffset) |
| offset[count] = i - len + startPos; |
| count++; |
| } |
| len = 0; |
| } |
| if (i < nCount) { |
| if ((doDecimal = (!doDecimal && isDecimal(str[i]) && i < nCount-1 && isNumber(str[i+1]))) != sal_False) |
| newStr->buffer[count] = (DecimalChar[number->number] ? DecimalChar[number->number] : str[i]); |
| else if (isMinus(str[i]) && i < nCount-1 && isNumber(str[i+1])) |
| newStr->buffer[count] = (MinusChar[number->number] ? MinusChar[number->number] : str[i]); |
| else if (isSeparator(str[i]) && i < nCount-1 && isNumber(str[i+1])) |
| newStr->buffer[count] = (SeparatorChar[number->number] ? SeparatorChar[number->number] : str[i]); |
| else |
| newStr->buffer[count] = str[i]; |
| if (useOffset) |
| offset[count] = i + startPos; |
| count++; |
| } |
| } |
| } |
| |
| if (useOffset) |
| offset.realloc(count); |
| OUString resultStr( newStr->buffer, count ); |
| x_rtl_uString_release( newStr ); |
| x_rtl_uString_release( srcStr ); |
| return resultStr; |
| } |
| return OUString(); |
| } |
| static void SAL_CALL NativeToAscii_numberMaker(sal_Int16 max, sal_Int16 prev, const sal_Unicode *str, |
| sal_Int32& i, sal_Int32 nCount, sal_Unicode *dst, sal_Int32& count, Sequence< sal_Int32 >& offset, sal_Bool useOffset, |
| OUString& numberChar, OUString& multiplierChar) |
| { |
| sal_Int16 curr = 0, num = 0, end = 0, shift = 0; |
| while (++i < nCount) { |
| if ((curr = sal::static_int_cast<sal_Int16>( numberChar.indexOf(str[i]) )) >= 0) { |
| if (num > 0) |
| break; |
| num = curr % 10; |
| } else if ((curr = sal::static_int_cast<sal_Int16>( multiplierChar.indexOf(str[i]) )) >= 0) { |
| curr = MultiplierExponent_7_CJK[curr % ExponentCount_7_CJK]; |
| if (prev > curr && num == 0) num = 1; // One may be omitted in informal format |
| shift = end = 0; |
| if (curr >= max) |
| max = curr; |
| else if (curr > prev) |
| shift = max - curr; |
| else |
| end = curr; |
| while (end++ < prev) { |
| dst[count] = NUMBER_ZERO + (end == prev ? num : 0); |
| if (useOffset) |
| offset[count] = i; |
| count++; |
| } |
| if (shift) { |
| count -= max; |
| for (sal_Int16 j = 0; j < shift; j++, count++) { |
| dst[count] = dst[count + curr]; |
| if (useOffset) |
| offset[count] = offset[count + curr]; |
| } |
| max = curr; |
| } |
| NativeToAscii_numberMaker(max, curr, str, i, nCount, dst, |
| count, offset, useOffset, numberChar, multiplierChar); |
| return; |
| } else |
| break; |
| } |
| while (end++ < prev) { |
| dst[count] = NUMBER_ZERO + (end == prev ? num : 0); |
| if (useOffset) |
| offset[count] = i - 1; |
| count++; |
| } |
| } |
| |
| static OUString SAL_CALL NativeToAscii(const OUString& inStr, |
| sal_Int32 startPos, sal_Int32 nCount, Sequence< sal_Int32 >& offset, sal_Bool useOffset ) throw(RuntimeException) |
| { |
| sal_Int32 strLen = inStr.getLength() - startPos; |
| |
| if (nCount > strLen) |
| nCount = strLen; |
| |
| if (nCount > 0) { |
| const sal_Unicode *str = inStr.getStr() + startPos; |
| rtl_uString *newStr = x_rtl_uString_new_WithLength( nCount * MultiplierExponent_7_CJK[0] + 1 ); |
| if (useOffset) |
| offset.realloc( nCount * MultiplierExponent_7_CJK[0] + 1 ); |
| sal_Int32 count = 0, index; |
| sal_Int32 i; |
| |
| OUString numberChar, multiplierChar, decimalChar, minusChar, separatorChar; |
| numberChar = OUString((sal_Unicode*)NumberChar, 10*NumberChar_Count); |
| multiplierChar = OUString((sal_Unicode*) MultiplierChar_7_CJK, ExponentCount_7_CJK*Multiplier_Count); |
| decimalChar = OUString(DecimalChar, NumberChar_Count); |
| minusChar = OUString(MinusChar, NumberChar_Count); |
| separatorChar = OUString(SeparatorChar, NumberChar_Count); |
| |
| for ( i = 0; i < nCount; i++) { |
| if ((index = multiplierChar.indexOf(str[i])) >= 0) { |
| if (count == 0 || !isNumber(newStr->buffer[count-1])) { // add 1 in front of multiplier |
| newStr->buffer[count] = NUMBER_ONE; |
| if (useOffset) |
| offset[count] = i; |
| count++; |
| } |
| index = MultiplierExponent_7_CJK[index % ExponentCount_7_CJK]; |
| NativeToAscii_numberMaker( |
| sal::static_int_cast<sal_Int16>( index ), sal::static_int_cast<sal_Int16>( index ), |
| str, i, nCount, newStr->buffer, count, offset, useOffset, |
| numberChar, multiplierChar); |
| } else { |
| if ((index = numberChar.indexOf(str[i])) >= 0) |
| newStr->buffer[count] = sal::static_int_cast<sal_Unicode>( (index % 10) + NUMBER_ZERO ); |
| else if ((index = separatorChar.indexOf(str[i])) >= 0 && |
| (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || |
| multiplierChar.indexOf(str[i+1]) >= 0))) |
| newStr->buffer[count] = SeparatorChar[NumberChar_HalfWidth]; |
| else if ((index = decimalChar.indexOf(str[i])) >= 0 && |
| (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || |
| multiplierChar.indexOf(str[i+1]) >= 0))) |
| // Only when decimal point is followed by numbers, |
| // it will be convert to ASCII decimal point |
| newStr->buffer[count] = DecimalChar[NumberChar_HalfWidth]; |
| else if ((index = minusChar.indexOf(str[i])) >= 0 && |
| (i < nCount-1 && (numberChar.indexOf(str[i+1]) >= 0 || |
| multiplierChar.indexOf(str[i+1]) >= 0))) |
| // Only when minus is followed by numbers, |
| // it will be convert to ASCII minus sign |
| newStr->buffer[count] = MinusChar[NumberChar_HalfWidth]; |
| else |
| newStr->buffer[count] = str[i]; |
| if (useOffset) |
| offset[count] = i; |
| count++; |
| } |
| } |
| |
| if (useOffset) { |
| offset.realloc(count); |
| for (i = 0; i < count; i++) |
| offset[i] += startPos; |
| } |
| OUString resultStr( newStr->buffer, count ); |
| x_rtl_uString_release( newStr ); |
| return resultStr; |
| } |
| return OUString(); |
| } |
| |
| static Number natnum4[4] = { |
| { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Modern_ja, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67, |
| ExponentCount_7_CJK, MultiplierExponent_7_CJK }, |
| { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ZERO, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| }; |
| |
| static Number natnum5[4] = { |
| { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], 0, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], 0, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Traditional_ja, MultiplierChar_7_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE_67, |
| ExponentCount_7_CJK, MultiplierExponent_7_CJK }, |
| { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ZERO, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| }; |
| |
| static Number natnum6[4] = { |
| { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh], 0, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], 0, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_FullWidth, MultiplierChar_7_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE_67, |
| ExponentCount_7_CJK, MultiplierExponent_7_CJK }, |
| { NumberChar_FullWidth, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| }; |
| |
| static Number natnum7[4] = { |
| { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Lower_zh, MultiplierChar_6_CJK[Multiplier_Lower_zh_TW], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Modern_ja, MultiplierChar_2_CJK[Multiplier_Modern_ja], NUMBER_OMIT_ZERO_ONE, |
| ExponentCount_2_CJK, MultiplierExponent_2_CJK }, |
| { NumberChar_Lower_ko, MultiplierChar_6_CJK[Multiplier_Lower_ko], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| }; |
| |
| static Number natnum8[4] = { |
| { NumberChar_Upper_zh, MultiplierChar_6_CJK[Multiplier_Upper_zh], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Upper_zh_TW, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| { NumberChar_Traditional_ja, MultiplierChar_2_CJK[Multiplier_Traditional_ja], NUMBER_OMIT_ZERO_ONE, |
| ExponentCount_2_CJK, MultiplierExponent_2_CJK }, |
| { NumberChar_Upper_ko, MultiplierChar_6_CJK[Multiplier_Upper_zh_TW], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }, |
| }; |
| |
| static Number natnum10 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ZERO, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }; |
| static Number natnum11 = { NumberChar_Hangul_ko, MultiplierChar_6_CJK[Multiplier_Hangul_ko], NUMBER_OMIT_ALL, |
| ExponentCount_6_CJK, MultiplierExponent_6_CJK }; |
| |
| //! ATTENTION: Do not change order of elements! |
| //! Append new languages to the end of the list! |
| static const sal_Char *natnum1Locales[] = { |
| "zh_CN", |
| "zh_TW", |
| "ja", |
| "ko", |
| "he", |
| "ar", |
| "th", |
| "hi", |
| "or", |
| "mr", |
| "bn", |
| "pa", |
| "gu", |
| "ta", |
| "te", |
| "kn", |
| "ml", |
| "lo", |
| "bo", |
| "my", |
| "km", |
| "mn", |
| "ne", |
| "dz", |
| "fa" |
| }; |
| static sal_Int16 nbOfLocale = sizeof(natnum1Locales)/sizeof(natnum1Locales[0]); |
| |
| //! ATTENTION: Do not change order of elements! |
| //! Number and order must match elements of natnum1Locales! |
| static sal_Int16 natnum1[] = { |
| NumberChar_Lower_zh, |
| NumberChar_Lower_zh, |
| NumberChar_Modern_ja, |
| NumberChar_Lower_ko, |
| NumberChar_he, |
| NumberChar_Indic_ar, |
| NumberChar_th, |
| NumberChar_hi, |
| NumberChar_or, |
| NumberChar_mr, |
| NumberChar_bn, |
| NumberChar_pa, |
| NumberChar_gu, |
| NumberChar_ta, |
| NumberChar_te, |
| NumberChar_kn, |
| NumberChar_ml, |
| NumberChar_lo, |
| NumberChar_bo, |
| NumberChar_my, |
| NumberChar_km, |
| NumberChar_mn, |
| NumberChar_ne, |
| NumberChar_dz, |
| NumberChar_EastIndic_ar |
| }; |
| static sal_Int16 sizeof_natnum1 = sizeof(natnum1)/sizeof(natnum1[0]); |
| |
| //! ATTENTION: Do not change order of elements! |
| //! Order must match first elements of natnum1Locales! |
| static sal_Int16 natnum2[] = { |
| NumberChar_Upper_zh, |
| NumberChar_Upper_zh_TW, |
| NumberChar_Traditional_ja, |
| NumberChar_Upper_ko, |
| NumberChar_he |
| }; |
| static sal_Int16 sizeof_natnum2 = sizeof(natnum2)/sizeof(natnum2[0]); |
| |
| #define isLang(lang) rLocale.Language.equalsAsciiL(lang, 2) |
| #define isCtry(ctry) rLocale.Country.equalsAsciiL(ctry, 2) |
| |
| static sal_Int16 SAL_CALL getLanguageNumber( const Locale& rLocale) |
| { |
| // return zh_TW for TW, HK and MO, return zh_CN for other zh locales. |
| if (isLang("zh")) return (isCtry("TW") || isCtry("HK") || isCtry("MO")) ? 1 : 0; |
| |
| for (sal_Int16 i = 2; i < nbOfLocale; i++) |
| if (isLang(natnum1Locales[i])) |
| return i; |
| |
| return -1; |
| } |
| |
| OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, |
| sal_Int16 nNativeNumberMode, Sequence< sal_Int32 >& offset) throw (RuntimeException) |
| { |
| Number *number = 0; |
| sal_Int16 num = -1; |
| |
| if (isValidNatNum(rLocale, nNativeNumberMode)) { |
| sal_Int16 langnum = getLanguageNumber(rLocale); |
| switch (nNativeNumberMode) { |
| case NativeNumberMode::NATNUM0: // Ascii |
| return NativeToAscii(aNumberString, 0, aNumberString.getLength(), offset, useOffset); |
| case NativeNumberMode::NATNUM1: // Char, Lower |
| num = natnum1[langnum]; |
| break; |
| case NativeNumberMode::NATNUM2: // Char, Upper |
| num = natnum2[langnum]; |
| break; |
| case NativeNumberMode::NATNUM3: // Char, FullWidth |
| num = NumberChar_FullWidth; |
| break; |
| case NativeNumberMode::NATNUM4: // Text, Lower, Long |
| number = &natnum4[langnum]; |
| break; |
| case NativeNumberMode::NATNUM5: // Text, Upper, Long |
| number = &natnum5[langnum]; |
| break; |
| case NativeNumberMode::NATNUM6: // Text, FullWidth |
| number = &natnum6[langnum]; |
| break; |
| case NativeNumberMode::NATNUM7: // Text. Lower, Short |
| number = &natnum7[langnum]; |
| break; |
| case NativeNumberMode::NATNUM8: // Text, Upper, Short |
| number = &natnum8[langnum]; |
| break; |
| case NativeNumberMode::NATNUM9: // Char, Hangul |
| num = NumberChar_Hangul_ko; |
| break; |
| case NativeNumberMode::NATNUM10: // Text, Hangul, Long |
| number = &natnum10; |
| break; |
| case NativeNumberMode::NATNUM11: // Text, Hangul, Short |
| number = &natnum11; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| if (number || num >= 0) { |
| if (!aLocale.Language.equals(rLocale.Language) || |
| !aLocale.Country.equals(rLocale.Country) || |
| !aLocale.Variant.equals(rLocale.Variant)) { |
| LocaleDataItem item = LocaleData().getLocaleItem( rLocale ); |
| aLocale = rLocale; |
| DecimalChar[NumberChar_HalfWidth]=item.decimalSeparator.toChar(); |
| if (DecimalChar[NumberChar_HalfWidth] > 0x7E || DecimalChar[NumberChar_HalfWidth] < 0x21) |
| DecimalChar[NumberChar_FullWidth]=0xFF0E; |
| else |
| DecimalChar[NumberChar_FullWidth]=DecimalChar[NumberChar_HalfWidth]+0xFEE0; |
| SeparatorChar[NumberChar_HalfWidth]=item.thousandSeparator.toChar(); |
| if (SeparatorChar[NumberChar_HalfWidth] > 0x7E || SeparatorChar[NumberChar_HalfWidth] < 0x21) |
| SeparatorChar[NumberChar_FullWidth]=0xFF0C; |
| else |
| SeparatorChar[NumberChar_FullWidth]=SeparatorChar[NumberChar_HalfWidth]+0xFEE0; |
| } |
| if (number) |
| return AsciiToNative( aNumberString, 0, aNumberString.getLength(), offset, useOffset, number ); |
| else if (num == NumberChar_he) |
| return getHebrewNativeNumberString(aNumberString, |
| nNativeNumberMode == NativeNumberMode::NATNUM2); |
| else |
| return AsciiToNativeChar(aNumberString, 0, aNumberString.getLength(), offset, useOffset, num); |
| } |
| else |
| return aNumberString; |
| } |
| |
| OUString SAL_CALL NativeNumberSupplier::getNativeNumberString(const OUString& aNumberString, const Locale& rLocale, |
| sal_Int16 nNativeNumberMode) throw (RuntimeException) |
| { |
| Sequence< sal_Int32 > offset; |
| return getNativeNumberString(aNumberString, rLocale, nNativeNumberMode, offset); |
| } |
| |
| sal_Unicode SAL_CALL NativeNumberSupplier::getNativeNumberChar( const sal_Unicode inChar, const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw(com::sun::star::uno::RuntimeException) |
| { |
| if (nNativeNumberMode == NativeNumberMode::NATNUM0) { // Ascii |
| for (sal_Int16 i = 0; i < NumberChar_Count; i++) |
| for (sal_Int16 j = 0; j < 10; j++) |
| if (inChar == NumberChar[i][j]) |
| return j; |
| return inChar; |
| } |
| else if (isNumber(inChar) && isValidNatNum(rLocale, nNativeNumberMode)) { |
| sal_Int16 langnum = getLanguageNumber(rLocale); |
| switch (nNativeNumberMode) { |
| case NativeNumberMode::NATNUM1: // Char, Lower |
| case NativeNumberMode::NATNUM4: // Text, Lower, Long |
| case NativeNumberMode::NATNUM7: // Text. Lower, Short |
| return NumberChar[natnum1[langnum]][inChar - NUMBER_ZERO]; |
| case NativeNumberMode::NATNUM2: // Char, Upper |
| case NativeNumberMode::NATNUM5: // Text, Upper, Long |
| case NativeNumberMode::NATNUM8: // Text, Upper, Short |
| return NumberChar[natnum2[langnum]][inChar - NUMBER_ZERO]; |
| case NativeNumberMode::NATNUM3: // Char, FullWidth |
| case NativeNumberMode::NATNUM6: // Text, FullWidth |
| return NumberChar[NumberChar_FullWidth][inChar - NUMBER_ZERO]; |
| case NativeNumberMode::NATNUM9: // Char, Hangul |
| case NativeNumberMode::NATNUM10: // Text, Hangul, Long |
| case NativeNumberMode::NATNUM11: // Text, Hangul, Short |
| return NumberChar[NumberChar_Hangul_ko][inChar - NUMBER_ZERO]; |
| default: |
| break; |
| } |
| } |
| return inChar; |
| } |
| |
| sal_Bool SAL_CALL NativeNumberSupplier::isValidNatNum( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException) |
| { |
| sal_Int16 langnum = getLanguageNumber(rLocale); |
| |
| switch (nNativeNumberMode) { |
| case NativeNumberMode::NATNUM0: // Ascii |
| case NativeNumberMode::NATNUM3: // Char, FullWidth |
| return sal_True; |
| case NativeNumberMode::NATNUM1: // Char, Lower |
| return (langnum >= 0); |
| case NativeNumberMode::NATNUM2: // Char, Upper |
| if (langnum == 4) // Hebrew numbering |
| return sal_True; |
| case NativeNumberMode::NATNUM4: // Text, Lower, Long |
| case NativeNumberMode::NATNUM5: // Text, Upper, Long |
| case NativeNumberMode::NATNUM6: // Text, FullWidth |
| case NativeNumberMode::NATNUM7: // Text. Lower, Short |
| case NativeNumberMode::NATNUM8: // Text, Upper, Short |
| return (langnum >= 0 && langnum < 4); // CJK numbering |
| case NativeNumberMode::NATNUM9: // Char, Hangul |
| case NativeNumberMode::NATNUM10: // Text, Hangul, Long |
| case NativeNumberMode::NATNUM11: // Text, Hangul, Short |
| return (langnum == 3); // Korean numbering |
| } |
| return sal_False; |
| } |
| |
| NativeNumberXmlAttributes SAL_CALL NativeNumberSupplier::convertToXmlAttributes( const Locale& rLocale, sal_Int16 nNativeNumberMode ) throw (RuntimeException) |
| { |
| static const sal_Int16 attShort = 0; |
| static const sal_Int16 attMedium = 1; |
| static const sal_Int16 attLong = 2; |
| static const sal_Char *attType[] = { "short", "medium", "long" }; |
| |
| sal_Int16 number = NumberChar_HalfWidth, type = attShort; |
| |
| if (isValidNatNum(rLocale, nNativeNumberMode)) { |
| sal_Int16 langnum = getLanguageNumber(rLocale); |
| switch (nNativeNumberMode) { |
| case NativeNumberMode::NATNUM0: // Ascii |
| number = NumberChar_HalfWidth; |
| type = attShort; |
| break; |
| case NativeNumberMode::NATNUM1: // Char, Lower |
| number = natnum1[langnum]; |
| type = attShort; |
| break; |
| case NativeNumberMode::NATNUM2: // Char, Upper |
| number = natnum2[langnum]; |
| type = number == NumberChar_he ? attMedium : attShort; |
| break; |
| case NativeNumberMode::NATNUM3: // Char, FullWidth |
| number = NumberChar_FullWidth; |
| type = attShort; |
| break; |
| case NativeNumberMode::NATNUM4: // Text, Lower, Long |
| number = natnum1[langnum]; |
| type = attLong; |
| break; |
| case NativeNumberMode::NATNUM5: // Text, Upper, Long |
| number = natnum2[langnum]; |
| type = attLong; |
| break; |
| case NativeNumberMode::NATNUM6: // Text, FullWidth |
| number = NumberChar_FullWidth; |
| type = attLong; |
| break; |
| case NativeNumberMode::NATNUM7: // Text. Lower, Short |
| number = natnum1[langnum]; |
| type = attMedium; |
| break; |
| case NativeNumberMode::NATNUM8: // Text, Upper, Short |
| number = natnum2[langnum]; |
| type = attMedium; |
| break; |
| case NativeNumberMode::NATNUM9: // Char, Hangul |
| number = NumberChar_Hangul_ko; |
| type = attShort; |
| break; |
| case NativeNumberMode::NATNUM10: // Text, Hangul, Long |
| number = NumberChar_Hangul_ko; |
| type = attLong; |
| break; |
| case NativeNumberMode::NATNUM11: // Text, Hangul, Short |
| number = NumberChar_Hangul_ko; |
| type = attMedium; |
| break; |
| default: |
| break; |
| } |
| } |
| return NativeNumberXmlAttributes(rLocale, OUString(&NumberChar[number][1], 1), |
| OUString::createFromAscii(attType[type])); |
| } |
| |
| static sal_Bool natNumIn(sal_Int16 num, sal_Int16 natnum[], sal_Int16 len) |
| { |
| for (sal_Int16 i = 0; i < len; i++) |
| if (natnum[i] == num) |
| return sal_True; |
| return sal_False; |
| } |
| |
| sal_Int16 SAL_CALL NativeNumberSupplier::convertFromXmlAttributes( const NativeNumberXmlAttributes& aAttr ) throw (RuntimeException) |
| { |
| sal_Unicode numberChar[NumberChar_Count]; |
| for (sal_Int16 i = 0; i < NumberChar_Count; i++) |
| numberChar[i] = NumberChar[i][1]; |
| OUString number(numberChar, NumberChar_Count); |
| |
| sal_Int16 num = sal::static_int_cast<sal_Int16>( number.indexOf(aAttr.Format) ); |
| |
| if (aAttr.Style.equalsAscii("short")) { |
| if (num == NumberChar_FullWidth) |
| return NativeNumberMode::NATNUM3; |
| else if (num == NumberChar_Hangul_ko) |
| return NativeNumberMode::NATNUM9; |
| else if (natNumIn(num, natnum1, sizeof_natnum1)) |
| return NativeNumberMode::NATNUM1; |
| else if (natNumIn(num, natnum2, sizeof_natnum2)) |
| return NativeNumberMode::NATNUM2; |
| } else if (aAttr.Style.equalsAscii("medium")) { |
| if (num == NumberChar_Hangul_ko) |
| return NativeNumberMode::NATNUM11; |
| else if (num == NumberChar_he) |
| return NativeNumberMode::NATNUM2; |
| else if (natNumIn(num, natnum1, sizeof_natnum1)) |
| return NativeNumberMode::NATNUM7; |
| else if (natNumIn(num, natnum2, sizeof_natnum2)) |
| return NativeNumberMode::NATNUM8; |
| } else if (aAttr.Style.equalsAscii("long")) { |
| if (num == NumberChar_FullWidth) |
| return NativeNumberMode::NATNUM6; |
| else if (num == NumberChar_Hangul_ko) |
| return NativeNumberMode::NATNUM10; |
| else if (natNumIn(num, natnum1, sizeof_natnum1)) |
| return NativeNumberMode::NATNUM4; |
| else if (natNumIn(num, natnum2, sizeof_natnum2)) |
| return NativeNumberMode::NATNUM5; |
| } else { |
| throw RuntimeException(); |
| } |
| return NativeNumberMode::NATNUM0; |
| } |
| |
| |
| // Following code generates Hebrew Number, |
| // see numerical system in the Hebrew Numbering System in following link for details, |
| // http://people.netscape.com/smontagu/writings/HebrewNumbers.html |
| |
| struct HebrewNumberChar { |
| sal_Unicode code; |
| sal_Int16 value; |
| } HebrewNumberCharArray[] = { |
| { 0x05ea, 400 }, |
| { 0x05ea, 400 }, |
| { 0x05e9, 300 }, |
| { 0x05e8, 200 }, |
| { 0x05e7, 100 }, |
| { 0x05e6, 90 }, |
| { 0x05e4, 80 }, |
| { 0x05e2, 70 }, |
| { 0x05e1, 60 }, |
| { 0x05e0, 50 }, |
| { 0x05de, 40 }, |
| { 0x05dc, 30 }, |
| { 0x05db, 20 }, |
| { 0x05d9, 10 }, |
| { 0x05d8, 9 }, |
| { 0x05d7, 8 }, |
| { 0x05d6, 7 }, |
| { 0x05d5, 6 }, |
| { 0x05d4, 5 }, |
| { 0x05d3, 4 }, |
| { 0x05d2, 3 }, |
| { 0x05d1, 2 }, |
| { 0x05d0, 1 } |
| }; |
| |
| static sal_Int16 nbOfHebrewNumberChar = sizeof(HebrewNumberCharArray)/sizeof(HebrewNumberChar); |
| |
| static sal_Unicode thousand[] = {0x05d0, 0x05dc, 0x05e3, 0x0}; |
| static sal_Unicode thousands[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x0}; |
| static sal_Unicode thousands_last[] = {0x05d0, 0x05dc, 0x05e4, 0x05d9, 0x05dd, 0x0}; |
| static sal_Unicode geresh = 0x05f3; |
| static sal_Unicode gershayim = 0x05f4; |
| |
| void makeHebrewNumber(sal_Int64 value, OUStringBuffer& output, sal_Bool isLast, sal_Bool useGeresh) |
| { |
| sal_Int16 num = sal::static_int_cast<sal_Int16>(value % 1000); |
| |
| if (value > 1000) { |
| makeHebrewNumber(value / 1000, output, num != 0, useGeresh); |
| output.appendAscii(" "); |
| } |
| if (num == 0) { |
| output.append(value == 1000 ? thousand : isLast ? thousands_last : thousands); |
| } else { |
| sal_Int16 nbOfChar = 0; |
| for (sal_Int32 j = 0; num > 0 && j < nbOfHebrewNumberChar; j++) { |
| if (num - HebrewNumberCharArray[j].value >= 0) { |
| nbOfChar++; |
| if (num == 15 || num == 16) // substitution for 15 and 16 |
| j++; |
| num = sal::static_int_cast<sal_Int16>( num - HebrewNumberCharArray[j].value ); |
| output.append(HebrewNumberCharArray[j].code); |
| } |
| } |
| if (useGeresh) { |
| if (nbOfChar > 1) // a number is written as more than one character |
| output.insert(output.getLength() - 1, gershayim); |
| else if (nbOfChar == 1) // a number is written as a single character |
| output.append(geresh); |
| } |
| } |
| } |
| |
| OUString SAL_CALL getHebrewNativeNumberString(const OUString& aNumberString, sal_Bool useGeresh) |
| { |
| sal_Int64 value = 0; |
| sal_Int32 i, count = 0, len = aNumberString.getLength(); |
| const sal_Unicode *src = aNumberString.getStr(); |
| sal_Bool neg = sal_False; |
| |
| for (i = 0; i < len; i++) { |
| sal_Unicode ch = src[i]; |
| if (isNumber(ch)) { |
| if (++count >= 20) // Number is too long, could not be handled. |
| return aNumberString; |
| value = value * 10 + (ch - NUMBER_ZERO); |
| } |
| else if (isSeparator(ch) && count > 0) continue; |
| else if (isMinus(ch) && count == 0) neg = sal_True; |
| else break; |
| } |
| |
| if (value > 0) { |
| OUStringBuffer output(count*2 + 2 + len - i); |
| |
| makeHebrewNumber(value, output, sal_True, useGeresh); |
| |
| if (i < len) |
| output.append(aNumberString.copy(i)); |
| |
| return output.makeStringAndClear(); |
| } |
| else |
| return aNumberString; |
| } |
| |
| static const sal_Char* implementationName = "com.sun.star.i18n.NativeNumberSupplier"; |
| |
| OUString SAL_CALL NativeNumberSupplier::getImplementationName() throw( RuntimeException ) |
| { |
| return OUString::createFromAscii( implementationName ); |
| } |
| |
| sal_Bool SAL_CALL |
| NativeNumberSupplier::supportsService(const OUString& rServiceName) throw( RuntimeException ) |
| { |
| return rServiceName.compareToAscii(implementationName) == 0; |
| } |
| |
| Sequence< OUString > SAL_CALL |
| NativeNumberSupplier::getSupportedServiceNames() throw( RuntimeException ) |
| { |
| Sequence< OUString > aRet(1); |
| aRet[0] = OUString::createFromAscii( implementationName ); |
| return aRet; |
| } |
| |
| } } } } |