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
30namespace android {
31
32// ----------------------------------------------------------------------------
33
34static 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
62static 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
74static 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
98static 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
141static 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 */
158static const 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
172int 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