diff options
24 files changed, 393 insertions, 120 deletions
diff --git a/include/ScopedJavaUnicodeString.h b/include/ScopedJavaUnicodeString.h index b108a6b..f6ed7ad 100644 --- a/include/ScopedJavaUnicodeString.h +++ b/include/ScopedJavaUnicodeString.h @@ -1,12 +1,12 @@ /* * Copyright (C) 2010 The Android Open Source Project - * + * * Licensed 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. @@ -24,34 +24,44 @@ // jstring. We give ICU a direct pointer to the characters on the Java heap. // It's clever enough to copy-on-write if necessary. class ScopedJavaUnicodeString { -public: - ScopedJavaUnicodeString(JNIEnv* env, jstring s) : mEnv(env), mString(s) { - mChars = env->GetStringChars(mString, NULL); - const int32_t charCount = env->GetStringLength(mString); - mUnicodeString.setTo(false, mChars, charCount); + public: + ScopedJavaUnicodeString(JNIEnv* env, jstring s) : mEnv(env), mString(s) { + if (s == NULL) { + jniThrowNullPointerException(mEnv, NULL); + } else { + mChars = env->GetStringChars(mString, NULL); + const int32_t charCount = env->GetStringLength(mString); + mUnicodeString.setTo(false, mChars, charCount); } + } - ~ScopedJavaUnicodeString() { - mEnv->ReleaseStringChars(mString, mChars); + ~ScopedJavaUnicodeString() { + if (mString != NULL) { + mEnv->ReleaseStringChars(mString, mChars); } + } - const UnicodeString& unicodeString() const { - return mUnicodeString; - } + bool valid() const { + return (mString != NULL); + } - UnicodeString& unicodeString() { - return mUnicodeString; - } + const UnicodeString& unicodeString() const { + return mUnicodeString; + } + + UnicodeString& unicodeString() { + return mUnicodeString; + } -private: - JNIEnv* mEnv; - jstring mString; - const UChar* mChars; - UnicodeString mUnicodeString; + private: + JNIEnv* mEnv; + jstring mString; + const UChar* mChars; + UnicodeString mUnicodeString; - // Disallow copy and assignment. - ScopedJavaUnicodeString(const ScopedJavaUnicodeString&); - void operator=(const ScopedJavaUnicodeString&); + // Disallow copy and assignment. + ScopedJavaUnicodeString(const ScopedJavaUnicodeString&); + void operator=(const ScopedJavaUnicodeString&); }; #endif // SCOPED_JAVA_UNICODE_STRING_H_included diff --git a/luni/src/main/java/libcore/icu/Transliterator.java b/luni/src/main/java/libcore/icu/Transliterator.java new file mode 100644 index 0000000..bef5d37 --- /dev/null +++ b/luni/src/main/java/libcore/icu/Transliterator.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed 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. + */ + +package libcore.icu; + +public final class Transliterator { + /** + * Returns the ids of all known transliterators. + */ + public static native String[] getAvailableIDs(); + + /** + * Transliterates 's' using the transliterator identified by 'id'. + */ + public static native String transliterate(String id, String s); + + private Transliterator() {} +} diff --git a/luni/src/main/native/IcuUtilities.cpp b/luni/src/main/native/IcuUtilities.cpp new file mode 100644 index 0000000..ef9909b --- /dev/null +++ b/luni/src/main/native/IcuUtilities.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed 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. + */ + +#define LOG_TAG "IcuUtilities" + +#include "IcuUtilities.h" + +#include "JniConstants.h" +#include "JniException.h" +#include "ScopedLocalRef.h" +#include "ScopedUtfChars.h" +#include "UniquePtr.h" +#include "cutils/log.h" +#include "unicode/strenum.h" +#include "unicode/uloc.h" +#include "unicode/ustring.h" + +Locale getLocale(JNIEnv* env, jstring localeName) { + return Locale::createFromName(ScopedUtfChars(env, localeName).c_str()); +} + +jobjectArray fromStringEnumeration(JNIEnv* env, StringEnumeration* se) { + UniquePtr<StringEnumeration> deleter(se); + if (se == NULL) { + return NULL; + } + + UErrorCode status = U_ZERO_ERROR; + int32_t count = se->count(status); + if (maybeThrowIcuException(env, "StringEnumeration::count", status)) { + return NULL; + } + + jobjectArray result = env->NewObjectArray(count, JniConstants::stringClass, NULL); + for (int32_t i = 0; i < count; ++i) { + const UnicodeString* string = se->snext(status); + if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) { + return NULL; + } + ScopedLocalRef<jstring> javaString(env, env->NewString(string->getBuffer(), string->length())); + env->SetObjectArrayElement(result, i, javaString.get()); + } + return result; +} + +bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error) { + if (U_SUCCESS(error)) { + return false; + } + const char* exceptionClass = "java/lang/RuntimeException"; + if (error == U_ILLEGAL_ARGUMENT_ERROR) { + exceptionClass = "java/lang/IllegalArgumentException"; + } else if (error == U_INDEX_OUTOFBOUNDS_ERROR || error == U_BUFFER_OVERFLOW_ERROR) { + exceptionClass = "java/lang/ArrayIndexOutOfBoundsException"; + } else if (error == U_UNSUPPORTED_ERROR) { + exceptionClass = "java/lang/UnsupportedOperationException"; + } + jniThrowExceptionFmt(env, exceptionClass, "%s failed: %s", function, u_errorName(error)); + return true; +} diff --git a/luni/src/main/native/IcuUtilities.h b/luni/src/main/native/IcuUtilities.h new file mode 100644 index 0000000..219d663 --- /dev/null +++ b/luni/src/main/native/IcuUtilities.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed 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. + */ + +#ifndef ICU_UTILITIES_H_included +#define ICU_UTILITIES_H_included + +#include "jni.h" +#include "unicode/utypes.h" // For UErrorCode. +#include "unicode/locid.h" // For Locale. + +extern Locale getLocale(JNIEnv* env, jstring localeName); +extern jobjectArray fromStringEnumeration(JNIEnv* env, StringEnumeration*); +bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error); + +#endif // ICU_UTILITIES_H_included diff --git a/luni/src/main/native/JniException.cpp b/luni/src/main/native/JniException.cpp index c733db4..8f97891 100644 --- a/luni/src/main/native/JniException.cpp +++ b/luni/src/main/native/JniException.cpp @@ -17,29 +17,6 @@ #include "JniException.h" #include "JNIHelp.h" -bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error) { - if (U_SUCCESS(error)) { - return false; - } - const char* exceptionClass; - switch (error) { - case U_ILLEGAL_ARGUMENT_ERROR: - exceptionClass = "java/lang/IllegalArgumentException"; - break; - case U_INDEX_OUTOFBOUNDS_ERROR: - case U_BUFFER_OVERFLOW_ERROR: - exceptionClass = "java/lang/ArrayIndexOutOfBoundsException"; - break; - case U_UNSUPPORTED_ERROR: - exceptionClass = "java/lang/UnsupportedOperationException"; - break; - default: - exceptionClass = "java/lang/RuntimeException"; - break; - } - return jniThrowExceptionFmt(env, exceptionClass, "%s failed: %s", function, u_errorName(error)); -} - void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error) { char buf[BUFSIZ]; jniThrowException(env, exceptionClassName, jniStrError(error, buf, sizeof(buf))); diff --git a/luni/src/main/native/JniException.h b/luni/src/main/native/JniException.h index cece2aa..2d4a097 100644 --- a/luni/src/main/native/JniException.h +++ b/luni/src/main/native/JniException.h @@ -18,13 +18,10 @@ #define JNI_EXCEPTION_H_included #include "jni.h" -#include "unicode/utypes.h" // For UErrorCode. void jniThrowExceptionWithErrno(JNIEnv* env, const char* exceptionClassName, int error); void jniThrowOutOfMemoryError(JNIEnv* env, const char* message); void jniThrowSocketException(JNIEnv* env, int error); -bool maybeThrowIcuException(JNIEnv* env, const char* function, UErrorCode error); - #endif // JNI_EXCEPTION_H_included diff --git a/luni/src/main/native/Register.cpp b/luni/src/main/native/Register.cpp index 36abd7b..7ef36ad 100644 --- a/luni/src/main/native/Register.cpp +++ b/luni/src/main/native/Register.cpp @@ -63,6 +63,7 @@ int JNI_OnLoad(JavaVM* vm, void*) { REGISTER(register_libcore_icu_NativeNormalizer); REGISTER(register_libcore_icu_NativePluralRules); REGISTER(register_libcore_icu_TimeZones); + REGISTER(register_libcore_icu_Transliterator); REGISTER(register_libcore_io_AsynchronousCloseMonitor); REGISTER(register_libcore_io_Memory); REGISTER(register_libcore_io_OsConstants); diff --git a/luni/src/main/native/zip.h b/luni/src/main/native/ZipUtilities.h index 303c940..4c86f32 100644 --- a/luni/src/main/native/zip.h +++ b/luni/src/main/native/ZipUtilities.h @@ -15,8 +15,8 @@ * limitations under the License. */ -#if !defined(zip_h) -#define zip_h +#ifndef ZIP_UTILITIES_H_included +#define ZIP_UTILITIES_H_included #include "JNIHelp.h" #include "JniException.h" @@ -97,4 +97,4 @@ static NativeZipStream* toNativeZipStream(jlong address) { return reinterpret_cast<NativeZipStream*>(static_cast<uintptr_t>(address)); } -#endif /* zip_h */ +#endif // ZIP_UTILITIES_H_included diff --git a/luni/src/main/native/java_text_Bidi.cpp b/luni/src/main/native/java_text_Bidi.cpp index cb492b4..d9ef35d 100644 --- a/luni/src/main/native/java_text_Bidi.cpp +++ b/luni/src/main/native/java_text_Bidi.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "Bidi" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" diff --git a/luni/src/main/native/java_util_regex_Matcher.cpp b/luni/src/main/native/java_util_regex_Matcher.cpp index a8ee1a0..9b58301 100644 --- a/luni/src/main/native/java_util_regex_Matcher.cpp +++ b/luni/src/main/native/java_util_regex_Matcher.cpp @@ -18,6 +18,7 @@ #include <stdlib.h> +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" diff --git a/luni/src/main/native/java_util_regex_Pattern.cpp b/luni/src/main/native/java_util_regex_Pattern.cpp index cad154f..bd1f326 100644 --- a/luni/src/main/native/java_util_regex_Pattern.cpp +++ b/luni/src/main/native/java_util_regex_Pattern.cpp @@ -83,6 +83,9 @@ static jint Pattern_compileImpl(JNIEnv* env, jclass, jstring javaRegex, jint fla error.offset = -1; ScopedJavaUnicodeString regex(env, javaRegex); + if (!regex.valid()) { + return 0; + } UnicodeString& regexString(regex.unicodeString()); RegexPattern* result = RegexPattern::compile(regexString, flags, error, status); if (!U_SUCCESS(status)) { diff --git a/luni/src/main/native/java_util_zip_Deflater.cpp b/luni/src/main/native/java_util_zip_Deflater.cpp index e129134..ed7d754 100644 --- a/luni/src/main/native/java_util_zip_Deflater.cpp +++ b/luni/src/main/native/java_util_zip_Deflater.cpp @@ -19,7 +19,7 @@ #include "JniConstants.h" #include "ScopedPrimitiveArray.h" -#include "zip.h" +#include "ZipUtilities.h" static void Deflater_setDictionaryImpl(JNIEnv* env, jobject, jbyteArray dict, int off, int len, jlong handle) { toNativeZipStream(handle)->setDictionary(env, dict, off, len, false); diff --git a/luni/src/main/native/java_util_zip_Inflater.cpp b/luni/src/main/native/java_util_zip_Inflater.cpp index 890c6dc..6aa3e24 100644 --- a/luni/src/main/native/java_util_zip_Inflater.cpp +++ b/luni/src/main/native/java_util_zip_Inflater.cpp @@ -19,7 +19,7 @@ #include "JniConstants.h" #include "ScopedPrimitiveArray.h" -#include "zip.h" +#include "ZipUtilities.h" #include <errno.h> static jlong Inflater_createStream(JNIEnv* env, jobject, jboolean noHeader) { diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp index eafb336..7385757 100644 --- a/luni/src/main/native/libcore_icu_ICU.cpp +++ b/luni/src/main/native/libcore_icu_ICU.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "ICU" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" @@ -92,10 +93,6 @@ class ScopedResourceBundle { DISALLOW_COPY_AND_ASSIGN(ScopedResourceBundle); }; -Locale getLocale(JNIEnv* env, jstring localeName) { - return Locale::createFromName(ScopedUtfChars(env, localeName).c_str()); -} - static jstring ICU_addLikelySubtags(JNIEnv* env, jclass, jstring javaLocale) { UErrorCode status = U_ZERO_ERROR; ScopedUtfChars localeID(env, javaLocale); @@ -119,10 +116,13 @@ static jstring ICU_getScript(JNIEnv* env, jclass, jstring javaLocale) { } static jint ICU_getCurrencyFractionDigits(JNIEnv* env, jclass, jstring javaCurrencyCode) { - ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode); - UnicodeString icuCurrencyCode(currencyCode.unicodeString()); - UErrorCode status = U_ZERO_ERROR; - return ucurr_getDefaultFractionDigits(icuCurrencyCode.getTerminatedBuffer(), &status); + ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode); + if (!currencyCode.valid()) { + return 0; + } + UnicodeString icuCurrencyCode(currencyCode.unicodeString()); + UErrorCode status = U_ZERO_ERROR; + return ucurr_getDefaultFractionDigits(icuCurrencyCode.getTerminatedBuffer(), &status); } // TODO: rewrite this with int32_t ucurr_forLocale(const char* locale, UChar* buff, int32_t buffCapacity, UErrorCode* ec)... @@ -170,7 +170,13 @@ static jstring ICU_getCurrencyCode(JNIEnv* env, jclass, jstring javaCountryCode) static jstring getCurrencyName(JNIEnv* env, jstring javaLocaleName, jstring javaCurrencyCode, UCurrNameStyle nameStyle) { ScopedUtfChars localeName(env, javaLocaleName); + if (localeName.c_str() == NULL) { + return NULL; + } ScopedJavaUnicodeString currencyCode(env, javaCurrencyCode); + if (!currencyCode.valid()) { + return NULL; + } UnicodeString icuCurrencyCode(currencyCode.unicodeString()); UErrorCode status = U_ZERO_ERROR; UBool isChoiceFormat = false; @@ -621,19 +627,25 @@ static jboolean ICU_initLocaleDataImpl(JNIEnv* env, jclass, jstring javaLocaleNa } static jstring ICU_toLowerCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) { - ScopedJavaUnicodeString scopedString(env, javaString); - UnicodeString& s(scopedString.unicodeString()); - UnicodeString original(s); - s.toLower(Locale::createFromName(ScopedUtfChars(env, localeName).c_str())); - return s == original ? javaString : env->NewString(s.getBuffer(), s.length()); + ScopedJavaUnicodeString scopedString(env, javaString); + if (!scopedString.valid()) { + return NULL; + } + UnicodeString& s(scopedString.unicodeString()); + UnicodeString original(s); + s.toLower(Locale::createFromName(ScopedUtfChars(env, localeName).c_str())); + return s == original ? javaString : env->NewString(s.getBuffer(), s.length()); } static jstring ICU_toUpperCase(JNIEnv* env, jclass, jstring javaString, jstring localeName) { - ScopedJavaUnicodeString scopedString(env, javaString); - UnicodeString& s(scopedString.unicodeString()); - UnicodeString original(s); - s.toUpper(Locale::createFromName(ScopedUtfChars(env, localeName).c_str())); - return s == original ? javaString : env->NewString(s.getBuffer(), s.length()); + ScopedJavaUnicodeString scopedString(env, javaString); + if (!scopedString.valid()) { + return NULL; + } + UnicodeString& s(scopedString.unicodeString()); + UnicodeString original(s); + s.toUpper(Locale::createFromName(ScopedUtfChars(env, localeName).c_str())); + return s == original ? javaString : env->NewString(s.getBuffer(), s.length()); } static jstring versionString(JNIEnv* env, const UVersionInfo& version) { @@ -689,6 +701,9 @@ static jstring ICU_getBestDateTimePattern(JNIEnv* env, jclass, jstring javaPatte } ScopedJavaUnicodeString patternHolder(env, javaPattern); + if (!patternHolder.valid()) { + return NULL; + } UnicodeString result(generator->getBestPattern(patternHolder.unicodeString(), status)); if (maybeThrowIcuException(env, "DateTimePatternGenerator::getBestPattern", status)) { return NULL; diff --git a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp index 92c41ab..c025a60 100644 --- a/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp +++ b/luni/src/main/native/libcore_icu_NativeBreakIterator.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "NativeBreakIterator" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" diff --git a/luni/src/main/native/libcore_icu_NativeCollation.cpp b/luni/src/main/native/libcore_icu_NativeCollation.cpp index 32b1cc4..98a78ea 100644 --- a/luni/src/main/native/libcore_icu_NativeCollation.cpp +++ b/luni/src/main/native/libcore_icu_NativeCollation.cpp @@ -9,6 +9,7 @@ #define LOG_TAG "NativeCollation" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" diff --git a/luni/src/main/native/libcore_icu_NativeConverter.cpp b/luni/src/main/native/libcore_icu_NativeConverter.cpp index d7eee14..24dfa6f 100644 --- a/luni/src/main/native/libcore_icu_NativeConverter.cpp +++ b/luni/src/main/native/libcore_icu_NativeConverter.cpp @@ -15,6 +15,7 @@ #define LOG_TAG "NativeConverter" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" diff --git a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp index 0406094..cdc3bad 100644 --- a/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp +++ b/luni/src/main/native/libcore_icu_NativeDecimalFormat.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "NativeDecimalFormat" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" @@ -106,13 +107,12 @@ static jint NativeDecimalFormat_open(JNIEnv* env, jclass, jstring pattern0, jstring internationalCurrencySymbol, jchar minusSign, jchar monetaryDecimalSeparator, jstring nan, jchar patternSeparator, jchar percent, jchar perMill, jchar zeroDigit) { - if (pattern0 == NULL) { - jniThrowNullPointerException(env, NULL); - return 0; - } UErrorCode status = U_ZERO_ERROR; UParseError parseError; ScopedJavaUnicodeString pattern(env, pattern0); + if (!pattern.valid()) { + return 0; + } DecimalFormatSymbols* symbols = makeDecimalFormatSymbols(env, currencySymbol, decimalSeparator, digit, exponentSeparator, groupingSeparator, infinity, internationalCurrencySymbol, minusSign, @@ -188,11 +188,10 @@ static jstring NativeDecimalFormat_getTextAttribute(JNIEnv* env, jclass, jint ad } static void NativeDecimalFormat_applyPatternImpl(JNIEnv* env, jclass, jint addr, jboolean localized, jstring pattern0) { - if (pattern0 == NULL) { - jniThrowNullPointerException(env, NULL); - return; - } ScopedJavaUnicodeString pattern(env, pattern0); + if (!pattern.valid()) { + return; + } DecimalFormat* fmt = toDecimalFormat(addr); UErrorCode status = U_ZERO_ERROR; const char* function; @@ -299,6 +298,9 @@ static jobject NativeDecimalFormat_parse(JNIEnv* env, jclass, jint addr, jstring Formattable res; ParsePosition pp(parsePos); ScopedJavaUnicodeString src(env, text); + if (!src.valid()) { + return NULL; + } DecimalFormat* fmt = toDecimalFormat(addr); fmt->parse(src.unicodeString(), res, pp); diff --git a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp index 693e944..8ae42d9 100644 --- a/luni/src/main/native/libcore_icu_NativeNormalizer.cpp +++ b/luni/src/main/native/libcore_icu_NativeNormalizer.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "NativeNormalizer" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" @@ -23,28 +24,34 @@ #include "unicode/normlzr.h" static jstring NativeNormalizer_normalizeImpl(JNIEnv* env, jclass, jstring s, jint intMode) { - ScopedJavaUnicodeString src(env, s); - UNormalizationMode mode = static_cast<UNormalizationMode>(intMode); - UErrorCode status = U_ZERO_ERROR; - UnicodeString dst; - Normalizer::normalize(src.unicodeString(), mode, 0, dst, status); - maybeThrowIcuException(env, "Normalizer::normalize", status); - return dst.isBogus() ? NULL : env->NewString(dst.getBuffer(), dst.length()); + ScopedJavaUnicodeString src(env, s); + if (!src.valid()) { + return NULL; + } + UNormalizationMode mode = static_cast<UNormalizationMode>(intMode); + UErrorCode status = U_ZERO_ERROR; + UnicodeString dst; + Normalizer::normalize(src.unicodeString(), mode, 0, dst, status); + maybeThrowIcuException(env, "Normalizer::normalize", status); + return dst.isBogus() ? NULL : env->NewString(dst.getBuffer(), dst.length()); } static jboolean NativeNormalizer_isNormalizedImpl(JNIEnv* env, jclass, jstring s, jint intMode) { - ScopedJavaUnicodeString src(env, s); - UNormalizationMode mode = static_cast<UNormalizationMode>(intMode); - UErrorCode status = U_ZERO_ERROR; - UBool result = Normalizer::isNormalized(src.unicodeString(), mode, status); - maybeThrowIcuException(env, "Normalizer::isNormalized", status); - return result; + ScopedJavaUnicodeString src(env, s); + if (!src.valid()) { + return JNI_FALSE; + } + UNormalizationMode mode = static_cast<UNormalizationMode>(intMode); + UErrorCode status = U_ZERO_ERROR; + UBool result = Normalizer::isNormalized(src.unicodeString(), mode, status); + maybeThrowIcuException(env, "Normalizer::isNormalized", status); + return result; } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(NativeNormalizer, normalizeImpl, "(Ljava/lang/String;I)Ljava/lang/String;"), - NATIVE_METHOD(NativeNormalizer, isNormalizedImpl, "(Ljava/lang/String;I)Z"), + NATIVE_METHOD(NativeNormalizer, normalizeImpl, "(Ljava/lang/String;I)Ljava/lang/String;"), + NATIVE_METHOD(NativeNormalizer, isNormalizedImpl, "(Ljava/lang/String;I)Z"), }; void register_libcore_icu_NativeNormalizer(JNIEnv* env) { - jniRegisterNativeMethods(env, "libcore/icu/NativeNormalizer", gMethods, NELEM(gMethods)); + jniRegisterNativeMethods(env, "libcore/icu/NativeNormalizer", gMethods, NELEM(gMethods)); } diff --git a/luni/src/main/native/libcore_icu_NativePluralRules.cpp b/luni/src/main/native/libcore_icu_NativePluralRules.cpp index df228ff..3253eb8 100644 --- a/luni/src/main/native/libcore_icu_NativePluralRules.cpp +++ b/luni/src/main/native/libcore_icu_NativePluralRules.cpp @@ -16,6 +16,7 @@ #define LOG_TAG "NativePluralRules" +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" diff --git a/luni/src/main/native/libcore_icu_TimeZones.cpp b/luni/src/main/native/libcore_icu_TimeZones.cpp index 11e53a5..80cb096 100644 --- a/luni/src/main/native/libcore_icu_TimeZones.cpp +++ b/luni/src/main/native/libcore_icu_TimeZones.cpp @@ -19,6 +19,7 @@ #include <map> #include <vector> +#include "IcuUtilities.h" #include "JNIHelp.h" #include "JniConstants.h" #include "JniException.h" @@ -29,34 +30,12 @@ #include "unicode/smpdtfmt.h" #include "unicode/timezone.h" -extern Locale getLocale(JNIEnv* env, jstring localeName); - static jobjectArray TimeZones_forCountryCode(JNIEnv* env, jclass, jstring countryCode) { ScopedUtfChars countryChars(env, countryCode); if (countryChars.c_str() == NULL) { return NULL; } - - UniquePtr<StringEnumeration> ids(TimeZone::createEnumeration(countryChars.c_str())); - if (ids.get() == NULL) { - return NULL; - } - UErrorCode status = U_ZERO_ERROR; - int32_t idCount = ids->count(status); - if (maybeThrowIcuException(env, "StringEnumeration::count", status)) { - return NULL; - } - - jobjectArray result = env->NewObjectArray(idCount, JniConstants::stringClass, NULL); - for (int32_t i = 0; i < idCount; ++i) { - const UnicodeString* id = ids->snext(status); - if (maybeThrowIcuException(env, "StringEnumeration::snext", status)) { - return NULL; - } - ScopedLocalRef<jstring> idString(env, env->NewString(id->getBuffer(), id->length())); - env->SetObjectArrayElement(result, i, idString.get()); - } - return result; + return fromStringEnumeration(env, TimeZone::createEnumeration(countryChars.c_str())); } struct TimeZoneNames { @@ -146,6 +125,9 @@ static jobjectArray TimeZones_getZoneStringsImpl(JNIEnv* env, jclass, jstring lo ScopedLocalRef<jstring> javaZoneId(env, reinterpret_cast<jstring>(env->GetObjectArrayElement(timeZoneIds, i))); ScopedJavaUnicodeString zoneId(env, javaZoneId.get()); + if (!zoneId.valid()) { + return NULL; + } UnicodeString id(zoneId.unicodeString()); TimeZoneNames row; diff --git a/luni/src/main/native/libcore_icu_Transliterator.cpp b/luni/src/main/native/libcore_icu_Transliterator.cpp new file mode 100644 index 0000000..7f38192 --- /dev/null +++ b/luni/src/main/native/libcore_icu_Transliterator.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed 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. + */ + +#define LOG_TAG "Transliterator" + +#include "IcuUtilities.h" +#include "JNIHelp.h" +#include "JniConstants.h" +#include "JniException.h" +#include "ScopedJavaUnicodeString.h" +#include "ScopedStringChars.h" +#include "unicode/translit.h" + +extern jobjectArray fromStringEnumeration(JNIEnv* env, StringEnumeration*); + +static jobjectArray Transliterator_getAvailableIDs(JNIEnv* env, jclass) { + UErrorCode status = U_ZERO_ERROR; + return fromStringEnumeration(env, Transliterator::getAvailableIDs(status)); +} + +static jstring Transliterator_transliterate(JNIEnv* env, jclass, jstring javaId, jstring javaString) { + ScopedJavaUnicodeString id(env, javaId); + if (!id.valid()) { + return NULL; + } + ScopedJavaUnicodeString string(env, javaString); + if (!string.valid()) { + return NULL; + } + + UErrorCode status = U_ZERO_ERROR; + Transliterator* t = Transliterator::createInstance(id.unicodeString(), UTRANS_FORWARD, status); + if (maybeThrowIcuException(env, "Transliterator::createInstance", status)) { + return NULL; + } + + UnicodeString& s(string.unicodeString()); + t->transliterate(s); + + return env->NewString(s.getBuffer(), s.length()); +} + +static JNINativeMethod gMethods[] = { + NATIVE_METHOD(Transliterator, getAvailableIDs, "()[Ljava/lang/String;"), + NATIVE_METHOD(Transliterator, transliterate, "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;"), +}; +void register_libcore_icu_Transliterator(JNIEnv* env) { + jniRegisterNativeMethods(env, "libcore/icu/Transliterator", gMethods, NELEM(gMethods)); +} diff --git a/luni/src/main/native/sub.mk b/luni/src/main/native/sub.mk index d5705a6..e562972 100644 --- a/luni/src/main/native/sub.mk +++ b/luni/src/main/native/sub.mk @@ -5,6 +5,7 @@ LOCAL_SRC_FILES := \ AsynchronousSocketCloseMonitor.cpp \ + IcuUtilities.cpp \ JniConstants.cpp \ JniException.cpp \ NetworkUtilities.cpp \ @@ -39,6 +40,7 @@ LOCAL_SRC_FILES := \ libcore_icu_NativeNormalizer.cpp \ libcore_icu_NativePluralRules.cpp \ libcore_icu_TimeZones.cpp \ + libcore_icu_Transliterator.cpp \ libcore_io_AsynchronousCloseMonitor.cpp \ libcore_io_Memory.cpp \ libcore_io_OsConstants.cpp \ diff --git a/luni/src/test/java/libcore/icu/TransliteratorTest.java b/luni/src/test/java/libcore/icu/TransliteratorTest.java new file mode 100644 index 0000000..7187cbc --- /dev/null +++ b/luni/src/test/java/libcore/icu/TransliteratorTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed 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. + */ + +package libcore.icu; + +public class TransliteratorTest extends junit.framework.TestCase { + public void testAll() throws Exception { + for (String id : Transliterator.getAvailableIDs()) { + System.err.println(id); + Transliterator.transliterate(id, "hello"); + } + } + + public void test_Unknown() throws Exception { + try { + Transliterator.transliterate("Unknown", "hello"); + fail(); + } catch (RuntimeException expected) { + } + } + + public void test_null_id() throws Exception { + try { + Transliterator.transliterate(null, "hello"); + fail(); + } catch (NullPointerException expected) { + } + } + + public void test_null_string() throws Exception { + try { + Transliterator.transliterate("Any-Upper", null); + fail(); + } catch (NullPointerException expected) { + } + } + + public void test_Any_Upper() throws Exception { + assertEquals("HELLO WORLD!", Transliterator.transliterate("Any-Upper", "HeLlO WoRlD!")); + assertEquals("STRASSE", Transliterator.transliterate("Any-Upper", "Straße")); + } + + public void test_Any_Lower() throws Exception { + assertEquals("hello world!", Transliterator.transliterate("Any-Lower", "HeLlO WoRlD!")); + } + + public void test_Greek_Latin() throws Exception { + String greek = "Καλημέρα κόσμε!"; + + // Transliterate Greek to Latin, then to plain ASCII. + String latin = Transliterator.transliterate("Greek-Latin", greek); + String ascii = Transliterator.transliterate("Latin-Ascii", latin); + assertEquals("Kalēméra kósme!", latin); + assertEquals("Kalemera kosme!", ascii); + + // Use alternative transliteration variants. + assertEquals("Kaliméra kósme!", Transliterator.transliterate("Greek-Latin/BGN", greek)); + assertEquals("Kali̱méra kósme!", Transliterator.transliterate("Greek-Latin/UNGEGN", greek)); + } + + public void test_Han_Latin() throws Exception { + assertEquals("hàn zì/hàn zì", Transliterator.transliterate("Han-Latin", "汉字/漢字")); + } +} |