1 /* //device/libs/android_runtime/android_util_StringBlock.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 ** http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17
18 #define LOG_TAG "StringBlock"
19
20 #include "jni.h"
21 #include <utils/misc.h>
22 #include <android_runtime/AndroidRuntime.h>
23 #include <utils/Log.h>
24
25 #include <utils/ResourceTypes.h>
26
27 #include <stdio.h>
28
29 namespace android {
30
31 // ----------------------------------------------------------------------------
32
doThrow(JNIEnv * env,const char * exc,const char * msg=NULL)33 static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
34 {
35 jclass npeClazz;
36
37 npeClazz = env->FindClass(exc);
38 LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
39
40 env->ThrowNew(npeClazz, msg);
41 }
42
android_content_StringBlock_nativeCreate(JNIEnv * env,jobject clazz,jbyteArray bArray,jint off,jint len)43 static jint android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz,
44 jbyteArray bArray,
45 jint off, jint len)
46 {
47 if (bArray == NULL) {
48 doThrow(env, "java/lang/NullPointerException");
49 return 0;
50 }
51
52 jsize bLen = env->GetArrayLength(bArray);
53 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
54 doThrow(env, "java/lang/IndexOutOfBoundsException");
55 return 0;
56 }
57
58 jbyte* b = env->GetByteArrayElements(bArray, NULL);
59 ResStringPool* osb = new ResStringPool(b+off, len, true);
60 env->ReleaseByteArrayElements(bArray, b, 0);
61
62 if (osb == NULL || osb->getError() != NO_ERROR) {
63 doThrow(env, "java/lang/IllegalArgumentException");
64 return 0;
65 }
66
67 return (jint)osb;
68 }
69
android_content_StringBlock_nativeGetSize(JNIEnv * env,jobject clazz,jint token)70 static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
71 jint token)
72 {
73 ResStringPool* osb = (ResStringPool*)token;
74 if (osb == NULL) {
75 doThrow(env, "java/lang/NullPointerException");
76 return 0;
77 }
78
79 return osb->size();
80 }
81
android_content_StringBlock_nativeGetString(JNIEnv * env,jobject clazz,jint token,jint idx)82 static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
83 jint token, jint idx)
84 {
85 ResStringPool* osb = (ResStringPool*)token;
86 if (osb == NULL) {
87 doThrow(env, "java/lang/NullPointerException");
88 return 0;
89 }
90
91 size_t len;
92 const char16_t* str = osb->stringAt(idx, &len);
93 if (str == NULL) {
94 doThrow(env, "java/lang/IndexOutOfBoundsException");
95 return 0;
96 }
97
98 return env->NewString((const jchar*)str, len);
99 }
100
android_content_StringBlock_nativeGetStyle(JNIEnv * env,jobject clazz,jint token,jint idx)101 static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
102 jint token, jint idx)
103 {
104 ResStringPool* osb = (ResStringPool*)token;
105 if (osb == NULL) {
106 doThrow(env, "java/lang/NullPointerException");
107 return NULL;
108 }
109
110 const ResStringPool_span* spans = osb->styleAt(idx);
111 if (spans == NULL) {
112 return NULL;
113 }
114
115 const ResStringPool_span* pos = spans;
116 int num = 0;
117 while (pos->name.index != ResStringPool_span::END) {
118 num++;
119 pos++;
120 }
121
122 if (num == 0) {
123 return NULL;
124 }
125
126 jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
127 if (array == NULL) {
128 doThrow(env, "java/lang/OutOfMemoryError");
129 return NULL;
130 }
131
132 num = 0;
133 static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
134 while (spans->name.index != ResStringPool_span::END) {
135 env->SetIntArrayRegion(array,
136 num*numInts, numInts,
137 (jint*)spans);
138 spans++;
139 num++;
140 }
141
142 return array;
143 }
144
android_content_StringBlock_nativeIndexOfString(JNIEnv * env,jobject clazz,jint token,jstring str)145 static jint android_content_StringBlock_nativeIndexOfString(JNIEnv* env, jobject clazz,
146 jint token, jstring str)
147 {
148 ResStringPool* osb = (ResStringPool*)token;
149 if (osb == NULL || str == NULL) {
150 doThrow(env, "java/lang/NullPointerException");
151 return 0;
152 }
153
154 const char16_t* str16 = env->GetStringChars(str, NULL);
155 jsize strLen = env->GetStringLength(str);
156
157 ssize_t idx = osb->indexOfString(str16, strLen);
158
159 env->ReleaseStringChars(str, str16);
160
161 return idx;
162 }
163
android_content_StringBlock_nativeDestroy(JNIEnv * env,jobject clazz,jint token)164 static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
165 jint token)
166 {
167 ResStringPool* osb = (ResStringPool*)token;
168 if (osb == NULL) {
169 doThrow(env, "java/lang/NullPointerException");
170 return;
171 }
172
173 delete osb;
174 }
175
176 // ----------------------------------------------------------------------------
177
178 /*
179 * JNI registration.
180 */
181 static JNINativeMethod gStringBlockMethods[] = {
182 /* name, signature, funcPtr */
183 { "nativeCreate", "([BII)I",
184 (void*) android_content_StringBlock_nativeCreate },
185 { "nativeGetSize", "(I)I",
186 (void*) android_content_StringBlock_nativeGetSize },
187 { "nativeGetString", "(II)Ljava/lang/String;",
188 (void*) android_content_StringBlock_nativeGetString },
189 { "nativeGetStyle", "(II)[I",
190 (void*) android_content_StringBlock_nativeGetStyle },
191 { "nativeIndexOfString","(ILjava/lang/String;)I",
192 (void*) android_content_StringBlock_nativeIndexOfString },
193 { "nativeDestroy", "(I)V",
194 (void*) android_content_StringBlock_nativeDestroy },
195 };
196
register_android_content_StringBlock(JNIEnv * env)197 int register_android_content_StringBlock(JNIEnv* env)
198 {
199 return AndroidRuntime::registerNativeMethods(env,
200 "android/content/res/StringBlock", gStringBlockMethods, NELEM(gStringBlockMethods));
201 }
202
203 }; // namespace android
204
205