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