1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Internal native functions.  All of the functions defined here make
5 * direct use of VM functions or data structures, so they can't be written
6 * with JNI and shouldn't really be in a shared library.
7 *
8 * All functions here either complete quickly or are used to enter a wait
9 * state, so we don't set the thread status to THREAD_NATIVE when executing
10 * these methods.  This means that the GC will wait for these functions
11 * to finish.  DO NOT perform long operations or blocking I/O in here.
12 *
13 * In some cases we're following the division of labor defined by GNU
14 * ClassPath, e.g. java.lang.Thread has "Thread" and "VMThread", with
15 * the VM-specific behavior isolated in VMThread.
16 */
17
18#include "JNIHelp.h"
19#include "AndroidSystemNatives.h"
20#include "ErrorCode.h"
21#include "unicode/ubrk.h"
22#include "unicode/putil.h"
23#include <stdlib.h>
24
25static jstring getAvailableLocalesImpl(JNIEnv *env, jclass clazz, jint index) {
26
27    const char * locale = ubrk_getAvailable(index);
28
29    return (*env)->NewStringUTF(env, locale);
30
31}
32
33static jint getAvailableLocalesCountImpl(JNIEnv *env, jclass clazz) {
34    return ubrk_countAvailable();
35}
36
37static jint getCharacterInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
38
39    UErrorCode status = U_ZERO_ERROR;
40
41    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
42
43    UBreakIterator *iter = ubrk_open(UBRK_CHARACTER, localeChars, NULL, 0, &status);
44
45    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
46
47    if ( icu4jni_error(env, status) != FALSE) {
48        return 0;
49    }
50
51    return (long) iter;
52}
53
54static jint getLineInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
55
56    UErrorCode status = U_ZERO_ERROR;
57
58    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
59
60    enum UBreakIteratorType type = UBRK_LINE;
61
62    UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
63
64    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
65
66    if ( icu4jni_error(env, status) != FALSE) {
67        return 0;
68    }
69
70    return (long) iter;
71}
72
73static jint getSentenceInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
74
75    UErrorCode status = U_ZERO_ERROR;
76
77    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
78
79    enum UBreakIteratorType type = UBRK_SENTENCE;
80
81    UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
82
83    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
84
85    if ( icu4jni_error(env, status) != FALSE) {
86        return 0;
87    }
88
89    return (long) iter;
90}
91
92static jint getWordInstanceImpl(JNIEnv *env, jclass clazz, jstring locale) {
93
94    UErrorCode status = U_ZERO_ERROR;
95
96    const char *localeChars = (*env)->GetStringUTFChars(env, locale, 0);
97
98    enum UBreakIteratorType type = UBRK_WORD;
99
100    UBreakIterator *iter = ubrk_open(type, localeChars, NULL, 0, &status);
101
102    (*env)->ReleaseStringUTFChars(env, locale, localeChars);
103
104    if ( icu4jni_error(env, status) != FALSE) {
105        return 0;
106    }
107
108    return (long) iter;
109}
110
111static void closeBreakIteratorImpl(JNIEnv *env, jclass clazz, jint address) {
112
113    UBreakIterator *bi = (UBreakIterator *)(long)address;
114
115    ubrk_close(bi);
116}
117
118static jint cloneImpl(JNIEnv *env, jclass clazz, jint address) {
119
120    UErrorCode status = U_ZERO_ERROR;
121
122    UBreakIterator *bi = (UBreakIterator *)(long)address;
123
124    jint buffersize = U_BRK_SAFECLONE_BUFFERSIZE;
125
126    UBreakIterator *iter = ubrk_safeClone(bi, NULL, &buffersize, &status);
127
128    if (icu4jni_error(env, status) != FALSE) {
129        return 0;
130    }
131
132    return (long) iter;
133}
134
135static void setTextImpl(JNIEnv *env, jclass clazz, jint address, jstring text) {
136
137    UErrorCode status = U_ZERO_ERROR;
138
139    UBreakIterator *bi = (UBreakIterator *)(long)address;
140
141    const UChar *strUChars = (*env)->GetStringChars(env, text, NULL);
142    int strLen = (*env)->GetStringLength(env, text);
143
144    ubrk_setText(bi, strUChars, strLen, &status);
145
146    (*env)->ReleaseStringChars(env, text, strUChars);
147
148    icu4jni_error(env, status);
149}
150
151static jboolean isBoundaryImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
152
153    UBreakIterator *bi = (UBreakIterator *)(long)address;
154
155    return ubrk_isBoundary(bi, offset);
156}
157
158static jint nextImpl(JNIEnv *env, jclass clazz, jint address, jint n) {
159
160    UBreakIterator *bi = (UBreakIterator *)(long)address;
161
162    if(n < 0) {
163        while(n++ < -1) {
164            ubrk_previous(bi);
165        }
166        return ubrk_previous(bi);
167    } else if(n == 0) {
168        return ubrk_current(bi);
169    } else {
170        while(n-- > 1) {
171            ubrk_next(bi);
172        }
173        return ubrk_next(bi);
174    }
175
176    return -1;
177}
178
179static jint precedingImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
180
181    UBreakIterator *bi = (UBreakIterator *)(long)address;
182
183    return ubrk_preceding(bi, offset);
184}
185
186static jint firstImpl(JNIEnv *env, jclass clazz, jint address) {
187
188    UBreakIterator *bi = (UBreakIterator *)(long)address;
189
190    return ubrk_first(bi);
191}
192
193static jint followingImpl(JNIEnv *env, jclass clazz, jint address, jint offset) {
194
195    UBreakIterator *bi = (UBreakIterator *)(long)address;
196
197    return ubrk_following(bi, offset);
198}
199
200static jint currentImpl(JNIEnv *env, jclass clazz, jint address) {
201
202    UBreakIterator *bi = (UBreakIterator *)(long)address;
203
204    return ubrk_current(bi);
205}
206
207static jint previousImpl(JNIEnv *env, jclass clazz, jint address) {
208
209    UBreakIterator *bi = (UBreakIterator *)(long)address;
210
211    return ubrk_previous(bi);
212}
213
214static jint lastImpl(JNIEnv *env, jclass clazz, jint address) {
215
216    UBreakIterator *bi = (UBreakIterator *)(long)address;
217
218    return ubrk_last(bi);
219}
220
221/*
222 * JNI registration
223 */
224static JNINativeMethod gMethods[] = {
225    /* name, signature, funcPtr */
226    { "getAvailableLocalesImpl", "(I)Ljava/lang/String;",
227            (void*) getAvailableLocalesImpl },
228    { "getAvailableLocalesCountImpl", "()I",
229            (void*) getAvailableLocalesCountImpl },
230    { "getCharacterInstanceImpl", "(Ljava/lang/String;)I",
231            (void*) getCharacterInstanceImpl },
232    { "getLineInstanceImpl", "(Ljava/lang/String;)I",
233            (void*) getLineInstanceImpl },
234    { "getSentenceInstanceImpl", "(Ljava/lang/String;)I",
235            (void*) getSentenceInstanceImpl },
236    { "getWordInstanceImpl", "(Ljava/lang/String;)I",
237            (void*) getWordInstanceImpl },
238    { "closeBreakIteratorImpl", "(I)V",
239            (void*) closeBreakIteratorImpl },
240    { "cloneImpl", "(I)I",
241            (void*) cloneImpl },
242    { "setTextImpl", "(ILjava/lang/String;)V",
243            (void*) setTextImpl },
244    { "isBoundaryImpl", "(II)Z",
245            (void*) isBoundaryImpl },
246    { "nextImpl", "(II)I",
247            (void*) nextImpl },
248    { "precedingImpl", "(II)I",
249            (void*) precedingImpl },
250    { "firstImpl", "(I)I",
251            (void*) firstImpl },
252    { "lastImpl", "(I)I",
253            (void*) lastImpl },
254    { "currentImpl", "(I)I",
255            (void*) currentImpl },
256    { "followingImpl", "(II)I",
257            (void*) followingImpl },
258    { "previousImpl", "(I)I",
259            (void*) previousImpl },
260};
261int register_com_ibm_icu4jni_text_NativeBreakIterator(JNIEnv* env) {
262    return jniRegisterNativeMethods(env, "com/ibm/icu4jni/text/NativeBreakIterator",
263                gMethods, NELEM(gMethods));
264}
265