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 "JNIHelp.h"
22 #include <utils/misc.h>
23 #include <core_jni_helpers.h>
24 #include <utils/Log.h>
25 
26 #include <androidfw/ResourceTypes.h>
27 
28 #include <stdio.h>
29 
30 namespace android {
31 
32 // ----------------------------------------------------------------------------
33 
android_content_StringBlock_nativeCreate(JNIEnv * env,jobject clazz,jbyteArray bArray,jint off,jint len)34 static jlong android_content_StringBlock_nativeCreate(JNIEnv* env, jobject clazz,
35                                                   jbyteArray bArray,
36                                                   jint off, jint len)
37 {
38     if (bArray == NULL) {
39         jniThrowNullPointerException(env, NULL);
40         return 0;
41     }
42 
43     jsize bLen = env->GetArrayLength(bArray);
44     if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
45         jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
46         return 0;
47     }
48 
49     jbyte* b = env->GetByteArrayElements(bArray, NULL);
50     ResStringPool* osb = new ResStringPool(b+off, len, true);
51     env->ReleaseByteArrayElements(bArray, b, 0);
52 
53     if (osb == NULL || osb->getError() != NO_ERROR) {
54         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
55         delete osb;
56         return 0;
57     }
58 
59     return reinterpret_cast<jlong>(osb);
60 }
61 
android_content_StringBlock_nativeGetSize(JNIEnv * env,jobject clazz,jlong token)62 static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
63                                                    jlong token)
64 {
65     ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
66     if (osb == NULL) {
67         jniThrowNullPointerException(env, NULL);
68         return 0;
69     }
70 
71     return osb->size();
72 }
73 
android_content_StringBlock_nativeGetString(JNIEnv * env,jobject clazz,jlong token,jint idx)74 static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
75                                                         jlong token, jint idx)
76 {
77     ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
78     if (osb == NULL) {
79         jniThrowNullPointerException(env, NULL);
80         return 0;
81     }
82 
83     size_t len;
84     const char* str8 = osb->string8At(idx, &len);
85     if (str8 != NULL) {
86         return env->NewStringUTF(str8);
87     }
88 
89     const char16_t* str = osb->stringAt(idx, &len);
90     if (str == NULL) {
91         jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
92         return 0;
93     }
94 
95     return env->NewString((const jchar*)str, len);
96 }
97 
android_content_StringBlock_nativeGetStyle(JNIEnv * env,jobject clazz,jlong token,jint idx)98 static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
99                                                          jlong token, jint idx)
100 {
101     ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
102     if (osb == NULL) {
103         jniThrowNullPointerException(env, NULL);
104         return NULL;
105     }
106 
107     const ResStringPool_span* spans = osb->styleAt(idx);
108     if (spans == NULL) {
109         return NULL;
110     }
111 
112     const ResStringPool_span* pos = spans;
113     int num = 0;
114     while (pos->name.index != ResStringPool_span::END) {
115         num++;
116         pos++;
117     }
118 
119     if (num == 0) {
120         return NULL;
121     }
122 
123     jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
124     if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
125         return NULL;
126     }
127 
128     num = 0;
129     static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
130     while (spans->name.index != ResStringPool_span::END) {
131         env->SetIntArrayRegion(array,
132                                   num*numInts, numInts,
133                                   (jint*)spans);
134         spans++;
135         num++;
136     }
137 
138     return array;
139 }
140 
android_content_StringBlock_nativeDestroy(JNIEnv * env,jobject clazz,jlong token)141 static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
142                                                    jlong token)
143 {
144     ResStringPool* osb = reinterpret_cast<ResStringPool*>(token);
145     if (osb == NULL) {
146         jniThrowNullPointerException(env, NULL);
147         return;
148     }
149 
150     delete osb;
151 }
152 
153 // ----------------------------------------------------------------------------
154 
155 /*
156  * JNI registration.
157  */
158 static JNINativeMethod gStringBlockMethods[] = {
159     /* name, signature, funcPtr */
160     { "nativeCreate",      "([BII)J",
161             (void*) android_content_StringBlock_nativeCreate },
162     { "nativeGetSize",      "(J)I",
163             (void*) android_content_StringBlock_nativeGetSize },
164     { "nativeGetString",    "(JI)Ljava/lang/String;",
165             (void*) android_content_StringBlock_nativeGetString },
166     { "nativeGetStyle",    "(JI)[I",
167             (void*) android_content_StringBlock_nativeGetStyle },
168     { "nativeDestroy",      "(J)V",
169             (void*) android_content_StringBlock_nativeDestroy },
170 };
171 
register_android_content_StringBlock(JNIEnv * env)172 int register_android_content_StringBlock(JNIEnv* env)
173 {
174     return RegisterMethodsOrDie(env,
175             "android/content/res/StringBlock", gStringBlockMethods, NELEM(gStringBlockMethods));
176 }
177 
178 }; // namespace android
179