Home | History | Annotate | Download | only in native
      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