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