1/* //device/libs/android_runtime/android_util_XmlBlock.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 "XmlBlock"
19
20#include "jni.h"
21#include "JNIHelp.h"
22#include <core_jni_helpers.h>
23#include <androidfw/AssetManager.h>
24#include <androidfw/ResourceTypes.h>
25#include <utils/Log.h>
26#include <utils/misc.h>
27
28#include <stdio.h>
29
30namespace android {
31
32// ----------------------------------------------------------------------------
33
34static jlong android_content_XmlBlock_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    ResXMLTree* osb = new ResXMLTree();
51    osb->setTo(b+off, len, true);
52    env->ReleaseByteArrayElements(bArray, b, 0);
53
54    if (osb->getError() != NO_ERROR) {
55        jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
56        return 0;
57    }
58
59    return reinterpret_cast<jlong>(osb);
60}
61
62static jlong android_content_XmlBlock_nativeGetStringBlock(JNIEnv* env, jobject clazz,
63                                                       jlong token)
64{
65    ResXMLTree* osb = reinterpret_cast<ResXMLTree*>(token);
66    if (osb == NULL) {
67        jniThrowNullPointerException(env, NULL);
68        return 0;
69    }
70
71    return reinterpret_cast<jlong>(&osb->getStrings());
72}
73
74static jlong android_content_XmlBlock_nativeCreateParseState(JNIEnv* env, jobject clazz,
75                                                          jlong token)
76{
77    ResXMLTree* osb = reinterpret_cast<ResXMLTree*>(token);
78    if (osb == NULL) {
79        jniThrowNullPointerException(env, NULL);
80        return 0;
81    }
82
83    ResXMLParser* st = new ResXMLParser(*osb);
84    if (st == NULL) {
85        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
86        return 0;
87    }
88
89    st->restart();
90
91    return reinterpret_cast<jlong>(st);
92}
93
94static jint android_content_XmlBlock_nativeNext(JNIEnv* env, jobject clazz,
95                                             jlong token)
96{
97    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
98    if (st == NULL) {
99        return ResXMLParser::END_DOCUMENT;
100    }
101
102    do {
103        ResXMLParser::event_code_t code = st->next();
104        switch (code) {
105            case ResXMLParser::START_TAG:
106                return 2;
107            case ResXMLParser::END_TAG:
108                return 3;
109            case ResXMLParser::TEXT:
110                return 4;
111            case ResXMLParser::START_DOCUMENT:
112                return 0;
113            case ResXMLParser::END_DOCUMENT:
114                return 1;
115            case ResXMLParser::BAD_DOCUMENT:
116                goto bad;
117            default:
118                break;
119        }
120    } while (true);
121
122bad:
123    jniThrowException(env, "org/xmlpull/v1/XmlPullParserException",
124            "Corrupt XML binary file");
125    return ResXMLParser::BAD_DOCUMENT;
126}
127
128static jint android_content_XmlBlock_nativeGetNamespace(JNIEnv* env, jobject clazz,
129                                                   jlong token)
130{
131    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
132    if (st == NULL) {
133        return -1;
134    }
135
136    return static_cast<jint>(st->getElementNamespaceID());
137}
138
139static jint android_content_XmlBlock_nativeGetName(JNIEnv* env, jobject clazz,
140                                                jlong token)
141{
142    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
143    if (st == NULL) {
144        return -1;
145    }
146
147    return static_cast<jint>(st->getElementNameID());
148}
149
150static jint android_content_XmlBlock_nativeGetText(JNIEnv* env, jobject clazz,
151                                                jlong token)
152{
153    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
154    if (st == NULL) {
155        return -1;
156    }
157
158    return static_cast<jint>(st->getTextID());
159}
160
161static jint android_content_XmlBlock_nativeGetLineNumber(JNIEnv* env, jobject clazz,
162                                                         jlong token)
163{
164    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
165    if (st == NULL) {
166        jniThrowNullPointerException(env, NULL);
167        return 0;
168    }
169
170    return static_cast<jint>(st->getLineNumber());
171}
172
173static jint android_content_XmlBlock_nativeGetAttributeCount(JNIEnv* env, jobject clazz,
174                                                          jlong token)
175{
176    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
177    if (st == NULL) {
178        jniThrowNullPointerException(env, NULL);
179        return 0;
180    }
181
182    return static_cast<jint>(st->getAttributeCount());
183}
184
185static jint android_content_XmlBlock_nativeGetAttributeNamespace(JNIEnv* env, jobject clazz,
186                                                                 jlong token, jint idx)
187{
188    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
189    if (st == NULL) {
190        jniThrowNullPointerException(env, NULL);
191        return 0;
192    }
193
194    return static_cast<jint>(st->getAttributeNamespaceID(idx));
195}
196
197static jint android_content_XmlBlock_nativeGetAttributeName(JNIEnv* env, jobject clazz,
198                                                         jlong token, jint idx)
199{
200    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
201    if (st == NULL) {
202        jniThrowNullPointerException(env, NULL);
203        return 0;
204    }
205
206    return static_cast<jint>(st->getAttributeNameID(idx));
207}
208
209static jint android_content_XmlBlock_nativeGetAttributeResource(JNIEnv* env, jobject clazz,
210                                                             jlong token, jint idx)
211{
212    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
213    if (st == NULL) {
214        jniThrowNullPointerException(env, NULL);
215        return 0;
216    }
217
218    return static_cast<jint>(st->getAttributeNameResID(idx));
219}
220
221static jint android_content_XmlBlock_nativeGetAttributeDataType(JNIEnv* env, jobject clazz,
222                                                                jlong token, jint idx)
223{
224    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
225    if (st == NULL) {
226        jniThrowNullPointerException(env, NULL);
227        return 0;
228    }
229
230    return static_cast<jint>(st->getAttributeDataType(idx));
231}
232
233static jint android_content_XmlBlock_nativeGetAttributeData(JNIEnv* env, jobject clazz,
234                                                            jlong token, jint idx)
235{
236    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
237    if (st == NULL) {
238        jniThrowNullPointerException(env, NULL);
239        return 0;
240    }
241
242    return static_cast<jint>(st->getAttributeData(idx));
243}
244
245static jint android_content_XmlBlock_nativeGetAttributeStringValue(JNIEnv* env, jobject clazz,
246                                                                   jlong token, jint idx)
247{
248    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
249    if (st == NULL) {
250        jniThrowNullPointerException(env, NULL);
251        return 0;
252    }
253
254    return static_cast<jint>(st->getAttributeValueStringID(idx));
255}
256
257static jint android_content_XmlBlock_nativeGetAttributeIndex(JNIEnv* env, jobject clazz,
258                                                             jlong token,
259                                                             jstring ns, jstring name)
260{
261    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
262    if (st == NULL || name == NULL) {
263        jniThrowNullPointerException(env, NULL);
264        return 0;
265    }
266
267    const char16_t* ns16 = NULL;
268    jsize nsLen = 0;
269    if (ns) {
270        ns16 = reinterpret_cast<const char16_t*>(env->GetStringChars(ns, NULL));
271        nsLen = env->GetStringLength(ns);
272    }
273
274    const char16_t* name16 = reinterpret_cast<const char16_t*>(
275        env->GetStringChars(name, NULL));
276    jsize nameLen = env->GetStringLength(name);
277
278    jint idx = static_cast<jint>(st->indexOfAttribute(ns16, nsLen, name16, nameLen));
279
280    if (ns) {
281        env->ReleaseStringChars(ns, reinterpret_cast<const jchar*>(ns16));
282    }
283    env->ReleaseStringChars(name, reinterpret_cast<const jchar*>(name16));
284
285    return idx;
286}
287
288static jint android_content_XmlBlock_nativeGetIdAttribute(JNIEnv* env, jobject clazz,
289                                                          jlong token)
290{
291    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
292    if (st == NULL) {
293        jniThrowNullPointerException(env, NULL);
294        return 0;
295    }
296
297    ssize_t idx = st->indexOfID();
298    return idx >= 0 ? static_cast<jint>(st->getAttributeValueStringID(idx)) : -1;
299}
300
301static jint android_content_XmlBlock_nativeGetClassAttribute(JNIEnv* env, jobject clazz,
302                                                             jlong token)
303{
304    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
305    if (st == NULL) {
306        jniThrowNullPointerException(env, NULL);
307        return 0;
308    }
309
310    ssize_t idx = st->indexOfClass();
311    return idx >= 0 ? static_cast<jint>(st->getAttributeValueStringID(idx)) : -1;
312}
313
314static jint android_content_XmlBlock_nativeGetStyleAttribute(JNIEnv* env, jobject clazz,
315                                                             jlong token)
316{
317    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
318    if (st == NULL) {
319        jniThrowNullPointerException(env, NULL);
320        return 0;
321    }
322
323    ssize_t idx = st->indexOfStyle();
324    if (idx < 0) {
325        return 0;
326    }
327
328    Res_value value;
329    if (st->getAttributeValue(idx, &value) < 0) {
330        return 0;
331    }
332
333    return value.dataType == value.TYPE_REFERENCE
334        || value.dataType == value.TYPE_ATTRIBUTE
335        ? value.data : 0;
336}
337
338static void android_content_XmlBlock_nativeDestroyParseState(JNIEnv* env, jobject clazz,
339                                                          jlong token)
340{
341    ResXMLParser* st = reinterpret_cast<ResXMLParser*>(token);
342    if (st == NULL) {
343        jniThrowNullPointerException(env, NULL);
344        return;
345    }
346
347    delete st;
348}
349
350static void android_content_XmlBlock_nativeDestroy(JNIEnv* env, jobject clazz,
351                                                   jlong token)
352{
353    ResXMLTree* osb = reinterpret_cast<ResXMLTree*>(token);
354    if (osb == NULL) {
355        jniThrowNullPointerException(env, NULL);
356        return;
357    }
358
359    delete osb;
360}
361
362// ----------------------------------------------------------------------------
363
364/*
365 * JNI registration.
366 */
367static JNINativeMethod gXmlBlockMethods[] = {
368    /* name, signature, funcPtr */
369    { "nativeCreate",               "([BII)J",
370            (void*) android_content_XmlBlock_nativeCreate },
371    { "nativeGetStringBlock",       "(J)J",
372            (void*) android_content_XmlBlock_nativeGetStringBlock },
373    { "nativeCreateParseState",     "(J)J",
374            (void*) android_content_XmlBlock_nativeCreateParseState },
375    { "nativeNext",                 "(J)I",
376            (void*) android_content_XmlBlock_nativeNext },
377    { "nativeGetNamespace",         "(J)I",
378            (void*) android_content_XmlBlock_nativeGetNamespace },
379    { "nativeGetName",              "(J)I",
380            (void*) android_content_XmlBlock_nativeGetName },
381    { "nativeGetText",              "(J)I",
382            (void*) android_content_XmlBlock_nativeGetText },
383    { "nativeGetLineNumber",        "(J)I",
384            (void*) android_content_XmlBlock_nativeGetLineNumber },
385    { "nativeGetAttributeCount",    "(J)I",
386            (void*) android_content_XmlBlock_nativeGetAttributeCount },
387    { "nativeGetAttributeNamespace","(JI)I",
388            (void*) android_content_XmlBlock_nativeGetAttributeNamespace },
389    { "nativeGetAttributeName",     "(JI)I",
390            (void*) android_content_XmlBlock_nativeGetAttributeName },
391    { "nativeGetAttributeResource", "(JI)I",
392            (void*) android_content_XmlBlock_nativeGetAttributeResource },
393    { "nativeGetAttributeDataType", "(JI)I",
394            (void*) android_content_XmlBlock_nativeGetAttributeDataType },
395    { "nativeGetAttributeData",    "(JI)I",
396            (void*) android_content_XmlBlock_nativeGetAttributeData },
397    { "nativeGetAttributeStringValue", "(JI)I",
398            (void*) android_content_XmlBlock_nativeGetAttributeStringValue },
399    { "nativeGetAttributeIndex",    "(JLjava/lang/String;Ljava/lang/String;)I",
400            (void*) android_content_XmlBlock_nativeGetAttributeIndex },
401    { "nativeGetIdAttribute",      "(J)I",
402            (void*) android_content_XmlBlock_nativeGetIdAttribute },
403    { "nativeGetClassAttribute",   "(J)I",
404            (void*) android_content_XmlBlock_nativeGetClassAttribute },
405    { "nativeGetStyleAttribute",   "(J)I",
406            (void*) android_content_XmlBlock_nativeGetStyleAttribute },
407    { "nativeDestroyParseState",    "(J)V",
408            (void*) android_content_XmlBlock_nativeDestroyParseState },
409    { "nativeDestroy",              "(J)V",
410            (void*) android_content_XmlBlock_nativeDestroy },
411};
412
413int register_android_content_XmlBlock(JNIEnv* env)
414{
415    return RegisterMethodsOrDie(env,
416            "android/content/res/XmlBlock", gXmlBlockMethods, NELEM(gXmlBlockMethods));
417}
418
419}; // namespace android
420