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