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 <android_runtime/AndroidRuntime.h>
24#include <utils/Log.h>
25
26#include <androidfw/ResourceTypes.h>
27
28#include <stdio.h>
29
30namespace android {
31
32// ----------------------------------------------------------------------------
33
34static jint 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        return 0;
56    }
57
58    return (jint)osb;
59}
60
61static jint android_content_StringBlock_nativeGetSize(JNIEnv* env, jobject clazz,
62                                                   jint token)
63{
64    ResStringPool* osb = (ResStringPool*)token;
65    if (osb == NULL) {
66        jniThrowNullPointerException(env, NULL);
67        return 0;
68    }
69
70    return osb->size();
71}
72
73static jstring android_content_StringBlock_nativeGetString(JNIEnv* env, jobject clazz,
74                                                        jint token, jint idx)
75{
76    ResStringPool* osb = (ResStringPool*)token;
77    if (osb == NULL) {
78        jniThrowNullPointerException(env, NULL);
79        return 0;
80    }
81
82    size_t len;
83    const char* str8 = osb->string8At(idx, &len);
84    if (str8 != NULL) {
85        return env->NewStringUTF(str8);
86    }
87
88    const char16_t* str = osb->stringAt(idx, &len);
89    if (str == NULL) {
90        jniThrowException(env, "java/lang/IndexOutOfBoundsException", NULL);
91        return 0;
92    }
93
94    return env->NewString((const jchar*)str, len);
95}
96
97static jintArray android_content_StringBlock_nativeGetStyle(JNIEnv* env, jobject clazz,
98                                                         jint token, jint idx)
99{
100    ResStringPool* osb = (ResStringPool*)token;
101    if (osb == NULL) {
102        jniThrowNullPointerException(env, NULL);
103        return NULL;
104    }
105
106    const ResStringPool_span* spans = osb->styleAt(idx);
107    if (spans == NULL) {
108        return NULL;
109    }
110
111    const ResStringPool_span* pos = spans;
112    int num = 0;
113    while (pos->name.index != ResStringPool_span::END) {
114        num++;
115        pos++;
116    }
117
118    if (num == 0) {
119        return NULL;
120    }
121
122    jintArray array = env->NewIntArray((num*sizeof(ResStringPool_span))/sizeof(jint));
123    if (array == NULL) { // NewIntArray already threw OutOfMemoryError.
124        return NULL;
125    }
126
127    num = 0;
128    static const int numInts = sizeof(ResStringPool_span)/sizeof(jint);
129    while (spans->name.index != ResStringPool_span::END) {
130        env->SetIntArrayRegion(array,
131                                  num*numInts, numInts,
132                                  (jint*)spans);
133        spans++;
134        num++;
135    }
136
137    return array;
138}
139
140static void android_content_StringBlock_nativeDestroy(JNIEnv* env, jobject clazz,
141                                                   jint token)
142{
143    ResStringPool* osb = (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 */
157static JNINativeMethod gStringBlockMethods[] = {
158    /* name, signature, funcPtr */
159    { "nativeCreate",      "([BII)I",
160            (void*) android_content_StringBlock_nativeCreate },
161    { "nativeGetSize",      "(I)I",
162            (void*) android_content_StringBlock_nativeGetSize },
163    { "nativeGetString",    "(II)Ljava/lang/String;",
164            (void*) android_content_StringBlock_nativeGetString },
165    { "nativeGetStyle",    "(II)[I",
166            (void*) android_content_StringBlock_nativeGetStyle },
167    { "nativeDestroy",      "(I)V",
168            (void*) android_content_StringBlock_nativeDestroy },
169};
170
171int register_android_content_StringBlock(JNIEnv* env)
172{
173    return AndroidRuntime::registerNativeMethods(env,
174            "android/content/res/StringBlock", gStringBlockMethods, NELEM(gStringBlockMethods));
175}
176
177}; // namespace android
178