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