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