1 /* 2 * Copyright (C) 2006 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 "NativeBreakIterator" 18 19 #include "JNIHelp.h" 20 #include "JniConstants.h" 21 #include "JniException.h" 22 #include "ScopedUtfChars.h" 23 #include "unicode/ubrk.h" 24 #include "unicode/putil.h" 25 #include <stdlib.h> 26 27 /** 28 * ICU4C 4.6 doesn't let us update the pointers inside a UBreakIterator to track our char[] as it 29 * moves around the heap. This class pins the char[] for the lifetime of the 30 * java.text.BreakIterator. It also holds a global reference to the java.lang.String that owns the 31 * char[] so that the char[] can't be GCed. 32 */ 33 class BreakIteratorPeer { 34 public: 35 static BreakIteratorPeer* fromAddress(jint address) { 36 return reinterpret_cast<BreakIteratorPeer*>(static_cast<uintptr_t>(address)); 37 } 38 39 uintptr_t toAddress() { 40 return reinterpret_cast<uintptr_t>(this); 41 } 42 43 BreakIteratorPeer(UBreakIterator* it) : mIt(it), mString(NULL), mChars(NULL) { 44 } 45 46 void setText(JNIEnv* env, jstring s) { 47 releaseString(env); 48 49 mString = reinterpret_cast<jstring>(env->NewGlobalRef(s)); 50 mChars = env->GetStringChars(mString, NULL); 51 if (mChars == NULL) { 52 return; 53 } 54 55 size_t charCount = env->GetStringLength(mString); 56 UErrorCode status = U_ZERO_ERROR; 57 ubrk_setText(mIt, mChars, charCount, &status); 58 maybeThrowIcuException(env, status); 59 } 60 61 BreakIteratorPeer* clone(JNIEnv* env) { 62 UErrorCode status = U_ZERO_ERROR; 63 jint bufferSize = U_BRK_SAFECLONE_BUFFERSIZE; 64 UBreakIterator* it = ubrk_safeClone(mIt, NULL, &bufferSize, &status); 65 if (maybeThrowIcuException(env, status)) { 66 return NULL; 67 } 68 BreakIteratorPeer* result = new BreakIteratorPeer(it); 69 if (mString != NULL) { 70 result->setText(env, mString); 71 } 72 return result; 73 } 74 75 void close(JNIEnv* env) { 76 if (mIt != NULL) { 77 ubrk_close(mIt); 78 mIt = NULL; 79 } 80 releaseString(env); 81 } 82 83 ~BreakIteratorPeer() { 84 if (mIt != NULL || mString != NULL) { 85 LOG_ALWAYS_FATAL("BreakIteratorPeer deleted but not closed"); 86 } 87 } 88 89 UBreakIterator* breakIterator() { 90 return mIt; 91 } 92 93 private: 94 UBreakIterator* mIt; 95 96 jstring mString; 97 const jchar* mChars; 98 99 void releaseString(JNIEnv* env) { 100 if (mString != NULL) { 101 env->ReleaseStringChars(mString, mChars); 102 env->DeleteGlobalRef(mString); 103 mString = NULL; 104 } 105 } 106 107 // Disallow copy and assignment. 108 BreakIteratorPeer(const BreakIteratorPeer&); 109 void operator=(const BreakIteratorPeer&); 110 }; 111 112 static UBreakIterator* breakIterator(jint address) { 113 return BreakIteratorPeer::fromAddress(address)->breakIterator(); 114 } 115 116 static jint makeIterator(JNIEnv* env, jstring locale, UBreakIteratorType type) { 117 UErrorCode status = U_ZERO_ERROR; 118 const ScopedUtfChars localeChars(env, locale); 119 if (localeChars.c_str() == NULL) { 120 return 0; 121 } 122 UBreakIterator* it = ubrk_open(type, localeChars.c_str(), NULL, 0, &status); 123 if (maybeThrowIcuException(env, status)) { 124 return 0; 125 } 126 return (new BreakIteratorPeer(it))->toAddress(); 127 } 128 129 static jint NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring locale) { 130 return makeIterator(env, locale, UBRK_CHARACTER); 131 } 132 133 static jint NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring locale) { 134 return makeIterator(env, locale, UBRK_LINE); 135 } 136 137 static jint NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring locale) { 138 return makeIterator(env, locale, UBRK_SENTENCE); 139 } 140 141 static jint NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring locale) { 142 return makeIterator(env, locale, UBRK_WORD); 143 } 144 145 static void NativeBreakIterator_closeBreakIteratorImpl(JNIEnv* env, jclass, jint address) { 146 BreakIteratorPeer* peer = BreakIteratorPeer::fromAddress(address); 147 peer->close(env); 148 delete peer; 149 } 150 151 static jint NativeBreakIterator_cloneImpl(JNIEnv* env, jclass, jint address) { 152 return BreakIteratorPeer::fromAddress(address)->clone(env)->toAddress(); 153 } 154 155 static void NativeBreakIterator_setTextImpl(JNIEnv* env, jclass, jint address, jstring javaText) { 156 BreakIteratorPeer* peer = BreakIteratorPeer::fromAddress(address); 157 peer->setText(env, javaText); 158 } 159 160 static jboolean NativeBreakIterator_isBoundaryImpl(JNIEnv*, jclass, jint address, jint offset) { 161 return ubrk_isBoundary(breakIterator(address), offset); 162 } 163 164 static jint NativeBreakIterator_nextImpl(JNIEnv*, jclass, jint address, jint n) { 165 UBreakIterator* bi = breakIterator(address); 166 if (n < 0) { 167 while (n++ < -1) { 168 ubrk_previous(bi); 169 } 170 return ubrk_previous(bi); 171 } else if (n == 0) { 172 return ubrk_current(bi); 173 } else { 174 while (n-- > 1) { 175 ubrk_next(bi); 176 } 177 return ubrk_next(bi); 178 } 179 return -1; 180 } 181 182 static jint NativeBreakIterator_precedingImpl(JNIEnv*, jclass, jint address, jint offset) { 183 return ubrk_preceding(breakIterator(address), offset); 184 } 185 186 static jint NativeBreakIterator_firstImpl(JNIEnv*, jclass, jint address) { 187 return ubrk_first(breakIterator(address)); 188 } 189 190 static jint NativeBreakIterator_followingImpl(JNIEnv*, jclass, jint address, jint offset) { 191 return ubrk_following(breakIterator(address), offset); 192 } 193 194 static jint NativeBreakIterator_currentImpl(JNIEnv*, jclass, jint address) { 195 return ubrk_current(breakIterator(address)); 196 } 197 198 static jint NativeBreakIterator_previousImpl(JNIEnv*, jclass, jint address) { 199 return ubrk_previous(breakIterator(address)); 200 } 201 202 static jint NativeBreakIterator_lastImpl(JNIEnv*, jclass, jint address) { 203 return ubrk_last(breakIterator(address)); 204 } 205 206 static JNINativeMethod gMethods[] = { 207 NATIVE_METHOD(NativeBreakIterator, cloneImpl, "(I)I"), 208 NATIVE_METHOD(NativeBreakIterator, closeBreakIteratorImpl, "(I)V"), 209 NATIVE_METHOD(NativeBreakIterator, currentImpl, "(I)I"), 210 NATIVE_METHOD(NativeBreakIterator, firstImpl, "(I)I"), 211 NATIVE_METHOD(NativeBreakIterator, followingImpl, "(II)I"), 212 NATIVE_METHOD(NativeBreakIterator, getCharacterInstanceImpl, "(Ljava/lang/String;)I"), 213 NATIVE_METHOD(NativeBreakIterator, getLineInstanceImpl, "(Ljava/lang/String;)I"), 214 NATIVE_METHOD(NativeBreakIterator, getSentenceInstanceImpl, "(Ljava/lang/String;)I"), 215 NATIVE_METHOD(NativeBreakIterator, getWordInstanceImpl, "(Ljava/lang/String;)I"), 216 NATIVE_METHOD(NativeBreakIterator, isBoundaryImpl, "(II)Z"), 217 NATIVE_METHOD(NativeBreakIterator, lastImpl, "(I)I"), 218 NATIVE_METHOD(NativeBreakIterator, nextImpl, "(II)I"), 219 NATIVE_METHOD(NativeBreakIterator, precedingImpl, "(II)I"), 220 NATIVE_METHOD(NativeBreakIterator, previousImpl, "(I)I"), 221 NATIVE_METHOD(NativeBreakIterator, setTextImpl, "(ILjava/lang/String;)V"), 222 }; 223 int register_libcore_icu_NativeBreakIterator(JNIEnv* env) { 224 return jniRegisterNativeMethods(env, "libcore/icu/NativeBreakIterator", gMethods, NELEM(gMethods)); 225 } 226