blob: 7146667472ab3fc4daefcd197cd0da0089a2da7b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_util_AssetManager.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Elliott Hughes69a017b2011-04-08 14:10:28 -07005** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008**
Elliott Hughes69a017b2011-04-08 14:10:28 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Elliott Hughes69a017b2011-04-08 14:10:28 -070011** 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
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
18#define LOG_TAG "asset"
19
Dianne Hackbornb8d81672009-11-20 14:26:42 -080020#define DEBUG_STYLES(x) //x
Dianne Hackborn20cb56e2010-03-04 00:58:29 -080021#define THROW_ON_BAD_ID 0
Dianne Hackbornb8d81672009-11-20 14:26:42 -080022
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080023#include <android_runtime/android_util_AssetManager.h>
24
25#include "jni.h"
26#include "JNIHelp.h"
Elliott Hughes69a017b2011-04-08 14:10:28 -070027#include "ScopedStringChars.h"
28#include "ScopedUtfChars.h"
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080029#include "android_util_Binder.h"
30#include <utils/misc.h>
31#include <android_runtime/AndroidRuntime.h>
32#include <utils/Log.h>
33
Mathias Agopianb13b9bd2012-02-17 18:27:36 -080034#include <androidfw/Asset.h>
35#include <androidfw/AssetManager.h>
36#include <androidfw/ResourceTypes.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
38#include <stdio.h>
39
40namespace android {
41
42// ----------------------------------------------------------------------------
43
44static struct typedvalue_offsets_t
45{
46 jfieldID mType;
47 jfieldID mData;
48 jfieldID mString;
49 jfieldID mAssetCookie;
50 jfieldID mResourceId;
51 jfieldID mChangingConfigurations;
52 jfieldID mDensity;
53} gTypedValueOffsets;
54
55static struct assetfiledescriptor_offsets_t
56{
57 jfieldID mFd;
58 jfieldID mStartOffset;
59 jfieldID mLength;
60} gAssetFileDescriptorOffsets;
61
62static struct assetmanager_offsets_t
63{
64 jfieldID mObject;
65} gAssetManagerOffsets;
66
67jclass g_stringClass = NULL;
68
69// ----------------------------------------------------------------------------
70
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080071enum {
Dianne Hackborn0d221012009-07-29 15:41:19 -070072 STYLE_NUM_ENTRIES = 6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080073 STYLE_TYPE = 0,
74 STYLE_DATA = 1,
75 STYLE_ASSET_COOKIE = 2,
76 STYLE_RESOURCE_ID = 3,
Dianne Hackborn0d221012009-07-29 15:41:19 -070077 STYLE_CHANGING_CONFIGURATIONS = 4,
78 STYLE_DENSITY = 5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080079};
80
81static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
82 const Res_value& value, uint32_t ref, ssize_t block,
83 uint32_t typeSpecFlags, ResTable_config* config = NULL);
84
85jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
86 const Res_value& value, uint32_t ref, ssize_t block,
87 uint32_t typeSpecFlags, ResTable_config* config)
88{
89 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
90 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
91 (jint)table->getTableCookie(block));
92 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
93 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
94 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
95 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
96 typeSpecFlags);
97 if (config != NULL) {
98 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
99 }
100 return block;
101}
102
103// ----------------------------------------------------------------------------
104
105// this guy is exported to other jni routines
106AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
107{
108 AssetManager* am = (AssetManager*)env->GetIntField(obj, gAssetManagerOffsets.mObject);
109 if (am != NULL) {
110 return am;
111 }
112 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
113 return NULL;
114}
115
116static jint android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
117 jstring fileName, jint mode)
118{
119 AssetManager* am = assetManagerForJavaObject(env, clazz);
120 if (am == NULL) {
121 return 0;
122 }
123
Steve Block71f2cf12011-10-20 11:56:00 +0100124 ALOGV("openAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125
Elliott Hughes69a017b2011-04-08 14:10:28 -0700126 ScopedUtfChars fileName8(env, fileName);
127 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800128 return -1;
129 }
130
131 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
132 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700133 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800134 return -1;
135 }
136
Elliott Hughes69a017b2011-04-08 14:10:28 -0700137 Asset* a = am->open(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800138
139 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700140 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800141 return -1;
142 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800143
144 //printf("Created Asset Stream: %p\n", a);
145
146 return (jint)a;
147}
148
149static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
150{
Kenny Rootddb76c42010-11-24 12:56:06 -0800151 off64_t startOffset, length;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800152 int fd = a->openFileDescriptor(&startOffset, &length);
153 delete a;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700154
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800155 if (fd < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700156 jniThrowException(env, "java/io/FileNotFoundException",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800157 "This file can not be opened as a file descriptor; it is probably compressed");
158 return NULL;
159 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700160
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800161 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
162 if (offsets == NULL) {
163 close(fd);
164 return NULL;
165 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700166
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800167 offsets[0] = startOffset;
168 offsets[1] = length;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700169
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800170 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700171
Elliott Hughesa3804cf2011-04-11 16:50:19 -0700172 jobject fileDesc = jniCreateFileDescriptor(env, fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800173 if (fileDesc == NULL) {
174 close(fd);
175 return NULL;
176 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700177
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800178 return newParcelFileDescriptor(env, fileDesc);
179}
180
181static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
182 jstring fileName, jlongArray outOffsets)
183{
184 AssetManager* am = assetManagerForJavaObject(env, clazz);
185 if (am == NULL) {
186 return NULL;
187 }
188
Steve Block71f2cf12011-10-20 11:56:00 +0100189 ALOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800190
Elliott Hughes69a017b2011-04-08 14:10:28 -0700191 ScopedUtfChars fileName8(env, fileName);
192 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800193 return NULL;
194 }
195
Elliott Hughes69a017b2011-04-08 14:10:28 -0700196 Asset* a = am->open(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800197
198 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700199 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800200 return NULL;
201 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800202
203 //printf("Created Asset Stream: %p\n", a);
204
205 return returnParcelFileDescriptor(env, a, outOffsets);
206}
207
208static jint android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
209 jint cookie,
210 jstring fileName,
211 jint mode)
212{
213 AssetManager* am = assetManagerForJavaObject(env, clazz);
214 if (am == NULL) {
215 return 0;
216 }
217
Steve Block71f2cf12011-10-20 11:56:00 +0100218 ALOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800219
Elliott Hughes69a017b2011-04-08 14:10:28 -0700220 ScopedUtfChars fileName8(env, fileName);
221 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800222 return -1;
223 }
224
225 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
226 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700227 jniThrowException(env, "java/lang/IllegalArgumentException", "Bad access mode");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800228 return -1;
229 }
230
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800231 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -0700232 ? am->openNonAsset((void*)cookie, fileName8.c_str(), (Asset::AccessMode)mode)
233 : am->openNonAsset(fileName8.c_str(), (Asset::AccessMode)mode);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800234
235 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700236 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800237 return -1;
238 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800239
240 //printf("Created Asset Stream: %p\n", a);
241
242 return (jint)a;
243}
244
245static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
246 jint cookie,
247 jstring fileName,
248 jlongArray outOffsets)
249{
250 AssetManager* am = assetManagerForJavaObject(env, clazz);
251 if (am == NULL) {
252 return NULL;
253 }
254
Steve Block71f2cf12011-10-20 11:56:00 +0100255 ALOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800256
Elliott Hughes69a017b2011-04-08 14:10:28 -0700257 ScopedUtfChars fileName8(env, fileName);
258 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800259 return NULL;
260 }
261
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800262 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -0700263 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_RANDOM)
264 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_RANDOM);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800265
266 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700267 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800268 return NULL;
269 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800270
271 //printf("Created Asset Stream: %p\n", a);
272
273 return returnParcelFileDescriptor(env, a, outOffsets);
274}
275
276static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
277 jstring fileName)
278{
279 AssetManager* am = assetManagerForJavaObject(env, clazz);
280 if (am == NULL) {
281 return NULL;
282 }
283
Elliott Hughes69a017b2011-04-08 14:10:28 -0700284 ScopedUtfChars fileName8(env, fileName);
285 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800286 return NULL;
287 }
288
Elliott Hughes69a017b2011-04-08 14:10:28 -0700289 AssetDir* dir = am->openDir(fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800290
291 if (dir == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700292 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800293 return NULL;
294 }
295
296 jclass cls = env->FindClass("java/lang/String");
297 LOG_FATAL_IF(cls == NULL, "No string class?!?");
298 if (cls == NULL) {
299 delete dir;
300 return NULL;
301 }
302
303 size_t N = dir->getFileCount();
304
305 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
306 cls, NULL);
307 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800308 delete dir;
309 return NULL;
310 }
311
312 for (size_t i=0; i<N; i++) {
313 const String8& name = dir->getFileName(i);
314 jstring str = env->NewStringUTF(name.string());
315 if (str == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800316 delete dir;
317 return NULL;
318 }
319 env->SetObjectArrayElement(array, i, str);
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700320 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800321 }
322
323 delete dir;
324
325 return array;
326}
327
328static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
329 jint asset)
330{
331 Asset* a = (Asset*)asset;
332
333 //printf("Destroying Asset Stream: %p\n", a);
334
335 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700336 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800337 return;
338 }
339
340 delete a;
341}
342
343static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
344 jint asset)
345{
346 Asset* a = (Asset*)asset;
347
348 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700349 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800350 return -1;
351 }
352
353 uint8_t b;
354 ssize_t res = a->read(&b, 1);
355 return res == 1 ? b : -1;
356}
357
358static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
359 jint asset, jbyteArray bArray,
360 jint off, jint len)
361{
362 Asset* a = (Asset*)asset;
363
364 if (a == NULL || bArray == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700365 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800366 return -1;
367 }
368
369 if (len == 0) {
370 return 0;
371 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700372
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800373 jsize bLen = env->GetArrayLength(bArray);
374 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700375 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800376 return -1;
377 }
378
379 jbyte* b = env->GetByteArrayElements(bArray, NULL);
380 ssize_t res = a->read(b+off, len);
381 env->ReleaseByteArrayElements(bArray, b, 0);
382
383 if (res > 0) return res;
384
385 if (res < 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700386 jniThrowException(env, "java/io/IOException", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800387 }
388 return -1;
389}
390
391static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
392 jint asset,
393 jlong offset, jint whence)
394{
395 Asset* a = (Asset*)asset;
396
397 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700398 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800399 return -1;
400 }
401
402 return a->seek(
403 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
404}
405
406static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
407 jint asset)
408{
409 Asset* a = (Asset*)asset;
410
411 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700412 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800413 return -1;
414 }
415
416 return a->getLength();
417}
418
419static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
420 jint asset)
421{
422 Asset* a = (Asset*)asset;
423
424 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700425 jniThrowNullPointerException(env, "asset");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800426 return -1;
427 }
428
429 return a->getRemainingLength();
430}
431
432static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
433 jstring path)
434{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700435 ScopedUtfChars path8(env, path);
436 if (path8.c_str() == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800437 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 }
439
440 AssetManager* am = assetManagerForJavaObject(env, clazz);
441 if (am == NULL) {
Glenn Kasten129e19c2012-01-10 17:57:36 -0800442 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 }
444
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800445 void* cookie;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700446 bool res = am->addAssetPath(String8(path8.c_str()), &cookie);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447
448 return (res) ? (jint)cookie : 0;
449}
450
451static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
452{
453 AssetManager* am = assetManagerForJavaObject(env, clazz);
454 if (am == NULL) {
455 return JNI_TRUE;
456 }
457 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
458}
459
460static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
461 jstring locale)
462{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700463 ScopedUtfChars locale8(env, locale);
464 if (locale8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800465 return;
466 }
467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 AssetManager* am = assetManagerForJavaObject(env, clazz);
469 if (am == NULL) {
470 return;
471 }
472
Elliott Hughes69a017b2011-04-08 14:10:28 -0700473 am->setLocale(locale8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800474}
475
476static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
477{
478 Vector<String8> locales;
479
480 AssetManager* am = assetManagerForJavaObject(env, clazz);
481 if (am == NULL) {
482 return NULL;
483 }
484
485 am->getLocales(&locales);
486
487 const int N = locales.size();
488
489 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
490 if (result == NULL) {
491 return NULL;
492 }
493
494 for (int i=0; i<N; i++) {
Gilles Debunne0db187a2010-08-27 11:51:34 -0700495 jstring str = env->NewStringUTF(locales[i].string());
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700496 if (str == NULL) {
497 return NULL;
498 }
499 env->SetObjectArrayElement(result, i, str);
500 env->DeleteLocalRef(str);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800501 }
502
503 return result;
504}
505
506static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
507 jint mcc, jint mnc,
508 jstring locale, jint orientation,
509 jint touchscreen, jint density,
510 jint keyboard, jint keyboardHidden,
511 jint navigation,
512 jint screenWidth, jint screenHeight,
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700513 jint smallestScreenWidthDp,
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700514 jint screenWidthDp, jint screenHeightDp,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100515 jint screenLayout, jint uiMode,
516 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800517{
518 AssetManager* am = assetManagerForJavaObject(env, clazz);
519 if (am == NULL) {
520 return;
521 }
522
523 ResTable_config config;
524 memset(&config, 0, sizeof(config));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700525
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800526 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700527
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800528 config.mcc = (uint16_t)mcc;
529 config.mnc = (uint16_t)mnc;
530 config.orientation = (uint8_t)orientation;
531 config.touchscreen = (uint8_t)touchscreen;
532 config.density = (uint16_t)density;
533 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700534 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800535 config.navigation = (uint8_t)navigation;
536 config.screenWidth = (uint16_t)screenWidth;
537 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn69cb8752011-05-19 18:13:32 -0700538 config.smallestScreenWidthDp = (uint16_t)smallestScreenWidthDp;
Dianne Hackborn3fc982f2011-03-30 16:20:26 -0700539 config.screenWidthDp = (uint16_t)screenWidthDp;
540 config.screenHeightDp = (uint16_t)screenHeightDp;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700541 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100542 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800543 config.sdkVersion = (uint16_t)sdkVersion;
544 config.minorVersion = 0;
545 am->setConfiguration(config, locale8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700546
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
548}
549
550static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
551 jstring name,
552 jstring defType,
553 jstring defPackage)
554{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700555 ScopedStringChars name16(env, name);
556 if (name16.get() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 return 0;
558 }
559
560 AssetManager* am = assetManagerForJavaObject(env, clazz);
561 if (am == NULL) {
562 return 0;
563 }
564
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 const char16_t* defType16 = defType
566 ? env->GetStringChars(defType, NULL) : NULL;
567 jsize defTypeLen = defType
568 ? env->GetStringLength(defType) : 0;
569 const char16_t* defPackage16 = defPackage
570 ? env->GetStringChars(defPackage, NULL) : NULL;
571 jsize defPackageLen = defPackage
572 ? env->GetStringLength(defPackage) : 0;
573
574 jint ident = am->getResources().identifierForName(
Elliott Hughes69a017b2011-04-08 14:10:28 -0700575 name16.get(), name16.size(), defType16, defTypeLen, defPackage16, defPackageLen);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800576
577 if (defPackage16) {
578 env->ReleaseStringChars(defPackage, defPackage16);
579 }
580 if (defType16) {
581 env->ReleaseStringChars(defType, defType16);
582 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800583
584 return ident;
585}
586
587static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
588 jint resid)
589{
590 AssetManager* am = assetManagerForJavaObject(env, clazz);
591 if (am == NULL) {
592 return NULL;
593 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700594
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800595 ResTable::resource_name name;
596 if (!am->getResources().getResourceName(resid, &name)) {
597 return NULL;
598 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700599
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800600 String16 str;
601 if (name.package != NULL) {
602 str.setTo(name.package, name.packageLen);
603 }
604 if (name.type != NULL) {
605 if (str.size() > 0) {
606 char16_t div = ':';
607 str.append(&div, 1);
608 }
609 str.append(name.type, name.typeLen);
610 }
611 if (name.name != NULL) {
612 if (str.size() > 0) {
613 char16_t div = '/';
614 str.append(&div, 1);
615 }
616 str.append(name.name, name.nameLen);
617 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700618
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800619 return env->NewString((const jchar*)str.string(), str.size());
620}
621
622static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
623 jint resid)
624{
625 AssetManager* am = assetManagerForJavaObject(env, clazz);
626 if (am == NULL) {
627 return NULL;
628 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700629
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800630 ResTable::resource_name name;
631 if (!am->getResources().getResourceName(resid, &name)) {
632 return NULL;
633 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 if (name.package != NULL) {
636 return env->NewString((const jchar*)name.package, name.packageLen);
637 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700638
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800639 return NULL;
640}
641
642static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
643 jint resid)
644{
645 AssetManager* am = assetManagerForJavaObject(env, clazz);
646 if (am == NULL) {
647 return NULL;
648 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 ResTable::resource_name name;
651 if (!am->getResources().getResourceName(resid, &name)) {
652 return NULL;
653 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700654
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800655 if (name.type != NULL) {
656 return env->NewString((const jchar*)name.type, name.typeLen);
657 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 return NULL;
660}
661
662static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
663 jint resid)
664{
665 AssetManager* am = assetManagerForJavaObject(env, clazz);
666 if (am == NULL) {
667 return NULL;
668 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700669
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800670 ResTable::resource_name name;
671 if (!am->getResources().getResourceName(resid, &name)) {
672 return NULL;
673 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700674
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800675 if (name.name != NULL) {
676 return env->NewString((const jchar*)name.name, name.nameLen);
677 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700678
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800679 return NULL;
680}
681
682static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
683 jint ident,
Kenny Root55fc8502010-10-28 14:47:01 -0700684 jshort density,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800685 jobject outValue,
686 jboolean resolve)
687{
688 AssetManager* am = assetManagerForJavaObject(env, clazz);
689 if (am == NULL) {
690 return 0;
691 }
692 const ResTable& res(am->getResources());
693
694 Res_value value;
695 ResTable_config config;
696 uint32_t typeSpecFlags;
Kenny Root55fc8502010-10-28 14:47:01 -0700697 ssize_t block = res.getResource(ident, &value, false, density, &typeSpecFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800698#if THROW_ON_BAD_ID
699 if (block == BAD_INDEX) {
700 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
701 return 0;
702 }
703#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800704 uint32_t ref = ident;
705 if (resolve) {
706 block = res.resolveReference(&value, block, &ref);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800707#if THROW_ON_BAD_ID
708 if (block == BAD_INDEX) {
709 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
710 return 0;
711 }
712#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800713 }
714 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
715}
716
717static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
718 jint ident, jint bagEntryId,
719 jobject outValue, jboolean resolve)
720{
721 AssetManager* am = assetManagerForJavaObject(env, clazz);
722 if (am == NULL) {
723 return 0;
724 }
725 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700726
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800727 // Now lock down the resource object and start pulling stuff from it.
728 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -0700729
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800730 ssize_t block = -1;
731 Res_value value;
732
733 const ResTable::bag_entry* entry = NULL;
734 uint32_t typeSpecFlags;
735 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
736
737 for (ssize_t i=0; i<entryCount; i++) {
738 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
739 block = entry->stringBlock;
740 value = entry->map.value;
741 }
742 entry++;
743 }
744
745 res.unlock();
746
747 if (block < 0) {
748 return block;
749 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700750
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 uint32_t ref = ident;
752 if (resolve) {
753 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800754#if THROW_ON_BAD_ID
755 if (block == BAD_INDEX) {
756 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
757 return 0;
758 }
759#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800760 }
761 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
762}
763
764static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
765{
766 AssetManager* am = assetManagerForJavaObject(env, clazz);
767 if (am == NULL) {
768 return 0;
769 }
770 return am->getResources().getTableCount();
771}
772
773static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
774 jint block)
775{
776 AssetManager* am = assetManagerForJavaObject(env, clazz);
777 if (am == NULL) {
778 return 0;
779 }
780 return (jint)am->getResources().getTableStringBlock(block);
781}
782
783static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
784 jint cookie)
785{
786 AssetManager* am = assetManagerForJavaObject(env, clazz);
787 if (am == NULL) {
788 return NULL;
789 }
790 String8 name(am->getAssetPath((void*)cookie));
791 if (name.length() == 0) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700792 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "Empty cookie name");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800793 return NULL;
794 }
795 jstring str = env->NewStringUTF(name.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800796 return str;
797}
798
799static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
800{
801 AssetManager* am = assetManagerForJavaObject(env, clazz);
802 if (am == NULL) {
803 return 0;
804 }
805 return (jint)(new ResTable::Theme(am->getResources()));
806}
807
808static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
809 jint themeInt)
810{
811 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
812 delete theme;
813}
814
815static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
816 jint themeInt,
817 jint styleRes,
818 jboolean force)
819{
820 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
821 theme->applyStyle(styleRes, force ? true : false);
822}
823
824static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
825 jint destInt, jint srcInt)
826{
827 ResTable::Theme* dest = (ResTable::Theme*)destInt;
828 ResTable::Theme* src = (ResTable::Theme*)srcInt;
829 dest->setTo(*src);
830}
831
832static jint android_content_AssetManager_loadThemeAttributeValue(
833 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
834{
835 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
836 const ResTable& res(theme->getResTable());
837
838 Res_value value;
839 // XXX value could be different in different configs!
840 uint32_t typeSpecFlags = 0;
841 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
842 uint32_t ref = 0;
843 if (resolve) {
844 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -0800845#if THROW_ON_BAD_ID
846 if (block == BAD_INDEX) {
847 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
848 return 0;
849 }
850#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800851 }
852 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
853}
854
855static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
856 jint themeInt, jint pri,
857 jstring tag, jstring prefix)
858{
859 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
860 const ResTable& res(theme->getResTable());
Elliott Hughes69a017b2011-04-08 14:10:28 -0700861
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800862 // XXX Need to use params.
863 theme->dumpToLog();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800864}
865
866static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
867 jint themeToken,
868 jint defStyleAttr,
869 jint defStyleRes,
870 jint xmlParserToken,
871 jintArray attrs,
872 jintArray outValues,
873 jintArray outIndices)
874{
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700875 if (themeToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700876 jniThrowNullPointerException(env, "theme token");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700877 return JNI_FALSE;
878 }
879 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700880 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700881 return JNI_FALSE;
882 }
883 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700884 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800885 return JNI_FALSE;
886 }
887
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800888 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
889 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700890
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800891 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
892 const ResTable& res = theme->getResTable();
893 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700894 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800895 Res_value value;
896
897 const jsize NI = env->GetArrayLength(attrs);
898 const jsize NV = env->GetArrayLength(outValues);
899 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -0700900 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800901 return JNI_FALSE;
902 }
903
904 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
905 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800906 return JNI_FALSE;
907 }
908
909 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
910 jint* dest = baseDest;
911 if (dest == NULL) {
912 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800913 return JNI_FALSE;
914 }
915
916 jint* indices = NULL;
917 int indicesIdx = 0;
918 if (outIndices != NULL) {
919 if (env->GetArrayLength(outIndices) > NI) {
920 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
921 }
922 }
923
924 // Load default style from attribute, if specified...
925 uint32_t defStyleBagTypeSetFlags = 0;
926 if (defStyleAttr != 0) {
927 Res_value value;
928 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
929 if (value.dataType == Res_value::TYPE_REFERENCE) {
930 defStyleRes = value.data;
931 }
932 }
933 }
934
935 // Retrieve the style class associated with the current XML tag.
936 int style = 0;
937 uint32_t styleBagTypeSetFlags = 0;
938 if (xmlParser != NULL) {
939 ssize_t idx = xmlParser->indexOfStyle();
940 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
941 if (value.dataType == value.TYPE_ATTRIBUTE) {
942 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
943 value.dataType = Res_value::TYPE_NULL;
944 }
945 }
946 if (value.dataType == value.TYPE_REFERENCE) {
947 style = value.data;
948 }
949 }
950 }
951
952 // Now lock down the resource object and start pulling stuff from it.
953 res.lock();
954
955 // Retrieve the default style bag, if requested.
956 const ResTable::bag_entry* defStyleEnt = NULL;
957 uint32_t defStyleTypeSetFlags = 0;
958 ssize_t bagOff = defStyleRes != 0
959 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
960 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
961 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
962 (bagOff >= 0 ? bagOff : 0);
963
964 // Retrieve the style class bag, if requested.
965 const ResTable::bag_entry* styleEnt = NULL;
966 uint32_t styleTypeSetFlags = 0;
967 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
968 styleTypeSetFlags |= styleBagTypeSetFlags;
969 const ResTable::bag_entry* endStyleEnt = styleEnt +
970 (bagOff >= 0 ? bagOff : 0);
971
972 // Retrieve the XML attributes, if requested.
973 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
974 jsize ix=0;
975 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
976
977 static const ssize_t kXmlBlock = 0x10000000;
978
979 // Now iterate through all of the attributes that the client has requested,
980 // filling in each with whatever data we can find.
981 ssize_t block = 0;
982 uint32_t typeSetFlags;
983 for (jsize ii=0; ii<NI; ii++) {
984 const uint32_t curIdent = (uint32_t)src[ii];
985
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800986 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
Elliott Hughes69a017b2011-04-08 14:10:28 -0700987
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800988 // Try to find a value for this attribute... we prioritize values
989 // coming from, first XML attributes, then XML style, then default
990 // style, and finally the theme.
991 value.dataType = Res_value::TYPE_NULL;
992 value.data = 0;
993 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700994 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800995
996 // Skip through XML attributes until the end or the next possible match.
997 while (ix < NX && curIdent > curXmlAttr) {
998 ix++;
999 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1000 }
1001 // Retrieve the current XML attribute if it matches, and step to next.
1002 if (ix < NX && curIdent == curXmlAttr) {
1003 block = kXmlBlock;
1004 xmlParser->getAttributeValue(ix, &value);
1005 ix++;
1006 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001007 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1008 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009 }
1010
1011 // Skip through the style values until the end or the next possible match.
1012 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1013 styleEnt++;
1014 }
1015 // Retrieve the current style attribute if it matches, and step to next.
1016 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1017 if (value.dataType == Res_value::TYPE_NULL) {
1018 block = styleEnt->stringBlock;
1019 typeSetFlags = styleTypeSetFlags;
1020 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001021 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1022 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024 styleEnt++;
1025 }
1026
1027 // Skip through the default style values until the end or the next possible match.
1028 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1029 defStyleEnt++;
1030 }
1031 // Retrieve the current default style attribute if it matches, and step to next.
1032 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1033 if (value.dataType == Res_value::TYPE_NULL) {
1034 block = defStyleEnt->stringBlock;
1035 typeSetFlags = defStyleTypeSetFlags;
1036 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001037 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1038 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 }
1040 defStyleEnt++;
1041 }
1042
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001043 uint32_t resid = 0;
1044 if (value.dataType != Res_value::TYPE_NULL) {
1045 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001046 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1047 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001048 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001049 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1050 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 } else {
1052 // If we still don't have a value for this attribute, try to find
1053 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001054 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1055 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001056 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1057 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001058 newBlock = res.resolveReference(&value, block, &resid,
1059 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001060#if THROW_ON_BAD_ID
1061 if (newBlock == BAD_INDEX) {
1062 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1063 return JNI_FALSE;
1064 }
1065#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001066 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001067 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1068 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001069 }
1070 }
1071
1072 // Deal with the special @null value -- it turns back to TYPE_NULL.
1073 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001074 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001075 value.dataType = Res_value::TYPE_NULL;
Kenny Root7fbe4d22011-01-20 13:15:44 -08001076 block = kXmlBlock;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001079 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1080 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001081
1082 // Write the final value back to Java.
1083 dest[STYLE_TYPE] = value.dataType;
1084 dest[STYLE_DATA] = value.data;
1085 dest[STYLE_ASSET_COOKIE] =
1086 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1087 dest[STYLE_RESOURCE_ID] = resid;
1088 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001089 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001090
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001091 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1092 indicesIdx++;
1093 indices[indicesIdx] = ii;
1094 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001095
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001096 dest += STYLE_NUM_ENTRIES;
1097 }
1098
1099 res.unlock();
1100
1101 if (indices != NULL) {
1102 indices[0] = indicesIdx;
1103 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1104 }
1105 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1106 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1107
1108 return JNI_TRUE;
1109}
1110
1111static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1112 jint xmlParserToken,
1113 jintArray attrs,
1114 jintArray outValues,
1115 jintArray outIndices)
1116{
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001117 if (xmlParserToken == 0) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001118 jniThrowNullPointerException(env, "xmlParserToken");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001119 return JNI_FALSE;
1120 }
1121 if (attrs == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001122 jniThrowNullPointerException(env, "attrs");
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001123 return JNI_FALSE;
1124 }
1125 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001126 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001127 return JNI_FALSE;
1128 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001129
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001130 AssetManager* am = assetManagerForJavaObject(env, clazz);
1131 if (am == NULL) {
1132 return JNI_FALSE;
1133 }
1134 const ResTable& res(am->getResources());
1135 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001136 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001137 Res_value value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001138
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001139 const jsize NI = env->GetArrayLength(attrs);
1140 const jsize NV = env->GetArrayLength(outValues);
1141 if (NV < (NI*STYLE_NUM_ENTRIES)) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001142 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001143 return JNI_FALSE;
1144 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001145
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001146 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1147 if (src == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001148 return JNI_FALSE;
1149 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001150
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001151 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1152 jint* dest = baseDest;
1153 if (dest == NULL) {
1154 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001155 return JNI_FALSE;
1156 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001157
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001158 jint* indices = NULL;
1159 int indicesIdx = 0;
1160 if (outIndices != NULL) {
1161 if (env->GetArrayLength(outIndices) > NI) {
1162 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1163 }
1164 }
1165
1166 // Now lock down the resource object and start pulling stuff from it.
1167 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001168
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001169 // Retrieve the XML attributes, if requested.
1170 const jsize NX = xmlParser->getAttributeCount();
1171 jsize ix=0;
1172 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001173
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001174 static const ssize_t kXmlBlock = 0x10000000;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001175
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001176 // Now iterate through all of the attributes that the client has requested,
1177 // filling in each with whatever data we can find.
1178 ssize_t block = 0;
1179 uint32_t typeSetFlags;
1180 for (jsize ii=0; ii<NI; ii++) {
1181 const uint32_t curIdent = (uint32_t)src[ii];
Elliott Hughes69a017b2011-04-08 14:10:28 -07001182
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001183 // Try to find a value for this attribute...
1184 value.dataType = Res_value::TYPE_NULL;
1185 value.data = 0;
1186 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001187 config.density = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001188
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189 // Skip through XML attributes until the end or the next possible match.
1190 while (ix < NX && curIdent > curXmlAttr) {
1191 ix++;
1192 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1193 }
1194 // Retrieve the current XML attribute if it matches, and step to next.
1195 if (ix < NX && curIdent == curXmlAttr) {
1196 block = kXmlBlock;
1197 xmlParser->getAttributeValue(ix, &value);
1198 ix++;
1199 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1200 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001201
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001202 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1203 uint32_t resid = 0;
1204 if (value.dataType != Res_value::TYPE_NULL) {
1205 // Take care of resolving the found resource to its final value.
1206 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001207 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1208 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001209#if THROW_ON_BAD_ID
1210 if (newBlock == BAD_INDEX) {
1211 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1212 return JNI_FALSE;
1213 }
1214#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001215 if (newBlock >= 0) block = newBlock;
1216 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001217
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001218 // Deal with the special @null value -- it turns back to TYPE_NULL.
1219 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1220 value.dataType = Res_value::TYPE_NULL;
1221 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001222
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001223 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001224
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001225 // Write the final value back to Java.
1226 dest[STYLE_TYPE] = value.dataType;
1227 dest[STYLE_DATA] = value.data;
1228 dest[STYLE_ASSET_COOKIE] =
1229 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1230 dest[STYLE_RESOURCE_ID] = resid;
1231 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001232 dest[STYLE_DENSITY] = config.density;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001233
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001234 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1235 indicesIdx++;
1236 indices[indicesIdx] = ii;
1237 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001238
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001239 dest += STYLE_NUM_ENTRIES;
1240 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001241
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001242 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001243
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001244 if (indices != NULL) {
1245 indices[0] = indicesIdx;
1246 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1247 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001248
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001249 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1250 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001251
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001252 return JNI_TRUE;
1253}
1254
1255static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1256 jint id)
1257{
1258 AssetManager* am = assetManagerForJavaObject(env, clazz);
1259 if (am == NULL) {
Olivier Baillyd7c86722010-11-18 14:43:36 -08001260 return 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001261 }
1262 const ResTable& res(am->getResources());
Elliott Hughes69a017b2011-04-08 14:10:28 -07001263
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001264 res.lock();
1265 const ResTable::bag_entry* defStyleEnt = NULL;
1266 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1267 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001268
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001269 return bagOff;
1270}
1271
1272static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1273 jint id,
1274 jintArray outValues)
1275{
1276 if (outValues == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001277 jniThrowNullPointerException(env, "out values");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001278 return JNI_FALSE;
1279 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001280
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001281 AssetManager* am = assetManagerForJavaObject(env, clazz);
1282 if (am == NULL) {
1283 return JNI_FALSE;
1284 }
1285 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001286 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001287 Res_value value;
1288 ssize_t block;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001289
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001290 const jsize NV = env->GetArrayLength(outValues);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001291
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001292 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1293 jint* dest = baseDest;
1294 if (dest == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001295 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001296 return JNI_FALSE;
1297 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001298
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001299 // Now lock down the resource object and start pulling stuff from it.
1300 res.lock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001301
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001302 const ResTable::bag_entry* arrayEnt = NULL;
1303 uint32_t arrayTypeSetFlags = 0;
1304 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1305 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1306 (bagOff >= 0 ? bagOff : 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001307
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001308 int i = 0;
1309 uint32_t typeSetFlags;
1310 while (i < NV && arrayEnt < endArrayEnt) {
1311 block = arrayEnt->stringBlock;
1312 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001313 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001314 value = arrayEnt->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001315
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001316 uint32_t resid = 0;
1317 if (value.dataType != Res_value::TYPE_NULL) {
1318 // Take care of resolving the found resource to its final value.
1319 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001320 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1321 &typeSetFlags, &config);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001322#if THROW_ON_BAD_ID
1323 if (newBlock == BAD_INDEX) {
1324 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1325 return JNI_FALSE;
1326 }
1327#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001328 if (newBlock >= 0) block = newBlock;
1329 }
1330
1331 // Deal with the special @null value -- it turns back to TYPE_NULL.
1332 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1333 value.dataType = Res_value::TYPE_NULL;
1334 }
1335
1336 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1337
1338 // Write the final value back to Java.
1339 dest[STYLE_TYPE] = value.dataType;
1340 dest[STYLE_DATA] = value.data;
1341 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1342 dest[STYLE_RESOURCE_ID] = resid;
1343 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001344 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001345 dest += STYLE_NUM_ENTRIES;
1346 i+= STYLE_NUM_ENTRIES;
1347 arrayEnt++;
1348 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001349
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001350 i /= STYLE_NUM_ENTRIES;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001351
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001352 res.unlock();
Elliott Hughes69a017b2011-04-08 14:10:28 -07001353
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001354 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -07001355
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001356 return i;
1357}
1358
1359static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1360 jint cookie,
1361 jstring fileName)
1362{
1363 AssetManager* am = assetManagerForJavaObject(env, clazz);
1364 if (am == NULL) {
1365 return 0;
1366 }
1367
Steve Block71f2cf12011-10-20 11:56:00 +01001368 ALOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001369
Elliott Hughes69a017b2011-04-08 14:10:28 -07001370 ScopedUtfChars fileName8(env, fileName);
1371 if (fileName8.c_str() == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001372 return 0;
1373 }
1374
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001375 Asset* a = cookie
Elliott Hughes69a017b2011-04-08 14:10:28 -07001376 ? am->openNonAsset((void*)cookie, fileName8.c_str(), Asset::ACCESS_BUFFER)
1377 : am->openNonAsset(fileName8.c_str(), Asset::ACCESS_BUFFER);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001378
1379 if (a == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -07001380 jniThrowException(env, "java/io/FileNotFoundException", fileName8.c_str());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001381 return 0;
1382 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001383
1384 ResXMLTree* block = new ResXMLTree();
1385 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1386 a->close();
1387 delete a;
1388
1389 if (err != NO_ERROR) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001390 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001391 return 0;
1392 }
1393
1394 return (jint)block;
1395}
1396
1397static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1398 jint arrayResId)
1399{
1400 AssetManager* am = assetManagerForJavaObject(env, clazz);
1401 if (am == NULL) {
1402 return NULL;
1403 }
1404 const ResTable& res(am->getResources());
1405
1406 const ResTable::bag_entry* startOfBag;
1407 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1408 if (N < 0) {
1409 return NULL;
1410 }
1411
1412 jintArray array = env->NewIntArray(N * 2);
1413 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001414 res.unlockBag(startOfBag);
1415 return NULL;
1416 }
1417
1418 Res_value value;
1419 const ResTable::bag_entry* bag = startOfBag;
1420 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1421 jint stringIndex = -1;
1422 jint stringBlock = 0;
1423 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001424
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001425 // Take care of resolving the found resource to its final value.
1426 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1427 if (value.dataType == Res_value::TYPE_STRING) {
1428 stringIndex = value.data;
1429 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001430
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001431#if THROW_ON_BAD_ID
1432 if (stringBlock == BAD_INDEX) {
1433 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1434 return array;
1435 }
1436#endif
Elliott Hughes69a017b2011-04-08 14:10:28 -07001437
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001438 //todo: It might be faster to allocate a C array to contain
1439 // the blocknums and indices, put them in there and then
1440 // do just one SetIntArrayRegion()
1441 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1442 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1443 j = j + 2;
1444 }
1445 res.unlockBag(startOfBag);
1446 return array;
1447}
1448
1449static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1450 jint arrayResId)
1451{
1452 AssetManager* am = assetManagerForJavaObject(env, clazz);
1453 if (am == NULL) {
1454 return NULL;
1455 }
1456 const ResTable& res(am->getResources());
1457
1458 jclass cls = env->FindClass("java/lang/String");
1459 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1460 if (cls == NULL) {
1461 return NULL;
1462 }
1463
1464 const ResTable::bag_entry* startOfBag;
1465 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1466 if (N < 0) {
1467 return NULL;
1468 }
1469
1470 jobjectArray array = env->NewObjectArray(N, cls, NULL);
Kenny Root485dd212010-05-06 16:06:48 -07001471 if (env->ExceptionCheck()) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001472 res.unlockBag(startOfBag);
1473 return NULL;
1474 }
1475
1476 Res_value value;
1477 const ResTable::bag_entry* bag = startOfBag;
1478 size_t strLen = 0;
1479 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1480 value = bag->map.value;
1481 jstring str = NULL;
Kenny Root780d2a12010-02-22 22:36:26 -08001482
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001483 // Take care of resolving the found resource to its final value.
1484 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001485#if THROW_ON_BAD_ID
1486 if (block == BAD_INDEX) {
1487 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1488 return array;
1489 }
1490#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001491 if (value.dataType == Res_value::TYPE_STRING) {
Kenny Root780d2a12010-02-22 22:36:26 -08001492 const ResStringPool* pool = res.getTableStringBlock(block);
1493 const char* str8 = pool->string8At(value.data, &strLen);
1494 if (str8 != NULL) {
1495 str = env->NewStringUTF(str8);
1496 } else {
1497 const char16_t* str16 = pool->stringAt(value.data, &strLen);
1498 str = env->NewString(str16, strLen);
Kenny Root485dd212010-05-06 16:06:48 -07001499 }
1500
1501 // If one of our NewString{UTF} calls failed due to memory, an
1502 // exception will be pending.
1503 if (env->ExceptionCheck()) {
1504 res.unlockBag(startOfBag);
1505 return NULL;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001506 }
Kenny Root780d2a12010-02-22 22:36:26 -08001507
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001508 env->SetObjectArrayElement(array, i, str);
Kenny Root485dd212010-05-06 16:06:48 -07001509
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001510 // str is not NULL at that point, otherwise ExceptionCheck would have been true.
1511 // If we have a large amount of strings in our array, we might
1512 // overflow the local reference table of the VM.
Kenny Root485dd212010-05-06 16:06:48 -07001513 env->DeleteLocalRef(str);
1514 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001515 }
1516 res.unlockBag(startOfBag);
1517 return array;
1518}
1519
1520static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1521 jint arrayResId)
1522{
1523 AssetManager* am = assetManagerForJavaObject(env, clazz);
1524 if (am == NULL) {
1525 return NULL;
1526 }
1527 const ResTable& res(am->getResources());
1528
1529 const ResTable::bag_entry* startOfBag;
1530 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1531 if (N < 0) {
1532 return NULL;
1533 }
1534
1535 jintArray array = env->NewIntArray(N);
1536 if (array == NULL) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001537 res.unlockBag(startOfBag);
1538 return NULL;
1539 }
1540
1541 Res_value value;
1542 const ResTable::bag_entry* bag = startOfBag;
1543 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1544 value = bag->map.value;
Elliott Hughes69a017b2011-04-08 14:10:28 -07001545
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001546 // Take care of resolving the found resource to its final value.
1547 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
Dianne Hackborn20cb56e2010-03-04 00:58:29 -08001548#if THROW_ON_BAD_ID
1549 if (block == BAD_INDEX) {
1550 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!");
1551 return array;
1552 }
1553#endif
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001554 if (value.dataType >= Res_value::TYPE_FIRST_INT
1555 && value.dataType <= Res_value::TYPE_LAST_INT) {
1556 int intVal = value.data;
1557 env->SetIntArrayRegion(array, i, 1, &intVal);
1558 }
1559 }
1560 res.unlockBag(startOfBag);
1561 return array;
1562}
1563
1564static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1565{
1566 AssetManager* am = new AssetManager();
1567 if (am == NULL) {
Gilles Debunne4d4040b2010-08-26 15:59:54 -07001568 jniThrowException(env, "java/lang/OutOfMemoryError", "");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001569 return;
1570 }
1571
1572 am->addDefaultAssets();
1573
Steve Block71f2cf12011-10-20 11:56:00 +01001574 ALOGV("Created AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001575 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1576}
1577
1578static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1579{
1580 AssetManager* am = (AssetManager*)
1581 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
Steve Block71f2cf12011-10-20 11:56:00 +01001582 ALOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001583 if (am != NULL) {
1584 delete am;
1585 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1586 }
1587}
1588
1589static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1590{
1591 return Asset::getGlobalCount();
1592}
1593
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001594static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1595{
1596 String8 alloc = Asset::getAssetAllocations();
1597 if (alloc.length() <= 0) {
1598 return NULL;
1599 }
Elliott Hughes69a017b2011-04-08 14:10:28 -07001600
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001601 jstring str = env->NewStringUTF(alloc.string());
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001602 return str;
1603}
1604
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001605static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1606{
1607 return AssetManager::getGlobalCount();
1608}
1609
1610// ----------------------------------------------------------------------------
1611
1612/*
1613 * JNI registration.
1614 */
1615static JNINativeMethod gAssetManagerMethods[] = {
1616 /* name, signature, funcPtr */
1617
1618 // Basic asset stuff.
1619 { "openAsset", "(Ljava/lang/String;I)I",
1620 (void*) android_content_AssetManager_openAsset },
1621 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1622 (void*) android_content_AssetManager_openAssetFd },
1623 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1624 (void*) android_content_AssetManager_openNonAssetNative },
1625 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1626 (void*) android_content_AssetManager_openNonAssetFdNative },
1627 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1628 (void*) android_content_AssetManager_list },
1629 { "destroyAsset", "(I)V",
1630 (void*) android_content_AssetManager_destroyAsset },
1631 { "readAssetChar", "(I)I",
1632 (void*) android_content_AssetManager_readAssetChar },
1633 { "readAsset", "(I[BII)I",
1634 (void*) android_content_AssetManager_readAsset },
1635 { "seekAsset", "(IJI)J",
1636 (void*) android_content_AssetManager_seekAsset },
1637 { "getAssetLength", "(I)J",
1638 (void*) android_content_AssetManager_getAssetLength },
1639 { "getAssetRemainingLength", "(I)J",
1640 (void*) android_content_AssetManager_getAssetRemainingLength },
1641 { "addAssetPath", "(Ljava/lang/String;)I",
1642 (void*) android_content_AssetManager_addAssetPath },
1643 { "isUpToDate", "()Z",
1644 (void*) android_content_AssetManager_isUpToDate },
1645
1646 // Resources.
1647 { "setLocale", "(Ljava/lang/String;)V",
1648 (void*) android_content_AssetManager_setLocale },
1649 { "getLocales", "()[Ljava/lang/String;",
1650 (void*) android_content_AssetManager_getLocales },
Dianne Hackborn69cb8752011-05-19 18:13:32 -07001651 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001652 (void*) android_content_AssetManager_setConfiguration },
1653 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1654 (void*) android_content_AssetManager_getResourceIdentifier },
1655 { "getResourceName","(I)Ljava/lang/String;",
1656 (void*) android_content_AssetManager_getResourceName },
1657 { "getResourcePackageName","(I)Ljava/lang/String;",
1658 (void*) android_content_AssetManager_getResourcePackageName },
1659 { "getResourceTypeName","(I)Ljava/lang/String;",
1660 (void*) android_content_AssetManager_getResourceTypeName },
1661 { "getResourceEntryName","(I)Ljava/lang/String;",
1662 (void*) android_content_AssetManager_getResourceEntryName },
Kenny Root55fc8502010-10-28 14:47:01 -07001663 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001664 (void*) android_content_AssetManager_loadResourceValue },
1665 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1666 (void*) android_content_AssetManager_loadResourceBagValue },
1667 { "getStringBlockCount","()I",
1668 (void*) android_content_AssetManager_getStringBlockCount },
1669 { "getNativeStringBlock","(I)I",
1670 (void*) android_content_AssetManager_getNativeStringBlock },
1671 { "getCookieName","(I)Ljava/lang/String;",
1672 (void*) android_content_AssetManager_getCookieName },
1673
1674 // Themes.
1675 { "newTheme", "()I",
1676 (void*) android_content_AssetManager_newTheme },
1677 { "deleteTheme", "(I)V",
1678 (void*) android_content_AssetManager_deleteTheme },
1679 { "applyThemeStyle", "(IIZ)V",
1680 (void*) android_content_AssetManager_applyThemeStyle },
1681 { "copyTheme", "(II)V",
1682 (void*) android_content_AssetManager_copyTheme },
1683 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1684 (void*) android_content_AssetManager_loadThemeAttributeValue },
1685 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1686 (void*) android_content_AssetManager_dumpTheme },
1687 { "applyStyle","(IIII[I[I[I)Z",
1688 (void*) android_content_AssetManager_applyStyle },
1689 { "retrieveAttributes","(I[I[I[I)Z",
1690 (void*) android_content_AssetManager_retrieveAttributes },
1691 { "getArraySize","(I)I",
1692 (void*) android_content_AssetManager_getArraySize },
1693 { "retrieveArray","(I[I)I",
1694 (void*) android_content_AssetManager_retrieveArray },
1695
1696 // XML files.
1697 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1698 (void*) android_content_AssetManager_openXmlAssetNative },
1699
1700 // Arrays.
1701 { "getArrayStringResource","(I)[Ljava/lang/String;",
1702 (void*) android_content_AssetManager_getArrayStringResource },
1703 { "getArrayStringInfo","(I)[I",
1704 (void*) android_content_AssetManager_getArrayStringInfo },
1705 { "getArrayIntResource","(I)[I",
1706 (void*) android_content_AssetManager_getArrayIntResource },
1707
1708 // Bookkeeping.
1709 { "init", "()V",
1710 (void*) android_content_AssetManager_init },
1711 { "destroy", "()V",
1712 (void*) android_content_AssetManager_destroy },
1713 { "getGlobalAssetCount", "()I",
1714 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001715 { "getAssetAllocations", "()Ljava/lang/String;",
1716 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001717 { "getGlobalAssetManagerCount", "()I",
1718 (void*) android_content_AssetManager_getGlobalAssetCount },
1719};
1720
1721int register_android_content_AssetManager(JNIEnv* env)
1722{
1723 jclass typedValue = env->FindClass("android/util/TypedValue");
1724 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1725 gTypedValueOffsets.mType
1726 = env->GetFieldID(typedValue, "type", "I");
1727 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1728 gTypedValueOffsets.mData
1729 = env->GetFieldID(typedValue, "data", "I");
1730 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1731 gTypedValueOffsets.mString
1732 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1733 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1734 gTypedValueOffsets.mAssetCookie
1735 = env->GetFieldID(typedValue, "assetCookie", "I");
1736 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1737 gTypedValueOffsets.mResourceId
1738 = env->GetFieldID(typedValue, "resourceId", "I");
1739 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1740 gTypedValueOffsets.mChangingConfigurations
1741 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1742 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1743 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1744 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1745
1746 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1747 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1748 gAssetFileDescriptorOffsets.mFd
1749 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1750 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1751 gAssetFileDescriptorOffsets.mStartOffset
1752 = env->GetFieldID(assetFd, "mStartOffset", "J");
1753 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1754 gAssetFileDescriptorOffsets.mLength
1755 = env->GetFieldID(assetFd, "mLength", "J");
1756 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1757
1758 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1759 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1760 gAssetManagerOffsets.mObject
1761 = env->GetFieldID(assetManager, "mObject", "I");
1762 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1763
Carl Shapiroc1318ba2011-03-03 14:22:28 -08001764 jclass stringClass = env->FindClass("java/lang/String");
1765 LOG_FATAL_IF(stringClass == NULL, "Unable to find class java/lang/String");
1766 g_stringClass = (jclass)env->NewGlobalRef(stringClass);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001767
1768 return AndroidRuntime::registerNativeMethods(env,
1769 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1770}
1771
1772}; // namespace android