summaryrefslogtreecommitdiff
path: root/i18npool/source/nativenumber/nativenumbersupplier.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'i18npool/source/nativenumber/nativenumbersupplier.cxx')
-rw-r--r--i18npool/source/nativenumber/nativenumbersupplier.cxx920
1 files changed, 920 insertions, 0 deletions
diff --git a/i18npool/source/nativenumber/nativenumbersupplier.cxx b/i18npool/source/nativenumber/nativenumbersupplier.cxx
new file mode 100644
index 000000000000..cb170b6e1fd1
--- /dev/null
+++ b/i18npool/source/nativenumber/nativenumbersupplier.cxx
@@ -0,0 +1,920 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_i18npool.hxx"
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/macros.h>
+#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);
+ 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->buffer, nCount);
+}
+
+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);
+ return OUString(newStr->buffer, count);
+ }
+ 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;
+ }
+ return OUString(newStr->buffer, count);
+ }
+ 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 = SAL_N_ELEMENTS(natnum1Locales);
+
+//! 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 = SAL_N_ELEMENTS(natnum1);
+
+//! 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 = SAL_N_ELEMENTS(natnum2);
+
+#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.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("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.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("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.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("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();
+
+ 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) continue;
+ 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;
+}
+
+} } } }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */