1 /* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "AlphabeticIndex" 18 19 #include "IcuUtilities.h" 20 #include "JNIHelp.h" 21 #include "JniConstants.h" 22 #include "JniException.h" 23 #include "ScopedIcuLocale.h" 24 #include "ScopedJavaUnicodeString.h" 25 #include "unicode/alphaindex.h" 26 #include "unicode/uniset.h" 27 28 static AlphabeticIndex* fromPeer(jlong peer) { 29 return reinterpret_cast<AlphabeticIndex*>(static_cast<uintptr_t>(peer)); 30 } 31 32 static jlong AlphabeticIndex_create(JNIEnv* env, jclass, jstring javaLocaleName) { 33 UErrorCode status = U_ZERO_ERROR; 34 ScopedIcuLocale icuLocale(env, javaLocaleName); 35 if (!icuLocale.valid()) { 36 return 0; 37 } 38 AlphabeticIndex* ai = new AlphabeticIndex(icuLocale.locale(), status); 39 if (maybeThrowIcuException(env, "AlphabeticIndex", status)) { 40 return 0; 41 } 42 return reinterpret_cast<uintptr_t>(ai); 43 } 44 45 static void AlphabeticIndex_destroy(JNIEnv*, jclass, jlong peer) { 46 delete fromPeer(peer); 47 } 48 49 static jint AlphabeticIndex_getMaxLabelCount(JNIEnv*, jclass, jlong peer) { 50 AlphabeticIndex* ai = fromPeer(peer); 51 return ai->getMaxLabelCount(); 52 } 53 54 static void AlphabeticIndex_setMaxLabelCount(JNIEnv* env, jclass, jlong peer, jint count) { 55 AlphabeticIndex* ai = fromPeer(peer); 56 UErrorCode status = U_ZERO_ERROR; 57 ai->setMaxLabelCount(count, status); 58 maybeThrowIcuException(env, "AlphabeticIndex::setMaxLabelCount", status); 59 } 60 61 static void AlphabeticIndex_addLabels(JNIEnv* env, jclass, jlong peer, jstring javaLocaleName) { 62 AlphabeticIndex* ai = fromPeer(peer); 63 ScopedIcuLocale icuLocale(env, javaLocaleName); 64 if (!icuLocale.valid()) { 65 return; 66 } 67 UErrorCode status = U_ZERO_ERROR; 68 ai->addLabels(icuLocale.locale(), status); 69 maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status); 70 } 71 72 static void AlphabeticIndex_addLabelRange(JNIEnv* env, jclass, jlong peer, 73 jint codePointStart, jint codePointEnd) { 74 AlphabeticIndex* ai = fromPeer(peer); 75 UErrorCode status = U_ZERO_ERROR; 76 ai->addLabels(UnicodeSet(codePointStart, codePointEnd), status); 77 maybeThrowIcuException(env, "AlphabeticIndex::addLabels", status); 78 } 79 80 static jint AlphabeticIndex_getBucketCount(JNIEnv* env, jclass, jlong peer) { 81 AlphabeticIndex* ai = fromPeer(peer); 82 UErrorCode status = U_ZERO_ERROR; 83 jint result = ai->getBucketCount(status); 84 if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketCount", status)) { 85 return -1; 86 } 87 return result; 88 } 89 90 static jint AlphabeticIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) { 91 AlphabeticIndex* ai = fromPeer(peer); 92 ScopedJavaUnicodeString string(env, javaString); 93 if (!string.valid()) { 94 return -1; 95 } 96 UErrorCode status = U_ZERO_ERROR; 97 jint result = ai->getBucketIndex(string.unicodeString(), status); 98 if (maybeThrowIcuException(env, "AlphabeticIndex::getBucketIndex", status)) { 99 return -1; 100 } 101 return result; 102 } 103 104 static jstring AlphabeticIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) { 105 if (index < 0) { 106 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index); 107 return NULL; 108 } 109 110 // Iterate to the nth bucket. 111 AlphabeticIndex* ai = fromPeer(peer); 112 UErrorCode status = U_ZERO_ERROR; 113 ai->resetBucketIterator(status); 114 if (maybeThrowIcuException(env, "AlphabeticIndex::resetBucketIterator", status)) { 115 return NULL; 116 } 117 for (jint i = 0; i <= index; ++i) { 118 if (!ai->nextBucket(status)) { 119 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index); 120 return NULL; 121 } 122 if (maybeThrowIcuException(env, "AlphabeticIndex::nextBucket", status)) { 123 return NULL; 124 } 125 } 126 127 // Return "" for the underflow/inflow/overflow buckets. 128 if (ai->getBucketLabelType() != U_ALPHAINDEX_NORMAL) { 129 return env->NewStringUTF(""); 130 } 131 132 const UnicodeString& label(ai->getBucketLabel()); 133 return env->NewString(label.getBuffer(), label.length()); 134 } 135 136 static jlong AlphabeticIndex_buildImmutableIndex(JNIEnv* env, jclass, jlong peer) { 137 AlphabeticIndex* ai = fromPeer(peer); 138 UErrorCode status = U_ZERO_ERROR; 139 AlphabeticIndex::ImmutableIndex* ii = ai->buildImmutableIndex(status); 140 if (maybeThrowIcuException(env, "AlphabeticIndex::buildImmutableIndex", status)) { 141 return 0; 142 } 143 return reinterpret_cast<uintptr_t>(ii); 144 } 145 146 static AlphabeticIndex::ImmutableIndex* immutableIndexFromPeer(jlong peer) { 147 return reinterpret_cast<AlphabeticIndex::ImmutableIndex*>(static_cast<uintptr_t>(peer)); 148 } 149 150 static jint ImmutableIndex_getBucketCount(JNIEnv*, jclass, jlong peer) { 151 AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer); 152 return ii->getBucketCount(); 153 } 154 155 static jint ImmutableIndex_getBucketIndex(JNIEnv* env, jclass, jlong peer, jstring javaString) { 156 AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer); 157 ScopedJavaUnicodeString string(env, javaString); 158 if (!string.valid()) { 159 return -1; 160 } 161 UErrorCode status = U_ZERO_ERROR; 162 jint result = ii->getBucketIndex(string.unicodeString(), status); 163 if (maybeThrowIcuException(env, "AlphabeticIndex::ImmutableIndex::getBucketIndex", status)) { 164 return -1; 165 } 166 return result; 167 } 168 169 static jstring ImmutableIndex_getBucketLabel(JNIEnv* env, jclass, jlong peer, jint index) { 170 AlphabeticIndex::ImmutableIndex* ii = immutableIndexFromPeer(peer); 171 const AlphabeticIndex::Bucket* bucket = ii->getBucket(index); 172 if (bucket == NULL) { 173 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", "Invalid index: %d", index); 174 return NULL; 175 } 176 177 // Return "" for the underflow/inflow/overflow buckets. 178 if (bucket->getLabelType() != U_ALPHAINDEX_NORMAL) { 179 return env->NewStringUTF(""); 180 } 181 182 const UnicodeString& label(bucket->getLabel()); 183 return env->NewString(label.getBuffer(), label.length()); 184 } 185 186 static JNINativeMethod gMethods[] = { 187 NATIVE_METHOD(AlphabeticIndex, create, "(Ljava/lang/String;)J"), 188 NATIVE_METHOD(AlphabeticIndex, destroy, "(J)V"), 189 NATIVE_METHOD(AlphabeticIndex, getMaxLabelCount, "(J)I"), 190 NATIVE_METHOD(AlphabeticIndex, setMaxLabelCount, "(JI)V"), 191 NATIVE_METHOD(AlphabeticIndex, addLabels, "(JLjava/lang/String;)V"), 192 NATIVE_METHOD(AlphabeticIndex, addLabelRange, "(JII)V"), 193 NATIVE_METHOD(AlphabeticIndex, getBucketCount, "(J)I"), 194 NATIVE_METHOD(AlphabeticIndex, getBucketIndex, "(JLjava/lang/String;)I"), 195 NATIVE_METHOD(AlphabeticIndex, getBucketLabel, "(JI)Ljava/lang/String;"), 196 NATIVE_METHOD(AlphabeticIndex, buildImmutableIndex, "(J)J"), 197 }; 198 static JNINativeMethod gImmutableIndexMethods[] = { 199 NATIVE_METHOD(ImmutableIndex, getBucketCount, "(J)I"), 200 NATIVE_METHOD(ImmutableIndex, getBucketIndex, "(JLjava/lang/String;)I"), 201 NATIVE_METHOD(ImmutableIndex, getBucketLabel, "(JI)Ljava/lang/String;"), 202 }; 203 void register_libcore_icu_AlphabeticIndex(JNIEnv* env) { 204 jniRegisterNativeMethods(env, "libcore/icu/AlphabeticIndex", gMethods, NELEM(gMethods)); 205 jniRegisterNativeMethods(env, "libcore/icu/AlphabeticIndex$ImmutableIndex", gImmutableIndexMethods, NELEM(gImmutableIndexMethods)); 206 } 207