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