• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "IcuUtilities.h"
20 #include "JNIHelp.h"
21 #include "JniConstants.h"
22 #include "JniException.h"
23 #include "ScopedUtfChars.h"
24 #include "unicode/brkiter.h"
25 #include "unicode/putil.h"
26 #include <stdlib.h>
27 
28 // ICU documentation: http://icu-project.org/apiref/icu4c/classBreakIterator.html
29 
toBreakIterator(jint address)30 static BreakIterator* toBreakIterator(jint address) {
31   return reinterpret_cast<BreakIterator*>(static_cast<uintptr_t>(address));
32 }
33 
34 /**
35  * We use ICU4C's BreakIterator class, but our input is on the Java heap and potentially moving
36  * around between calls. This wrapper class ensures that our RegexMatcher is always pointing at
37  * the current location of the char[]. Earlier versions of Android simply copied the data to the
38  * native heap, but that's wasteful and hides allocations from the garbage collector.
39  */
40 class BreakIteratorAccessor {
41  public:
BreakIteratorAccessor(JNIEnv * env,jint address,jstring javaInput,bool reset)42   BreakIteratorAccessor(JNIEnv* env, jint address, jstring javaInput, bool reset) {
43     init(env, address);
44     mJavaInput = javaInput;
45 
46     if (mJavaInput == NULL) {
47       return;
48     }
49 
50     mChars = env->GetStringChars(mJavaInput, NULL);
51     if (mChars == NULL) {
52       return;
53     }
54 
55     mUText = utext_openUChars(NULL, mChars, env->GetStringLength(mJavaInput), &mStatus);
56     if (mUText == NULL) {
57       return;
58     }
59 
60     if (reset) {
61       mBreakIterator->setText(mUText, mStatus);
62     } else {
63       mBreakIterator->refreshInputText(mUText, mStatus);
64     }
65   }
66 
BreakIteratorAccessor(JNIEnv * env,jint address)67   BreakIteratorAccessor(JNIEnv* env, jint address) {
68     init(env, address);
69   }
70 
~BreakIteratorAccessor()71   ~BreakIteratorAccessor() {
72     utext_close(mUText);
73     if (mJavaInput) {
74       mEnv->ReleaseStringChars(mJavaInput, mChars);
75     }
76     maybeThrowIcuException(mEnv, "utext_close", mStatus);
77   }
78 
operator ->()79   BreakIterator* operator->() {
80     return mBreakIterator;
81   }
82 
status()83   UErrorCode& status() {
84     return mStatus;
85   }
86 
87  private:
init(JNIEnv * env,jint address)88   void init(JNIEnv* env, jint address) {
89     mEnv = env;
90     mJavaInput = NULL;
91     mBreakIterator = toBreakIterator(address);
92     mChars = NULL;
93     mStatus = U_ZERO_ERROR;
94     mUText = NULL;
95   }
96 
97   JNIEnv* mEnv;
98   jstring mJavaInput;
99   BreakIterator* mBreakIterator;
100   const jchar* mChars;
101   UErrorCode mStatus;
102   UText* mUText;
103 
104   // Disallow copy and assignment.
105   BreakIteratorAccessor(const BreakIteratorAccessor&);
106   void operator=(const BreakIteratorAccessor&);
107 };
108 
109 #define MAKE_BREAK_ITERATOR_INSTANCE(F) \
110   UErrorCode status = U_ZERO_ERROR; \
111   const ScopedUtfChars localeChars(env, javaLocale); \
112   if (localeChars.c_str() == NULL) { \
113     return 0; \
114   } \
115   Locale locale(Locale::createFromName(localeChars.c_str())); \
116   BreakIterator* it = F(locale, status); \
117   if (maybeThrowIcuException(env, "ubrk_open", status)) { \
118     return 0; \
119   } \
120   return reinterpret_cast<uintptr_t>(it)
121 
NativeBreakIterator_cloneImpl(JNIEnv * env,jclass,jint address)122 static jint NativeBreakIterator_cloneImpl(JNIEnv* env, jclass, jint address) {
123   BreakIteratorAccessor it(env, address);
124   return reinterpret_cast<uintptr_t>(it->clone());
125 }
126 
NativeBreakIterator_closeImpl(JNIEnv *,jclass,jint address)127 static void NativeBreakIterator_closeImpl(JNIEnv*, jclass, jint address) {
128   delete toBreakIterator(address);
129 }
130 
NativeBreakIterator_currentImpl(JNIEnv * env,jclass,jint address,jstring javaInput)131 static jint NativeBreakIterator_currentImpl(JNIEnv* env, jclass, jint address, jstring javaInput) {
132   BreakIteratorAccessor it(env, address, javaInput, false);
133   return it->current();
134 }
135 
NativeBreakIterator_firstImpl(JNIEnv * env,jclass,jint address,jstring javaInput)136 static jint NativeBreakIterator_firstImpl(JNIEnv* env, jclass, jint address, jstring javaInput) {
137   BreakIteratorAccessor it(env, address, javaInput, false);
138   return it->first();
139 }
140 
NativeBreakIterator_followingImpl(JNIEnv * env,jclass,jint address,jstring javaInput,jint offset)141 static jint NativeBreakIterator_followingImpl(JNIEnv* env, jclass, jint address, jstring javaInput, jint offset) {
142   BreakIteratorAccessor it(env, address, javaInput, false);
143   return it->following(offset);
144 }
145 
NativeBreakIterator_getCharacterInstanceImpl(JNIEnv * env,jclass,jstring javaLocale)146 static jint NativeBreakIterator_getCharacterInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
147   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createCharacterInstance);
148 }
149 
NativeBreakIterator_getLineInstanceImpl(JNIEnv * env,jclass,jstring javaLocale)150 static jint NativeBreakIterator_getLineInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
151   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createLineInstance);
152 }
153 
NativeBreakIterator_getSentenceInstanceImpl(JNIEnv * env,jclass,jstring javaLocale)154 static jint NativeBreakIterator_getSentenceInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
155   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createSentenceInstance);
156 }
157 
NativeBreakIterator_getWordInstanceImpl(JNIEnv * env,jclass,jstring javaLocale)158 static jint NativeBreakIterator_getWordInstanceImpl(JNIEnv* env, jclass, jstring javaLocale) {
159   MAKE_BREAK_ITERATOR_INSTANCE(BreakIterator::createWordInstance);
160 }
161 
NativeBreakIterator_isBoundaryImpl(JNIEnv * env,jclass,jint address,jstring javaInput,jint offset)162 static jboolean NativeBreakIterator_isBoundaryImpl(JNIEnv* env, jclass, jint address, jstring javaInput, jint offset) {
163   BreakIteratorAccessor it(env, address, javaInput, false);
164   return it->isBoundary(offset);
165 }
166 
NativeBreakIterator_lastImpl(JNIEnv * env,jclass,jint address,jstring javaInput)167 static jint NativeBreakIterator_lastImpl(JNIEnv* env, jclass, jint address, jstring javaInput) {
168   BreakIteratorAccessor it(env, address, javaInput, false);
169   return it->last();
170 }
171 
NativeBreakIterator_nextImpl(JNIEnv * env,jclass,jint address,jstring javaInput,jint n)172 static jint NativeBreakIterator_nextImpl(JNIEnv* env, jclass, jint address, jstring javaInput, jint n) {
173   BreakIteratorAccessor it(env, address, javaInput, false);
174   if (n < 0) {
175     while (n++ < -1) {
176       it->previous();
177     }
178     return it->previous();
179   } else if (n == 0) {
180     return it->current();
181   } else {
182     while (n-- > 1) {
183       it->next();
184     }
185     return it->next();
186   }
187   return -1;
188 }
189 
NativeBreakIterator_precedingImpl(JNIEnv * env,jclass,jint address,jstring javaInput,jint offset)190 static jint NativeBreakIterator_precedingImpl(JNIEnv* env, jclass, jint address, jstring javaInput, jint offset) {
191   BreakIteratorAccessor it(env, address, javaInput, false);
192   return it->preceding(offset);
193 }
194 
NativeBreakIterator_previousImpl(JNIEnv * env,jclass,jint address,jstring javaInput)195 static jint NativeBreakIterator_previousImpl(JNIEnv* env, jclass, jint address, jstring javaInput) {
196   BreakIteratorAccessor it(env, address, javaInput, false);
197   return it->previous();
198 }
199 
NativeBreakIterator_setTextImpl(JNIEnv * env,jclass,jint address,jstring javaInput)200 static void NativeBreakIterator_setTextImpl(JNIEnv* env, jclass, jint address, jstring javaInput) {
201   BreakIteratorAccessor it(env, address, javaInput, true);
202 }
203 
204 static JNINativeMethod gMethods[] = {
205   NATIVE_METHOD(NativeBreakIterator, cloneImpl, "(I)I"),
206   NATIVE_METHOD(NativeBreakIterator, closeImpl, "(I)V"),
207   NATIVE_METHOD(NativeBreakIterator, currentImpl, "(ILjava/lang/String;)I"),
208   NATIVE_METHOD(NativeBreakIterator, firstImpl, "(ILjava/lang/String;)I"),
209   NATIVE_METHOD(NativeBreakIterator, followingImpl, "(ILjava/lang/String;I)I"),
210   NATIVE_METHOD(NativeBreakIterator, getCharacterInstanceImpl, "(Ljava/lang/String;)I"),
211   NATIVE_METHOD(NativeBreakIterator, getLineInstanceImpl, "(Ljava/lang/String;)I"),
212   NATIVE_METHOD(NativeBreakIterator, getSentenceInstanceImpl, "(Ljava/lang/String;)I"),
213   NATIVE_METHOD(NativeBreakIterator, getWordInstanceImpl, "(Ljava/lang/String;)I"),
214   NATIVE_METHOD(NativeBreakIterator, isBoundaryImpl, "(ILjava/lang/String;I)Z"),
215   NATIVE_METHOD(NativeBreakIterator, lastImpl, "(ILjava/lang/String;)I"),
216   NATIVE_METHOD(NativeBreakIterator, nextImpl, "(ILjava/lang/String;I)I"),
217   NATIVE_METHOD(NativeBreakIterator, precedingImpl, "(ILjava/lang/String;I)I"),
218   NATIVE_METHOD(NativeBreakIterator, previousImpl, "(ILjava/lang/String;)I"),
219   NATIVE_METHOD(NativeBreakIterator, setTextImpl, "(ILjava/lang/String;)V"),
220 };
register_libcore_icu_NativeBreakIterator(JNIEnv * env)221 void register_libcore_icu_NativeBreakIterator(JNIEnv* env) {
222   jniRegisterNativeMethods(env, "libcore/icu/NativeBreakIterator", gMethods, NELEM(gMethods));
223 }
224