| /** |
| ******************************************************************************* |
| * Copyright (C) 1996-2005, International Business Machines Corporation and * |
| * others. All Rights Reserved. * |
| ******************************************************************************* |
| * |
| ******************************************************************************* |
| */ |
| |
| #define LOG_TAG "NativeCollation" |
| |
| #include "IcuUtilities.h" |
| #include "JNIHelp.h" |
| #include "JniConstants.h" |
| #include "JniException.h" |
| #include "ScopedStringChars.h" |
| #include "ScopedUtfChars.h" |
| #include "unicode/ucol.h" |
| #include "unicode/ucoleitr.h" |
| #include <cutils/log.h> |
| #include <memory> |
| |
| // Manages a UCollationElements instance along with the jchar |
| // array it is iterating over. The associated array can be unpinned |
| // only after a call to ucol_closeElements. This means we have to |
| // keep a reference to the string (so that it isn't collected) and |
| // make a call to GetStringChars to ensure the underlying array is |
| // pinned. |
| class CollationElements { |
| public: |
| CollationElements() |
| : mElements(NULL), mString(NULL), mChars(NULL) { |
| } |
| |
| UCollationElements* get() const { |
| return mElements; |
| } |
| |
| // Starts a new iteration sequence over the string |string|. If |
| // we have a valid UCollationElements object, we call ucol_setText |
| // on it. Otherwise, we create a new object with the specified |
| // collator. |
| UErrorCode start(JNIEnv* env, jstring string, UCollator* collator) { |
| release(env, false /* don't close the collator */); |
| mChars = env->GetStringChars(string, NULL); |
| if (mChars != NULL) { |
| mString = static_cast<jstring>(env->NewGlobalRef(string)); |
| const size_t size = env->GetStringLength(string); |
| |
| UErrorCode status = U_ZERO_ERROR; |
| // If we don't have a UCollationElements object yet, create |
| // a new one. If we do, reset it. |
| if (mElements == NULL) { |
| mElements = ucol_openElements(collator, mChars, size, &status); |
| } else { |
| ucol_setText(mElements, mChars, size, &status); |
| } |
| |
| return status; |
| } |
| |
| return U_ILLEGAL_ARGUMENT_ERROR; |
| } |
| |
| void release(JNIEnv* env, bool closeCollator) { |
| if (mElements != NULL && closeCollator) { |
| ucol_closeElements(mElements); |
| } |
| |
| if (mChars != NULL) { |
| env->ReleaseStringChars(mString, mChars); |
| env->DeleteGlobalRef(mString); |
| mChars = NULL; |
| mString = NULL; |
| } |
| } |
| |
| private: |
| UCollationElements* mElements; |
| jstring mString; |
| const jchar* mChars; |
| }; |
| |
| static UCollator* toCollator(jlong address) { |
| return reinterpret_cast<UCollator*>(static_cast<uintptr_t>(address)); |
| } |
| |
| static CollationElements* toCollationElements(jlong address) { |
| return reinterpret_cast<CollationElements*>(static_cast<uintptr_t>(address)); |
| } |
| |
| static void NativeCollation_closeCollator(JNIEnv*, jclass, jlong address) { |
| ucol_close(toCollator(address)); |
| } |
| |
| static void NativeCollation_closeElements(JNIEnv* env, jclass, jlong address) { |
| CollationElements* elements = toCollationElements(address); |
| elements->release(env, true /* close collator */); |
| delete elements; |
| } |
| |
| static jint NativeCollation_compare(JNIEnv* env, jclass, jlong address, jstring javaLhs, jstring javaRhs) { |
| ScopedStringChars lhs(env, javaLhs); |
| if (lhs.get() == NULL) { |
| return 0; |
| } |
| ScopedStringChars rhs(env, javaRhs); |
| if (rhs.get() == NULL) { |
| return 0; |
| } |
| return ucol_strcoll(toCollator(address), lhs.get(), lhs.size(), rhs.get(), rhs.size()); |
| } |
| |
| static jint NativeCollation_getAttribute(JNIEnv* env, jclass, jlong address, jint type) { |
| UErrorCode status = U_ZERO_ERROR; |
| jint result = ucol_getAttribute(toCollator(address), (UColAttribute) type, &status); |
| maybeThrowIcuException(env, "ucol_getAttribute", status); |
| return result; |
| } |
| |
| static jlong NativeCollation_getCollationElementIterator(JNIEnv* env, jclass, jlong address, jstring javaSource) { |
| ScopedStringChars source(env, javaSource); |
| if (source.get() == NULL) { |
| return -1; |
| } |
| |
| std::unique_ptr<CollationElements> ce(new CollationElements); |
| UErrorCode status = ce->start(env, javaSource, toCollator(address)); |
| maybeThrowIcuException(env, "ucol_openElements", status); |
| if (status == U_ZERO_ERROR) { |
| return static_cast<jlong>(reinterpret_cast<uintptr_t>(ce.release())); |
| } |
| |
| return 0L; |
| } |
| |
| static jint NativeCollation_getMaxExpansion(JNIEnv*, jclass, jlong address, jint order) { |
| return ucol_getMaxExpansion(toCollationElements(address)->get(), order); |
| } |
| |
| static jint NativeCollation_getOffset(JNIEnv*, jclass, jlong address) { |
| return ucol_getOffset(toCollationElements(address)->get()); |
| } |
| |
| static jstring NativeCollation_getRules(JNIEnv* env, jclass, jlong address) { |
| int32_t length = 0; |
| const UChar* rules = ucol_getRules(toCollator(address), &length); |
| return env->NewString(rules, length); |
| } |
| |
| static jbyteArray NativeCollation_getSortKey(JNIEnv* env, jclass, jlong address, jstring javaSource) { |
| ScopedStringChars source(env, javaSource); |
| if (source.get() == NULL) { |
| return NULL; |
| } |
| const UCollator* collator = toCollator(address); |
| // The buffer size prevents reallocation for most strings. |
| uint8_t byteArray[128]; |
| std::unique_ptr<uint8_t[]> largerByteArray; |
| uint8_t* usedByteArray = byteArray; |
| size_t byteArraySize = ucol_getSortKey(collator, source.get(), source.size(), usedByteArray, sizeof(byteArray) - 1); |
| if (byteArraySize > sizeof(byteArray) - 1) { |
| // didn't fit, try again with a larger buffer. |
| largerByteArray.reset(new uint8_t[byteArraySize + 1]); |
| usedByteArray = largerByteArray.get(); |
| byteArraySize = ucol_getSortKey(collator, source.get(), source.size(), usedByteArray, byteArraySize); |
| } |
| if (byteArraySize == 0) { |
| return NULL; |
| } |
| jbyteArray result = env->NewByteArray(byteArraySize); |
| env->SetByteArrayRegion(result, 0, byteArraySize, reinterpret_cast<jbyte*>(usedByteArray)); |
| return result; |
| } |
| |
| static jint NativeCollation_next(JNIEnv* env, jclass, jlong address) { |
| UErrorCode status = U_ZERO_ERROR; |
| jint result = ucol_next(toCollationElements(address)->get(), &status); |
| maybeThrowIcuException(env, "ucol_next", status); |
| return result; |
| } |
| |
| static jlong NativeCollation_openCollator(JNIEnv* env, jclass, jstring javaLocaleName) { |
| ScopedUtfChars localeChars(env, javaLocaleName); |
| if (localeChars.c_str() == NULL) { |
| return 0; |
| } |
| |
| UErrorCode status = U_ZERO_ERROR; |
| UCollator* c = ucol_open(localeChars.c_str(), &status); |
| maybeThrowIcuException(env, "ucol_open", status); |
| return static_cast<jlong>(reinterpret_cast<uintptr_t>(c)); |
| } |
| |
| static jlong NativeCollation_openCollatorFromRules(JNIEnv* env, jclass, jstring javaRules, jint mode, jint strength) { |
| ScopedStringChars rules(env, javaRules); |
| if (rules.get() == NULL) { |
| return -1; |
| } |
| UErrorCode status = U_ZERO_ERROR; |
| UCollator* c = ucol_openRules(rules.get(), rules.size(), |
| UColAttributeValue(mode), UCollationStrength(strength), NULL, &status); |
| maybeThrowIcuException(env, "ucol_openRules", status); |
| return static_cast<jlong>(reinterpret_cast<uintptr_t>(c)); |
| } |
| |
| static jint NativeCollation_previous(JNIEnv* env, jclass, jlong address) { |
| UErrorCode status = U_ZERO_ERROR; |
| jint result = ucol_previous(toCollationElements(address)->get(), &status); |
| maybeThrowIcuException(env, "ucol_previous", status); |
| return result; |
| } |
| |
| static void NativeCollation_reset(JNIEnv*, jclass, jlong address) { |
| ucol_reset(toCollationElements(address)->get()); |
| } |
| |
| static jlong NativeCollation_safeClone(JNIEnv* env, jclass, jlong address) { |
| UErrorCode status = U_ZERO_ERROR; |
| UCollator* c = ucol_safeClone(toCollator(address), NULL, NULL, &status); |
| maybeThrowIcuException(env, "ucol_safeClone", status); |
| return static_cast<jlong>(reinterpret_cast<uintptr_t>(c)); |
| } |
| |
| static void NativeCollation_setAttribute(JNIEnv* env, jclass, jlong address, jint type, jint value) { |
| UErrorCode status = U_ZERO_ERROR; |
| ucol_setAttribute(toCollator(address), (UColAttribute)type, (UColAttributeValue)value, &status); |
| maybeThrowIcuException(env, "ucol_setAttribute", status); |
| } |
| |
| static void NativeCollation_setOffset(JNIEnv* env, jclass, jlong address, jint offset) { |
| UErrorCode status = U_ZERO_ERROR; |
| ucol_setOffset(toCollationElements(address)->get(), offset, &status); |
| maybeThrowIcuException(env, "ucol_setOffset", status); |
| } |
| |
| static void NativeCollation_setText(JNIEnv* env, jclass, jlong address, jstring javaSource) { |
| ScopedStringChars source(env, javaSource); |
| if (source.get() == NULL) { |
| return; |
| } |
| UErrorCode status = toCollationElements(address)->start(env, javaSource, NULL); |
| maybeThrowIcuException(env, "ucol_setText", status); |
| } |
| |
| static JNINativeMethod gMethods[] = { |
| NATIVE_METHOD(NativeCollation, closeCollator, "(J)V"), |
| NATIVE_METHOD(NativeCollation, closeElements, "(J)V"), |
| NATIVE_METHOD(NativeCollation, compare, "(JLjava/lang/String;Ljava/lang/String;)I"), |
| NATIVE_METHOD(NativeCollation, getAttribute, "(JI)I"), |
| NATIVE_METHOD(NativeCollation, getCollationElementIterator, "(JLjava/lang/String;)J"), |
| NATIVE_METHOD(NativeCollation, getMaxExpansion, "(JI)I"), |
| NATIVE_METHOD(NativeCollation, getOffset, "(J)I"), |
| NATIVE_METHOD(NativeCollation, getRules, "(J)Ljava/lang/String;"), |
| NATIVE_METHOD(NativeCollation, getSortKey, "(JLjava/lang/String;)[B"), |
| NATIVE_METHOD(NativeCollation, next, "(J)I"), |
| NATIVE_METHOD(NativeCollation, openCollator, "(Ljava/lang/String;)J"), |
| NATIVE_METHOD(NativeCollation, openCollatorFromRules, "(Ljava/lang/String;II)J"), |
| NATIVE_METHOD(NativeCollation, previous, "(J)I"), |
| NATIVE_METHOD(NativeCollation, reset, "(J)V"), |
| NATIVE_METHOD(NativeCollation, safeClone, "(J)J"), |
| NATIVE_METHOD(NativeCollation, setAttribute, "(JII)V"), |
| NATIVE_METHOD(NativeCollation, setOffset, "(JI)V"), |
| NATIVE_METHOD(NativeCollation, setText, "(JLjava/lang/String;)V"), |
| }; |
| void register_libcore_icu_NativeCollation(JNIEnv* env) { |
| jniRegisterNativeMethods(env, "libcore/icu/NativeCollation", gMethods, NELEM(gMethods)); |
| } |