• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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