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