Home | History | Annotate | Download | only in native
      1 /**
      2 *******************************************************************************
      3 * Copyright (C) 1996-2005, International Business Machines Corporation and    *
      4 * others. All Rights Reserved.                                                *
      5 *******************************************************************************
      6 *
      7 *******************************************************************************
      8 */
      9 
     10 #define LOG_TAG "NativeCollation"
     11 
     12 #include "IcuUtilities.h"
     13 #include "JNIHelp.h"
     14 #include "JniConstants.h"
     15 #include "JniException.h"
     16 #include "ScopedStringChars.h"
     17 #include "ScopedUtfChars.h"
     18 #include "UniquePtr.h"
     19 #include "unicode/ucol.h"
     20 #include "unicode/ucoleitr.h"
     21 #include <cutils/log.h>
     22 
     23 // Manages a UCollationElements instance along with the jchar
     24 // array it is iterating over. The associated array can be unpinned
     25 // only after a call to ucol_closeElements. This means we have to
     26 // keep a reference to the string (so that it isn't collected) and
     27 // make a call to GetStringChars to ensure the underlying array is
     28 // pinned.
     29 class CollationElements {
     30 public:
     31     CollationElements()
     32         : mElements(NULL), mString(NULL), mChars(NULL) {
     33     }
     34 
     35     UCollationElements* get() const {
     36         return mElements;
     37     }
     38 
     39     // Starts a new iteration sequence over the string |string|. If
     40     // we have a valid UCollationElements object, we call ucol_setText
     41     // on it. Otherwise, we create a new object with the specified
     42     // collator.
     43     UErrorCode start(JNIEnv* env, jstring string, UCollator* collator) {
     44         release(env, false /* don't close the collator */);
     45         mChars = env->GetStringChars(string, NULL);
     46         if (mChars != NULL) {
     47             mString = static_cast<jstring>(env->NewGlobalRef(string));
     48             const size_t size = env->GetStringLength(string);
     49 
     50             UErrorCode status = U_ZERO_ERROR;
     51             // If we don't have a UCollationElements object yet, create
     52             // a new one. If we do, reset it.
     53             if (mElements == NULL) {
     54                 mElements = ucol_openElements(collator, mChars, size, &status);
     55             } else {
     56                ucol_setText(mElements, mChars, size, &status);
     57             }
     58 
     59             return status;
     60         }
     61 
     62         return U_ILLEGAL_ARGUMENT_ERROR;
     63     }
     64 
     65     void release(JNIEnv* env, bool closeCollator) {
     66         if (mElements != NULL && closeCollator) {
     67             ucol_closeElements(mElements);
     68         }
     69 
     70         if (mChars != NULL) {
     71             env->ReleaseStringChars(mString, mChars);
     72             env->DeleteGlobalRef(mString);
     73             mChars = NULL;
     74             mString = NULL;
     75         }
     76     }
     77 
     78 private:
     79     UCollationElements* mElements;
     80     jstring mString;
     81     const jchar* mChars;
     82 };
     83 
     84 static UCollator* toCollator(jlong address) {
     85     return reinterpret_cast<UCollator*>(static_cast<uintptr_t>(address));
     86 }
     87 
     88 static CollationElements* toCollationElements(jlong address) {
     89     return reinterpret_cast<CollationElements*>(static_cast<uintptr_t>(address));
     90 }
     91 
     92 static void NativeCollation_closeCollator(JNIEnv*, jclass, jlong address) {
     93     ucol_close(toCollator(address));
     94 }
     95 
     96 static void NativeCollation_closeElements(JNIEnv* env, jclass, jlong address) {
     97     CollationElements* elements = toCollationElements(address);
     98     elements->release(env, true /* close collator */);
     99     delete elements;
    100 }
    101 
    102 static jint NativeCollation_compare(JNIEnv* env, jclass, jlong address, jstring javaLhs, jstring javaRhs) {
    103     ScopedStringChars lhs(env, javaLhs);
    104     if (lhs.get() == NULL) {
    105         return 0;
    106     }
    107     ScopedStringChars rhs(env, javaRhs);
    108     if (rhs.get() == NULL) {
    109         return 0;
    110     }
    111     return ucol_strcoll(toCollator(address), lhs.get(), lhs.size(), rhs.get(), rhs.size());
    112 }
    113 
    114 static jint NativeCollation_getAttribute(JNIEnv* env, jclass, jlong address, jint type) {
    115     UErrorCode status = U_ZERO_ERROR;
    116     jint result = ucol_getAttribute(toCollator(address), (UColAttribute) type, &status);
    117     maybeThrowIcuException(env, "ucol_getAttribute", status);
    118     return result;
    119 }
    120 
    121 static jlong NativeCollation_getCollationElementIterator(JNIEnv* env, jclass, jlong address, jstring javaSource) {
    122     ScopedStringChars source(env, javaSource);
    123     if (source.get() == NULL) {
    124         return -1;
    125     }
    126 
    127     UniquePtr<CollationElements> ce(new CollationElements);
    128     UErrorCode status = ce->start(env, javaSource, toCollator(address));
    129     maybeThrowIcuException(env, "ucol_openElements", status);
    130     if (status == U_ZERO_ERROR) {
    131         return static_cast<jlong>(reinterpret_cast<uintptr_t>(ce.release()));
    132     }
    133 
    134     return 0L;
    135 }
    136 
    137 static jint NativeCollation_getMaxExpansion(JNIEnv*, jclass, jlong address, jint order) {
    138     return ucol_getMaxExpansion(toCollationElements(address)->get(), order);
    139 }
    140 
    141 static jint NativeCollation_getOffset(JNIEnv*, jclass, jlong address) {
    142     return ucol_getOffset(toCollationElements(address)->get());
    143 }
    144 
    145 static jstring NativeCollation_getRules(JNIEnv* env, jclass, jlong address) {
    146     int32_t length = 0;
    147     const UChar* rules = ucol_getRules(toCollator(address), &length);
    148     return env->NewString(rules, length);
    149 }
    150 
    151 static jbyteArray NativeCollation_getSortKey(JNIEnv* env, jclass, jlong address, jstring javaSource) {
    152     ScopedStringChars source(env, javaSource);
    153     if (source.get() == NULL) {
    154         return NULL;
    155     }
    156     const UCollator* collator  = toCollator(address);
    157     // The buffer size prevents reallocation for most strings.
    158     uint8_t byteArray[128];
    159     UniquePtr<uint8_t[]> largerByteArray;
    160     uint8_t* usedByteArray = byteArray;
    161     size_t byteArraySize = ucol_getSortKey(collator, source.get(), source.size(), usedByteArray, sizeof(byteArray) - 1);
    162     if (byteArraySize > sizeof(byteArray) - 1) {
    163         // didn't fit, try again with a larger buffer.
    164         largerByteArray.reset(new uint8_t[byteArraySize + 1]);
    165         usedByteArray = largerByteArray.get();
    166         byteArraySize = ucol_getSortKey(collator, source.get(), source.size(), usedByteArray, byteArraySize);
    167     }
    168     if (byteArraySize == 0) {
    169         return NULL;
    170     }
    171     jbyteArray result = env->NewByteArray(byteArraySize);
    172     env->SetByteArrayRegion(result, 0, byteArraySize, reinterpret_cast<jbyte*>(usedByteArray));
    173     return result;
    174 }
    175 
    176 static jint NativeCollation_next(JNIEnv* env, jclass, jlong address) {
    177     UErrorCode status = U_ZERO_ERROR;
    178     jint result = ucol_next(toCollationElements(address)->get(), &status);
    179     maybeThrowIcuException(env, "ucol_next", status);
    180     return result;
    181 }
    182 
    183 static jlong NativeCollation_openCollator(JNIEnv* env, jclass, jstring javaLocaleName) {
    184     ScopedUtfChars localeChars(env, javaLocaleName);
    185     if (localeChars.c_str() == NULL) {
    186         return 0;
    187     }
    188 
    189     UErrorCode status = U_ZERO_ERROR;
    190     UCollator* c = ucol_open(localeChars.c_str(), &status);
    191     maybeThrowIcuException(env, "ucol_open", status);
    192     return static_cast<jlong>(reinterpret_cast<uintptr_t>(c));
    193 }
    194 
    195 static jlong NativeCollation_openCollatorFromRules(JNIEnv* env, jclass, jstring javaRules, jint mode, jint strength) {
    196     ScopedStringChars rules(env, javaRules);
    197     if (rules.get() == NULL) {
    198         return -1;
    199     }
    200     UErrorCode status = U_ZERO_ERROR;
    201     UCollator* c = ucol_openRules(rules.get(), rules.size(),
    202             UColAttributeValue(mode), UCollationStrength(strength), NULL, &status);
    203     maybeThrowIcuException(env, "ucol_openRules", status);
    204     return static_cast<jlong>(reinterpret_cast<uintptr_t>(c));
    205 }
    206 
    207 static jint NativeCollation_previous(JNIEnv* env, jclass, jlong address) {
    208     UErrorCode status = U_ZERO_ERROR;
    209     jint result = ucol_previous(toCollationElements(address)->get(), &status);
    210     maybeThrowIcuException(env, "ucol_previous", status);
    211     return result;
    212 }
    213 
    214 static void NativeCollation_reset(JNIEnv*, jclass, jlong address) {
    215     ucol_reset(toCollationElements(address)->get());
    216 }
    217 
    218 static jlong NativeCollation_safeClone(JNIEnv* env, jclass, jlong address) {
    219     UErrorCode status = U_ZERO_ERROR;
    220     UCollator* c = ucol_safeClone(toCollator(address), NULL, NULL, &status);
    221     maybeThrowIcuException(env, "ucol_safeClone", status);
    222     return static_cast<jlong>(reinterpret_cast<uintptr_t>(c));
    223 }
    224 
    225 static void NativeCollation_setAttribute(JNIEnv* env, jclass, jlong address, jint type, jint value) {
    226     UErrorCode status = U_ZERO_ERROR;
    227     ucol_setAttribute(toCollator(address), (UColAttribute)type, (UColAttributeValue)value, &status);
    228     maybeThrowIcuException(env, "ucol_setAttribute", status);
    229 }
    230 
    231 static void NativeCollation_setOffset(JNIEnv* env, jclass, jlong address, jint offset) {
    232     UErrorCode status = U_ZERO_ERROR;
    233     ucol_setOffset(toCollationElements(address)->get(), offset, &status);
    234     maybeThrowIcuException(env, "ucol_setOffset", status);
    235 }
    236 
    237 static void NativeCollation_setText(JNIEnv* env, jclass, jlong address, jstring javaSource) {
    238     ScopedStringChars source(env, javaSource);
    239     if (source.get() == NULL) {
    240         return;
    241     }
    242     UErrorCode status = toCollationElements(address)->start(env, javaSource, NULL);
    243     maybeThrowIcuException(env, "ucol_setText", status);
    244 }
    245 
    246 static JNINativeMethod gMethods[] = {
    247     NATIVE_METHOD(NativeCollation, closeCollator, "(J)V"),
    248     NATIVE_METHOD(NativeCollation, closeElements, "(J)V"),
    249     NATIVE_METHOD(NativeCollation, compare, "(JLjava/lang/String;Ljava/lang/String;)I"),
    250     NATIVE_METHOD(NativeCollation, getAttribute, "(JI)I"),
    251     NATIVE_METHOD(NativeCollation, getCollationElementIterator, "(JLjava/lang/String;)J"),
    252     NATIVE_METHOD(NativeCollation, getMaxExpansion, "(JI)I"),
    253     NATIVE_METHOD(NativeCollation, getOffset, "(J)I"),
    254     NATIVE_METHOD(NativeCollation, getRules, "(J)Ljava/lang/String;"),
    255     NATIVE_METHOD(NativeCollation, getSortKey, "(JLjava/lang/String;)[B"),
    256     NATIVE_METHOD(NativeCollation, next, "(J)I"),
    257     NATIVE_METHOD(NativeCollation, openCollator, "(Ljava/lang/String;)J"),
    258     NATIVE_METHOD(NativeCollation, openCollatorFromRules, "(Ljava/lang/String;II)J"),
    259     NATIVE_METHOD(NativeCollation, previous, "(J)I"),
    260     NATIVE_METHOD(NativeCollation, reset, "(J)V"),
    261     NATIVE_METHOD(NativeCollation, safeClone, "(J)J"),
    262     NATIVE_METHOD(NativeCollation, setAttribute, "(JII)V"),
    263     NATIVE_METHOD(NativeCollation, setOffset, "(JI)V"),
    264     NATIVE_METHOD(NativeCollation, setText, "(JLjava/lang/String;)V"),
    265 };
    266 void register_libcore_icu_NativeCollation(JNIEnv* env) {
    267     jniRegisterNativeMethods(env, "libcore/icu/NativeCollation", gMethods, NELEM(gMethods));
    268 }
    269