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 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 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 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 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 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 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