blob: a82a21eae19ac6af7c0105bc14d905aba417d117 [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**
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 "asset"
19
Dianne Hackbornb8d81672009-11-20 14:26:42 -080020#define DEBUG_STYLES(x) //x
21
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080022#include <android_runtime/android_util_AssetManager.h>
23
24#include "jni.h"
25#include "JNIHelp.h"
26#include "android_util_Binder.h"
27#include <utils/misc.h>
28#include <android_runtime/AndroidRuntime.h>
29#include <utils/Log.h>
30
31#include <utils/Asset.h>
32#include <utils/AssetManager.h>
33#include <utils/ResourceTypes.h>
34
35#include <stdio.h>
36
37namespace android {
38
39// ----------------------------------------------------------------------------
40
41static struct typedvalue_offsets_t
42{
43 jfieldID mType;
44 jfieldID mData;
45 jfieldID mString;
46 jfieldID mAssetCookie;
47 jfieldID mResourceId;
48 jfieldID mChangingConfigurations;
49 jfieldID mDensity;
50} gTypedValueOffsets;
51
52static struct assetfiledescriptor_offsets_t
53{
54 jfieldID mFd;
55 jfieldID mStartOffset;
56 jfieldID mLength;
57} gAssetFileDescriptorOffsets;
58
59static struct assetmanager_offsets_t
60{
61 jfieldID mObject;
62} gAssetManagerOffsets;
63
64jclass g_stringClass = NULL;
65
66// ----------------------------------------------------------------------------
67
68static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL)
69{
70 jclass npeClazz;
71
72 npeClazz = env->FindClass(exc);
73 LOG_FATAL_IF(npeClazz == NULL, "Unable to find class %s", exc);
74
75 env->ThrowNew(npeClazz, msg);
76}
77
78enum {
Dianne Hackborn0d221012009-07-29 15:41:19 -070079 STYLE_NUM_ENTRIES = 6,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080080 STYLE_TYPE = 0,
81 STYLE_DATA = 1,
82 STYLE_ASSET_COOKIE = 2,
83 STYLE_RESOURCE_ID = 3,
Dianne Hackborn0d221012009-07-29 15:41:19 -070084 STYLE_CHANGING_CONFIGURATIONS = 4,
85 STYLE_DENSITY = 5
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080086};
87
88static jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
89 const Res_value& value, uint32_t ref, ssize_t block,
90 uint32_t typeSpecFlags, ResTable_config* config = NULL);
91
92jint copyValue(JNIEnv* env, jobject outValue, const ResTable* table,
93 const Res_value& value, uint32_t ref, ssize_t block,
94 uint32_t typeSpecFlags, ResTable_config* config)
95{
96 env->SetIntField(outValue, gTypedValueOffsets.mType, value.dataType);
97 env->SetIntField(outValue, gTypedValueOffsets.mAssetCookie,
98 (jint)table->getTableCookie(block));
99 env->SetIntField(outValue, gTypedValueOffsets.mData, value.data);
100 env->SetObjectField(outValue, gTypedValueOffsets.mString, NULL);
101 env->SetIntField(outValue, gTypedValueOffsets.mResourceId, ref);
102 env->SetIntField(outValue, gTypedValueOffsets.mChangingConfigurations,
103 typeSpecFlags);
104 if (config != NULL) {
105 env->SetIntField(outValue, gTypedValueOffsets.mDensity, config->density);
106 }
107 return block;
108}
109
110// ----------------------------------------------------------------------------
111
112// this guy is exported to other jni routines
113AssetManager* assetManagerForJavaObject(JNIEnv* env, jobject obj)
114{
115 AssetManager* am = (AssetManager*)env->GetIntField(obj, gAssetManagerOffsets.mObject);
116 if (am != NULL) {
117 return am;
118 }
119 jniThrowException(env, "java/lang/IllegalStateException", "AssetManager has been finalized!");
120 return NULL;
121}
122
123static jint android_content_AssetManager_openAsset(JNIEnv* env, jobject clazz,
124 jstring fileName, jint mode)
125{
126 AssetManager* am = assetManagerForJavaObject(env, clazz);
127 if (am == NULL) {
128 return 0;
129 }
130
131 LOGV("openAsset in %p (Java object %p)\n", am, clazz);
132
133 if (fileName == NULL || am == NULL) {
134 doThrow(env, "java/lang/NullPointerException");
135 return -1;
136 }
137
138 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
139 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
140 doThrow(env, "java/lang/IllegalArgumentException");
141 return -1;
142 }
143
144 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
145 Asset* a = am->open(fileName8, (Asset::AccessMode)mode);
146
147 if (a == NULL) {
148 doThrow(env, "java/io/FileNotFoundException", fileName8);
149 env->ReleaseStringUTFChars(fileName, fileName8);
150 return -1;
151 }
152 env->ReleaseStringUTFChars(fileName, fileName8);
153
154 //printf("Created Asset Stream: %p\n", a);
155
156 return (jint)a;
157}
158
159static jobject returnParcelFileDescriptor(JNIEnv* env, Asset* a, jlongArray outOffsets)
160{
161 off_t startOffset, length;
162 int fd = a->openFileDescriptor(&startOffset, &length);
163 delete a;
164
165 if (fd < 0) {
166 doThrow(env, "java/io/FileNotFoundException",
167 "This file can not be opened as a file descriptor; it is probably compressed");
168 return NULL;
169 }
170
171 jlong* offsets = (jlong*)env->GetPrimitiveArrayCritical(outOffsets, 0);
172 if (offsets == NULL) {
173 close(fd);
174 return NULL;
175 }
176
177 offsets[0] = startOffset;
178 offsets[1] = length;
179
180 env->ReleasePrimitiveArrayCritical(outOffsets, offsets, 0);
181
182 jobject fileDesc = newFileDescriptor(env, fd);
183 if (fileDesc == NULL) {
184 close(fd);
185 return NULL;
186 }
187
188 return newParcelFileDescriptor(env, fileDesc);
189}
190
191static jobject android_content_AssetManager_openAssetFd(JNIEnv* env, jobject clazz,
192 jstring fileName, jlongArray outOffsets)
193{
194 AssetManager* am = assetManagerForJavaObject(env, clazz);
195 if (am == NULL) {
196 return NULL;
197 }
198
199 LOGV("openAssetFd in %p (Java object %p)\n", am, clazz);
200
201 if (fileName == NULL || am == NULL) {
202 doThrow(env, "java/lang/NullPointerException");
203 return NULL;
204 }
205
206 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
207 Asset* a = am->open(fileName8, Asset::ACCESS_RANDOM);
208
209 if (a == NULL) {
210 doThrow(env, "java/io/FileNotFoundException", fileName8);
211 env->ReleaseStringUTFChars(fileName, fileName8);
212 return NULL;
213 }
214 env->ReleaseStringUTFChars(fileName, fileName8);
215
216 //printf("Created Asset Stream: %p\n", a);
217
218 return returnParcelFileDescriptor(env, a, outOffsets);
219}
220
221static jint android_content_AssetManager_openNonAssetNative(JNIEnv* env, jobject clazz,
222 jint cookie,
223 jstring fileName,
224 jint mode)
225{
226 AssetManager* am = assetManagerForJavaObject(env, clazz);
227 if (am == NULL) {
228 return 0;
229 }
230
231 LOGV("openNonAssetNative in %p (Java object %p)\n", am, clazz);
232
233 if (fileName == NULL || am == NULL) {
234 doThrow(env, "java/lang/NullPointerException");
235 return -1;
236 }
237
238 if (mode != Asset::ACCESS_UNKNOWN && mode != Asset::ACCESS_RANDOM
239 && mode != Asset::ACCESS_STREAMING && mode != Asset::ACCESS_BUFFER) {
240 doThrow(env, "java/lang/IllegalArgumentException");
241 return -1;
242 }
243
244 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
245 Asset* a = cookie
246 ? am->openNonAsset((void*)cookie, fileName8, (Asset::AccessMode)mode)
247 : am->openNonAsset(fileName8, (Asset::AccessMode)mode);
248
249 if (a == NULL) {
250 doThrow(env, "java/io/FileNotFoundException", fileName8);
251 env->ReleaseStringUTFChars(fileName, fileName8);
252 return -1;
253 }
254 env->ReleaseStringUTFChars(fileName, fileName8);
255
256 //printf("Created Asset Stream: %p\n", a);
257
258 return (jint)a;
259}
260
261static jobject android_content_AssetManager_openNonAssetFdNative(JNIEnv* env, jobject clazz,
262 jint cookie,
263 jstring fileName,
264 jlongArray outOffsets)
265{
266 AssetManager* am = assetManagerForJavaObject(env, clazz);
267 if (am == NULL) {
268 return NULL;
269 }
270
271 LOGV("openNonAssetFd in %p (Java object %p)\n", am, clazz);
272
273 if (fileName == NULL || am == NULL) {
274 doThrow(env, "java/lang/NullPointerException");
275 return NULL;
276 }
277
278 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
279 Asset* a = cookie
280 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_RANDOM)
281 : am->openNonAsset(fileName8, Asset::ACCESS_RANDOM);
282
283 if (a == NULL) {
284 doThrow(env, "java/io/FileNotFoundException", fileName8);
285 env->ReleaseStringUTFChars(fileName, fileName8);
286 return NULL;
287 }
288 env->ReleaseStringUTFChars(fileName, fileName8);
289
290 //printf("Created Asset Stream: %p\n", a);
291
292 return returnParcelFileDescriptor(env, a, outOffsets);
293}
294
295static jobjectArray android_content_AssetManager_list(JNIEnv* env, jobject clazz,
296 jstring fileName)
297{
298 AssetManager* am = assetManagerForJavaObject(env, clazz);
299 if (am == NULL) {
300 return NULL;
301 }
302
303 if (fileName == NULL || am == NULL) {
304 doThrow(env, "java/lang/NullPointerException");
305 return NULL;
306 }
307
308 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
309
310 AssetDir* dir = am->openDir(fileName8);
311
312 env->ReleaseStringUTFChars(fileName, fileName8);
313
314 if (dir == NULL) {
315 doThrow(env, "java/io/FileNotFoundException", fileName8);
316 return NULL;
317 }
318
319 jclass cls = env->FindClass("java/lang/String");
320 LOG_FATAL_IF(cls == NULL, "No string class?!?");
321 if (cls == NULL) {
322 delete dir;
323 return NULL;
324 }
325
326 size_t N = dir->getFileCount();
327
328 jobjectArray array = env->NewObjectArray(dir->getFileCount(),
329 cls, NULL);
330 if (array == NULL) {
331 doThrow(env, "java/lang/OutOfMemoryError");
332 delete dir;
333 return NULL;
334 }
335
336 for (size_t i=0; i<N; i++) {
337 const String8& name = dir->getFileName(i);
338 jstring str = env->NewStringUTF(name.string());
339 if (str == NULL) {
340 doThrow(env, "java/lang/OutOfMemoryError");
341 delete dir;
342 return NULL;
343 }
344 env->SetObjectArrayElement(array, i, str);
345 }
346
347 delete dir;
348
349 return array;
350}
351
352static void android_content_AssetManager_destroyAsset(JNIEnv* env, jobject clazz,
353 jint asset)
354{
355 Asset* a = (Asset*)asset;
356
357 //printf("Destroying Asset Stream: %p\n", a);
358
359 if (a == NULL) {
360 doThrow(env, "java/lang/NullPointerException");
361 return;
362 }
363
364 delete a;
365}
366
367static jint android_content_AssetManager_readAssetChar(JNIEnv* env, jobject clazz,
368 jint asset)
369{
370 Asset* a = (Asset*)asset;
371
372 if (a == NULL) {
373 doThrow(env, "java/lang/NullPointerException");
374 return -1;
375 }
376
377 uint8_t b;
378 ssize_t res = a->read(&b, 1);
379 return res == 1 ? b : -1;
380}
381
382static jint android_content_AssetManager_readAsset(JNIEnv* env, jobject clazz,
383 jint asset, jbyteArray bArray,
384 jint off, jint len)
385{
386 Asset* a = (Asset*)asset;
387
388 if (a == NULL || bArray == NULL) {
389 doThrow(env, "java/lang/NullPointerException");
390 return -1;
391 }
392
393 if (len == 0) {
394 return 0;
395 }
396
397 jsize bLen = env->GetArrayLength(bArray);
398 if (off < 0 || off >= bLen || len < 0 || len > bLen || (off+len) > bLen) {
399 doThrow(env, "java/lang/IndexOutOfBoundsException");
400 return -1;
401 }
402
403 jbyte* b = env->GetByteArrayElements(bArray, NULL);
404 ssize_t res = a->read(b+off, len);
405 env->ReleaseByteArrayElements(bArray, b, 0);
406
407 if (res > 0) return res;
408
409 if (res < 0) {
410 doThrow(env, "java/io/IOException");
411 }
412 return -1;
413}
414
415static jlong android_content_AssetManager_seekAsset(JNIEnv* env, jobject clazz,
416 jint asset,
417 jlong offset, jint whence)
418{
419 Asset* a = (Asset*)asset;
420
421 if (a == NULL) {
422 doThrow(env, "java/lang/NullPointerException");
423 return -1;
424 }
425
426 return a->seek(
427 offset, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
428}
429
430static jlong android_content_AssetManager_getAssetLength(JNIEnv* env, jobject clazz,
431 jint asset)
432{
433 Asset* a = (Asset*)asset;
434
435 if (a == NULL) {
436 doThrow(env, "java/lang/NullPointerException");
437 return -1;
438 }
439
440 return a->getLength();
441}
442
443static jlong android_content_AssetManager_getAssetRemainingLength(JNIEnv* env, jobject clazz,
444 jint asset)
445{
446 Asset* a = (Asset*)asset;
447
448 if (a == NULL) {
449 doThrow(env, "java/lang/NullPointerException");
450 return -1;
451 }
452
453 return a->getRemainingLength();
454}
455
456static jint android_content_AssetManager_addAssetPath(JNIEnv* env, jobject clazz,
457 jstring path)
458{
459 if (path == NULL) {
460 doThrow(env, "java/lang/NullPointerException");
461 return JNI_FALSE;
462 }
463
464 AssetManager* am = assetManagerForJavaObject(env, clazz);
465 if (am == NULL) {
466 return JNI_FALSE;
467 }
468
469 const char* path8 = env->GetStringUTFChars(path, NULL);
470
471 void* cookie;
472 bool res = am->addAssetPath(String8(path8), &cookie);
473
474 env->ReleaseStringUTFChars(path, path8);
475
476 return (res) ? (jint)cookie : 0;
477}
478
479static jboolean android_content_AssetManager_isUpToDate(JNIEnv* env, jobject clazz)
480{
481 AssetManager* am = assetManagerForJavaObject(env, clazz);
482 if (am == NULL) {
483 return JNI_TRUE;
484 }
485 return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
486}
487
488static void android_content_AssetManager_setLocale(JNIEnv* env, jobject clazz,
489 jstring locale)
490{
491 if (locale == NULL) {
492 doThrow(env, "java/lang/NullPointerException");
493 return;
494 }
495
496 const char* locale8 = env->GetStringUTFChars(locale, NULL);
497
498 AssetManager* am = assetManagerForJavaObject(env, clazz);
499 if (am == NULL) {
500 return;
501 }
502
503 am->setLocale(locale8);
504
505 env->ReleaseStringUTFChars(locale, locale8);
506}
507
508static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
509{
510 Vector<String8> locales;
511
512 AssetManager* am = assetManagerForJavaObject(env, clazz);
513 if (am == NULL) {
514 return NULL;
515 }
516
517 am->getLocales(&locales);
518
519 const int N = locales.size();
520
521 jobjectArray result = env->NewObjectArray(N, g_stringClass, NULL);
522 if (result == NULL) {
523 return NULL;
524 }
525
526 for (int i=0; i<N; i++) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800527 env->SetObjectArrayElement(result, i, env->NewStringUTF(locales[i].string()));
528 }
529
530 return result;
531}
532
533static void android_content_AssetManager_setConfiguration(JNIEnv* env, jobject clazz,
534 jint mcc, jint mnc,
535 jstring locale, jint orientation,
536 jint touchscreen, jint density,
537 jint keyboard, jint keyboardHidden,
538 jint navigation,
539 jint screenWidth, jint screenHeight,
Tobias Haamel27b28b32010-02-09 23:09:17 +0100540 jint screenLayout, jint uiMode,
541 jint sdkVersion)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800542{
543 AssetManager* am = assetManagerForJavaObject(env, clazz);
544 if (am == NULL) {
545 return;
546 }
547
548 ResTable_config config;
549 memset(&config, 0, sizeof(config));
550
551 const char* locale8 = locale != NULL ? env->GetStringUTFChars(locale, NULL) : NULL;
552
553 config.mcc = (uint16_t)mcc;
554 config.mnc = (uint16_t)mnc;
555 config.orientation = (uint8_t)orientation;
556 config.touchscreen = (uint8_t)touchscreen;
557 config.density = (uint16_t)density;
558 config.keyboard = (uint8_t)keyboard;
Dianne Hackbornc4db95c2009-07-21 17:46:02 -0700559 config.inputFlags = (uint8_t)keyboardHidden;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800560 config.navigation = (uint8_t)navigation;
561 config.screenWidth = (uint16_t)screenWidth;
562 config.screenHeight = (uint16_t)screenHeight;
Dianne Hackborn723738c2009-06-25 19:48:04 -0700563 config.screenLayout = (uint8_t)screenLayout;
Tobias Haamel27b28b32010-02-09 23:09:17 +0100564 config.uiMode = (uint8_t)uiMode;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800565 config.sdkVersion = (uint16_t)sdkVersion;
566 config.minorVersion = 0;
567 am->setConfiguration(config, locale8);
568
569 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
570}
571
572static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
573 jstring name,
574 jstring defType,
575 jstring defPackage)
576{
577 if (name == NULL) {
578 doThrow(env, "java/lang/NullPointerException");
579 return 0;
580 }
581
582 AssetManager* am = assetManagerForJavaObject(env, clazz);
583 if (am == NULL) {
584 return 0;
585 }
586
587 const char16_t* name16 = env->GetStringChars(name, NULL);
588 jsize nameLen = env->GetStringLength(name);
589 const char16_t* defType16 = defType
590 ? env->GetStringChars(defType, NULL) : NULL;
591 jsize defTypeLen = defType
592 ? env->GetStringLength(defType) : 0;
593 const char16_t* defPackage16 = defPackage
594 ? env->GetStringChars(defPackage, NULL) : NULL;
595 jsize defPackageLen = defPackage
596 ? env->GetStringLength(defPackage) : 0;
597
598 jint ident = am->getResources().identifierForName(
599 name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen);
600
601 if (defPackage16) {
602 env->ReleaseStringChars(defPackage, defPackage16);
603 }
604 if (defType16) {
605 env->ReleaseStringChars(defType, defType16);
606 }
607 env->ReleaseStringChars(name, name16);
608
609 return ident;
610}
611
612static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
613 jint resid)
614{
615 AssetManager* am = assetManagerForJavaObject(env, clazz);
616 if (am == NULL) {
617 return NULL;
618 }
619
620 ResTable::resource_name name;
621 if (!am->getResources().getResourceName(resid, &name)) {
622 return NULL;
623 }
624
625 String16 str;
626 if (name.package != NULL) {
627 str.setTo(name.package, name.packageLen);
628 }
629 if (name.type != NULL) {
630 if (str.size() > 0) {
631 char16_t div = ':';
632 str.append(&div, 1);
633 }
634 str.append(name.type, name.typeLen);
635 }
636 if (name.name != NULL) {
637 if (str.size() > 0) {
638 char16_t div = '/';
639 str.append(&div, 1);
640 }
641 str.append(name.name, name.nameLen);
642 }
643
644 return env->NewString((const jchar*)str.string(), str.size());
645}
646
647static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
648 jint resid)
649{
650 AssetManager* am = assetManagerForJavaObject(env, clazz);
651 if (am == NULL) {
652 return NULL;
653 }
654
655 ResTable::resource_name name;
656 if (!am->getResources().getResourceName(resid, &name)) {
657 return NULL;
658 }
659
660 if (name.package != NULL) {
661 return env->NewString((const jchar*)name.package, name.packageLen);
662 }
663
664 return NULL;
665}
666
667static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
668 jint resid)
669{
670 AssetManager* am = assetManagerForJavaObject(env, clazz);
671 if (am == NULL) {
672 return NULL;
673 }
674
675 ResTable::resource_name name;
676 if (!am->getResources().getResourceName(resid, &name)) {
677 return NULL;
678 }
679
680 if (name.type != NULL) {
681 return env->NewString((const jchar*)name.type, name.typeLen);
682 }
683
684 return NULL;
685}
686
687static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
688 jint resid)
689{
690 AssetManager* am = assetManagerForJavaObject(env, clazz);
691 if (am == NULL) {
692 return NULL;
693 }
694
695 ResTable::resource_name name;
696 if (!am->getResources().getResourceName(resid, &name)) {
697 return NULL;
698 }
699
700 if (name.name != NULL) {
701 return env->NewString((const jchar*)name.name, name.nameLen);
702 }
703
704 return NULL;
705}
706
707static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
708 jint ident,
709 jobject outValue,
710 jboolean resolve)
711{
712 AssetManager* am = assetManagerForJavaObject(env, clazz);
713 if (am == NULL) {
714 return 0;
715 }
716 const ResTable& res(am->getResources());
717
718 Res_value value;
719 ResTable_config config;
720 uint32_t typeSpecFlags;
721 ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config);
722 uint32_t ref = ident;
723 if (resolve) {
724 block = res.resolveReference(&value, block, &ref);
725 }
726 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
727}
728
729static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
730 jint ident, jint bagEntryId,
731 jobject outValue, jboolean resolve)
732{
733 AssetManager* am = assetManagerForJavaObject(env, clazz);
734 if (am == NULL) {
735 return 0;
736 }
737 const ResTable& res(am->getResources());
738
739 // Now lock down the resource object and start pulling stuff from it.
740 res.lock();
741
742 ssize_t block = -1;
743 Res_value value;
744
745 const ResTable::bag_entry* entry = NULL;
746 uint32_t typeSpecFlags;
747 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
748
749 for (ssize_t i=0; i<entryCount; i++) {
750 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
751 block = entry->stringBlock;
752 value = entry->map.value;
753 }
754 entry++;
755 }
756
757 res.unlock();
758
759 if (block < 0) {
760 return block;
761 }
762
763 uint32_t ref = ident;
764 if (resolve) {
765 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
766 }
767 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
768}
769
770static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
771{
772 AssetManager* am = assetManagerForJavaObject(env, clazz);
773 if (am == NULL) {
774 return 0;
775 }
776 return am->getResources().getTableCount();
777}
778
779static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
780 jint block)
781{
782 AssetManager* am = assetManagerForJavaObject(env, clazz);
783 if (am == NULL) {
784 return 0;
785 }
786 return (jint)am->getResources().getTableStringBlock(block);
787}
788
789static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
790 jint cookie)
791{
792 AssetManager* am = assetManagerForJavaObject(env, clazz);
793 if (am == NULL) {
794 return NULL;
795 }
796 String8 name(am->getAssetPath((void*)cookie));
797 if (name.length() == 0) {
798 doThrow(env, "java/lang/IndexOutOfBoundsException");
799 return NULL;
800 }
801 jstring str = env->NewStringUTF(name.string());
802 if (str == NULL) {
803 doThrow(env, "java/lang/OutOfMemoryError");
804 return NULL;
805 }
806 return str;
807}
808
809static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
810{
811 AssetManager* am = assetManagerForJavaObject(env, clazz);
812 if (am == NULL) {
813 return 0;
814 }
815 return (jint)(new ResTable::Theme(am->getResources()));
816}
817
818static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
819 jint themeInt)
820{
821 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
822 delete theme;
823}
824
825static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
826 jint themeInt,
827 jint styleRes,
828 jboolean force)
829{
830 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
831 theme->applyStyle(styleRes, force ? true : false);
832}
833
834static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
835 jint destInt, jint srcInt)
836{
837 ResTable::Theme* dest = (ResTable::Theme*)destInt;
838 ResTable::Theme* src = (ResTable::Theme*)srcInt;
839 dest->setTo(*src);
840}
841
842static jint android_content_AssetManager_loadThemeAttributeValue(
843 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
844{
845 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
846 const ResTable& res(theme->getResTable());
847
848 Res_value value;
849 // XXX value could be different in different configs!
850 uint32_t typeSpecFlags = 0;
851 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
852 uint32_t ref = 0;
853 if (resolve) {
854 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
855 }
856 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
857}
858
859static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
860 jint themeInt, jint pri,
861 jstring tag, jstring prefix)
862{
863 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
864 const ResTable& res(theme->getResTable());
865
866 if (tag == NULL) {
867 doThrow(env, "java/lang/NullPointerException");
868 return;
869 }
870
871 const char* tag8 = env->GetStringUTFChars(tag, NULL);
872 const char* prefix8 = NULL;
873 if (prefix != NULL) {
874 prefix8 = env->GetStringUTFChars(prefix, NULL);
875 }
876
877 // XXX Need to use params.
878 theme->dumpToLog();
879
880 if (prefix8 != NULL) {
881 env->ReleaseStringUTFChars(prefix, prefix8);
882 }
883 env->ReleaseStringUTFChars(tag, tag8);
884}
885
886static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
887 jint themeToken,
888 jint defStyleAttr,
889 jint defStyleRes,
890 jint xmlParserToken,
891 jintArray attrs,
892 jintArray outValues,
893 jintArray outIndices)
894{
895 if (themeToken == 0 || attrs == NULL || outValues == NULL) {
896 doThrow(env, "java/lang/NullPointerException");
897 return JNI_FALSE;
898 }
899
Dianne Hackbornb8d81672009-11-20 14:26:42 -0800900 DEBUG_STYLES(LOGI("APPLY STYLE: theme=0x%x defStyleAttr=0x%x defStyleRes=0x%x xml=0x%x",
901 themeToken, defStyleAttr, defStyleRes, xmlParserToken));
902
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800903 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
904 const ResTable& res = theme->getResTable();
905 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -0700906 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800907 Res_value value;
908
909 const jsize NI = env->GetArrayLength(attrs);
910 const jsize NV = env->GetArrayLength(outValues);
911 if (NV < (NI*STYLE_NUM_ENTRIES)) {
912 doThrow(env, "java/lang/IndexOutOfBoundsException");
913 return JNI_FALSE;
914 }
915
916 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
917 if (src == NULL) {
918 doThrow(env, "java/lang/OutOfMemoryError");
919 return JNI_FALSE;
920 }
921
922 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
923 jint* dest = baseDest;
924 if (dest == NULL) {
925 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
926 doThrow(env, "java/lang/OutOfMemoryError");
927 return JNI_FALSE;
928 }
929
930 jint* indices = NULL;
931 int indicesIdx = 0;
932 if (outIndices != NULL) {
933 if (env->GetArrayLength(outIndices) > NI) {
934 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
935 }
936 }
937
938 // Load default style from attribute, if specified...
939 uint32_t defStyleBagTypeSetFlags = 0;
940 if (defStyleAttr != 0) {
941 Res_value value;
942 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
943 if (value.dataType == Res_value::TYPE_REFERENCE) {
944 defStyleRes = value.data;
945 }
946 }
947 }
948
949 // Retrieve the style class associated with the current XML tag.
950 int style = 0;
951 uint32_t styleBagTypeSetFlags = 0;
952 if (xmlParser != NULL) {
953 ssize_t idx = xmlParser->indexOfStyle();
954 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
955 if (value.dataType == value.TYPE_ATTRIBUTE) {
956 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
957 value.dataType = Res_value::TYPE_NULL;
958 }
959 }
960 if (value.dataType == value.TYPE_REFERENCE) {
961 style = value.data;
962 }
963 }
964 }
965
966 // Now lock down the resource object and start pulling stuff from it.
967 res.lock();
968
969 // Retrieve the default style bag, if requested.
970 const ResTable::bag_entry* defStyleEnt = NULL;
971 uint32_t defStyleTypeSetFlags = 0;
972 ssize_t bagOff = defStyleRes != 0
973 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
974 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
975 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
976 (bagOff >= 0 ? bagOff : 0);
977
978 // Retrieve the style class bag, if requested.
979 const ResTable::bag_entry* styleEnt = NULL;
980 uint32_t styleTypeSetFlags = 0;
981 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
982 styleTypeSetFlags |= styleBagTypeSetFlags;
983 const ResTable::bag_entry* endStyleEnt = styleEnt +
984 (bagOff >= 0 ? bagOff : 0);
985
986 // Retrieve the XML attributes, if requested.
987 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
988 jsize ix=0;
989 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
990
991 static const ssize_t kXmlBlock = 0x10000000;
992
993 // Now iterate through all of the attributes that the client has requested,
994 // filling in each with whatever data we can find.
995 ssize_t block = 0;
996 uint32_t typeSetFlags;
997 for (jsize ii=0; ii<NI; ii++) {
998 const uint32_t curIdent = (uint32_t)src[ii];
999
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001000 DEBUG_STYLES(LOGI("RETRIEVING ATTR 0x%08x...", curIdent));
1001
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001002 // Try to find a value for this attribute... we prioritize values
1003 // coming from, first XML attributes, then XML style, then default
1004 // style, and finally the theme.
1005 value.dataType = Res_value::TYPE_NULL;
1006 value.data = 0;
1007 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001008 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001009
1010 // Skip through XML attributes until the end or the next possible match.
1011 while (ix < NX && curIdent > curXmlAttr) {
1012 ix++;
1013 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1014 }
1015 // Retrieve the current XML attribute if it matches, and step to next.
1016 if (ix < NX && curIdent == curXmlAttr) {
1017 block = kXmlBlock;
1018 xmlParser->getAttributeValue(ix, &value);
1019 ix++;
1020 curXmlAttr = xmlParser->getAttributeNameResID(ix);
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001021 DEBUG_STYLES(LOGI("-> From XML: type=0x%x, data=0x%08x",
1022 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001023 }
1024
1025 // Skip through the style values until the end or the next possible match.
1026 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1027 styleEnt++;
1028 }
1029 // Retrieve the current style attribute if it matches, and step to next.
1030 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1031 if (value.dataType == Res_value::TYPE_NULL) {
1032 block = styleEnt->stringBlock;
1033 typeSetFlags = styleTypeSetFlags;
1034 value = styleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001035 DEBUG_STYLES(LOGI("-> From style: type=0x%x, data=0x%08x",
1036 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001037 }
1038 styleEnt++;
1039 }
1040
1041 // Skip through the default style values until the end or the next possible match.
1042 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1043 defStyleEnt++;
1044 }
1045 // Retrieve the current default style attribute if it matches, and step to next.
1046 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1047 if (value.dataType == Res_value::TYPE_NULL) {
1048 block = defStyleEnt->stringBlock;
1049 typeSetFlags = defStyleTypeSetFlags;
1050 value = defStyleEnt->map.value;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001051 DEBUG_STYLES(LOGI("-> From def style: type=0x%x, data=0x%08x",
1052 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 }
1054 defStyleEnt++;
1055 }
1056
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001057 uint32_t resid = 0;
1058 if (value.dataType != Res_value::TYPE_NULL) {
1059 // Take care of resolving the found resource to its final value.
Dianne Hackborn0d221012009-07-29 15:41:19 -07001060 ssize_t newBlock = theme->resolveAttributeReference(&value, block,
1061 &resid, &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001062 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001063 DEBUG_STYLES(LOGI("-> Resolved attr: type=0x%x, data=0x%08x",
1064 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001065 } else {
1066 // If we still don't have a value for this attribute, try to find
1067 // it in the theme!
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001068 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1069 if (newBlock >= 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001070 DEBUG_STYLES(LOGI("-> From theme: type=0x%x, data=0x%08x",
1071 value.dataType, value.data));
Dianne Hackborn0d221012009-07-29 15:41:19 -07001072 newBlock = res.resolveReference(&value, block, &resid,
1073 &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 if (newBlock >= 0) block = newBlock;
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001075 DEBUG_STYLES(LOGI("-> Resolved theme: type=0x%x, data=0x%08x",
1076 value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001077 }
1078 }
1079
1080 // Deal with the special @null value -- it turns back to TYPE_NULL.
1081 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001082 DEBUG_STYLES(LOGI("-> Setting to @null!"));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001083 value.dataType = Res_value::TYPE_NULL;
1084 }
1085
Dianne Hackbornb8d81672009-11-20 14:26:42 -08001086 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x",
1087 curIdent, value.dataType, value.data));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001088
1089 // Write the final value back to Java.
1090 dest[STYLE_TYPE] = value.dataType;
1091 dest[STYLE_DATA] = value.data;
1092 dest[STYLE_ASSET_COOKIE] =
1093 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1094 dest[STYLE_RESOURCE_ID] = resid;
1095 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001096 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001097
1098 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1099 indicesIdx++;
1100 indices[indicesIdx] = ii;
1101 }
1102
1103 dest += STYLE_NUM_ENTRIES;
1104 }
1105
1106 res.unlock();
1107
1108 if (indices != NULL) {
1109 indices[0] = indicesIdx;
1110 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1111 }
1112 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1113 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1114
1115 return JNI_TRUE;
1116}
1117
1118static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1119 jint xmlParserToken,
1120 jintArray attrs,
1121 jintArray outValues,
1122 jintArray outIndices)
1123{
1124 if (xmlParserToken == 0 || attrs == NULL || outValues == NULL) {
1125 doThrow(env, "java/lang/NullPointerException");
1126 return JNI_FALSE;
1127 }
1128
1129 AssetManager* am = assetManagerForJavaObject(env, clazz);
1130 if (am == NULL) {
1131 return JNI_FALSE;
1132 }
1133 const ResTable& res(am->getResources());
1134 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001135 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001136 Res_value value;
1137
1138 const jsize NI = env->GetArrayLength(attrs);
1139 const jsize NV = env->GetArrayLength(outValues);
1140 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1141 doThrow(env, "java/lang/IndexOutOfBoundsException");
1142 return JNI_FALSE;
1143 }
1144
1145 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1146 if (src == NULL) {
1147 doThrow(env, "java/lang/OutOfMemoryError");
1148 return JNI_FALSE;
1149 }
1150
1151 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1152 jint* dest = baseDest;
1153 if (dest == NULL) {
1154 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1155 doThrow(env, "java/lang/OutOfMemoryError");
1156 return JNI_FALSE;
1157 }
1158
1159 jint* indices = NULL;
1160 int indicesIdx = 0;
1161 if (outIndices != NULL) {
1162 if (env->GetArrayLength(outIndices) > NI) {
1163 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1164 }
1165 }
1166
1167 // Now lock down the resource object and start pulling stuff from it.
1168 res.lock();
1169
1170 // Retrieve the XML attributes, if requested.
1171 const jsize NX = xmlParser->getAttributeCount();
1172 jsize ix=0;
1173 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1174
1175 static const ssize_t kXmlBlock = 0x10000000;
1176
1177 // Now iterate through all of the attributes that the client has requested,
1178 // filling in each with whatever data we can find.
1179 ssize_t block = 0;
1180 uint32_t typeSetFlags;
1181 for (jsize ii=0; ii<NI; ii++) {
1182 const uint32_t curIdent = (uint32_t)src[ii];
1183
1184 // Try to find a value for this attribute...
1185 value.dataType = Res_value::TYPE_NULL;
1186 value.data = 0;
1187 typeSetFlags = 0;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001188 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001189
1190 // Skip through XML attributes until the end or the next possible match.
1191 while (ix < NX && curIdent > curXmlAttr) {
1192 ix++;
1193 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1194 }
1195 // Retrieve the current XML attribute if it matches, and step to next.
1196 if (ix < NX && curIdent == curXmlAttr) {
1197 block = kXmlBlock;
1198 xmlParser->getAttributeValue(ix, &value);
1199 ix++;
1200 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1201 }
1202
1203 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1204 uint32_t resid = 0;
1205 if (value.dataType != Res_value::TYPE_NULL) {
1206 // Take care of resolving the found resource to its final value.
1207 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001208 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1209 &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001210 if (newBlock >= 0) block = newBlock;
1211 }
1212
1213 // Deal with the special @null value -- it turns back to TYPE_NULL.
1214 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1215 value.dataType = Res_value::TYPE_NULL;
1216 }
1217
1218 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1219
1220 // Write the final value back to Java.
1221 dest[STYLE_TYPE] = value.dataType;
1222 dest[STYLE_DATA] = value.data;
1223 dest[STYLE_ASSET_COOKIE] =
1224 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1225 dest[STYLE_RESOURCE_ID] = resid;
1226 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001227 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001228
1229 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1230 indicesIdx++;
1231 indices[indicesIdx] = ii;
1232 }
1233
1234 dest += STYLE_NUM_ENTRIES;
1235 }
1236
1237 res.unlock();
1238
1239 if (indices != NULL) {
1240 indices[0] = indicesIdx;
1241 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1242 }
1243
1244 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1245 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1246
1247 return JNI_TRUE;
1248}
1249
1250static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1251 jint id)
1252{
1253 AssetManager* am = assetManagerForJavaObject(env, clazz);
1254 if (am == NULL) {
1255 return NULL;
1256 }
1257 const ResTable& res(am->getResources());
1258
1259 res.lock();
1260 const ResTable::bag_entry* defStyleEnt = NULL;
1261 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1262 res.unlock();
1263
1264 return bagOff;
1265}
1266
1267static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1268 jint id,
1269 jintArray outValues)
1270{
1271 if (outValues == NULL) {
1272 doThrow(env, "java/lang/NullPointerException");
1273 return JNI_FALSE;
1274 }
1275
1276 AssetManager* am = assetManagerForJavaObject(env, clazz);
1277 if (am == NULL) {
1278 return JNI_FALSE;
1279 }
1280 const ResTable& res(am->getResources());
Dianne Hackborn0d221012009-07-29 15:41:19 -07001281 ResTable_config config;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001282 Res_value value;
1283 ssize_t block;
1284
1285 const jsize NV = env->GetArrayLength(outValues);
1286
1287 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1288 jint* dest = baseDest;
1289 if (dest == NULL) {
1290 doThrow(env, "java/lang/OutOfMemoryError");
1291 return JNI_FALSE;
1292 }
1293
1294 // Now lock down the resource object and start pulling stuff from it.
1295 res.lock();
1296
1297 const ResTable::bag_entry* arrayEnt = NULL;
1298 uint32_t arrayTypeSetFlags = 0;
1299 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1300 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1301 (bagOff >= 0 ? bagOff : 0);
1302
1303 int i = 0;
1304 uint32_t typeSetFlags;
1305 while (i < NV && arrayEnt < endArrayEnt) {
1306 block = arrayEnt->stringBlock;
1307 typeSetFlags = arrayTypeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001308 config.density = 0;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001309 value = arrayEnt->map.value;
1310
1311 uint32_t resid = 0;
1312 if (value.dataType != Res_value::TYPE_NULL) {
1313 // Take care of resolving the found resource to its final value.
1314 //printf("Resolving attribute reference\n");
Dianne Hackborn0d221012009-07-29 15:41:19 -07001315 ssize_t newBlock = res.resolveReference(&value, block, &resid,
1316 &typeSetFlags, &config);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001317 if (newBlock >= 0) block = newBlock;
1318 }
1319
1320 // Deal with the special @null value -- it turns back to TYPE_NULL.
1321 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1322 value.dataType = Res_value::TYPE_NULL;
1323 }
1324
1325 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1326
1327 // Write the final value back to Java.
1328 dest[STYLE_TYPE] = value.dataType;
1329 dest[STYLE_DATA] = value.data;
1330 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1331 dest[STYLE_RESOURCE_ID] = resid;
1332 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
Dianne Hackborn0d221012009-07-29 15:41:19 -07001333 dest[STYLE_DENSITY] = config.density;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001334 dest += STYLE_NUM_ENTRIES;
1335 i+= STYLE_NUM_ENTRIES;
1336 arrayEnt++;
1337 }
1338
1339 i /= STYLE_NUM_ENTRIES;
1340
1341 res.unlock();
1342
1343 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1344
1345 return i;
1346}
1347
1348static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1349 jint cookie,
1350 jstring fileName)
1351{
1352 AssetManager* am = assetManagerForJavaObject(env, clazz);
1353 if (am == NULL) {
1354 return 0;
1355 }
1356
1357 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1358
1359 if (fileName == NULL || am == NULL) {
1360 doThrow(env, "java/lang/NullPointerException");
1361 return 0;
1362 }
1363
1364 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
1365 Asset* a = cookie
1366 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
1367 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
1368
1369 if (a == NULL) {
1370 doThrow(env, "java/io/FileNotFoundException", fileName8);
1371 env->ReleaseStringUTFChars(fileName, fileName8);
1372 return 0;
1373 }
1374 env->ReleaseStringUTFChars(fileName, fileName8);
1375
1376 ResXMLTree* block = new ResXMLTree();
1377 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1378 a->close();
1379 delete a;
1380
1381 if (err != NO_ERROR) {
1382 doThrow(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1383 return 0;
1384 }
1385
1386 return (jint)block;
1387}
1388
1389static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1390 jint arrayResId)
1391{
1392 AssetManager* am = assetManagerForJavaObject(env, clazz);
1393 if (am == NULL) {
1394 return NULL;
1395 }
1396 const ResTable& res(am->getResources());
1397
1398 const ResTable::bag_entry* startOfBag;
1399 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1400 if (N < 0) {
1401 return NULL;
1402 }
1403
1404 jintArray array = env->NewIntArray(N * 2);
1405 if (array == NULL) {
1406 doThrow(env, "java/lang/OutOfMemoryError");
1407 res.unlockBag(startOfBag);
1408 return NULL;
1409 }
1410
1411 Res_value value;
1412 const ResTable::bag_entry* bag = startOfBag;
1413 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1414 jint stringIndex = -1;
1415 jint stringBlock = 0;
1416 value = bag->map.value;
1417
1418 // Take care of resolving the found resource to its final value.
1419 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1420 if (value.dataType == Res_value::TYPE_STRING) {
1421 stringIndex = value.data;
1422 }
1423
1424 //todo: It might be faster to allocate a C array to contain
1425 // the blocknums and indices, put them in there and then
1426 // do just one SetIntArrayRegion()
1427 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1428 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1429 j = j + 2;
1430 }
1431 res.unlockBag(startOfBag);
1432 return array;
1433}
1434
1435static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1436 jint arrayResId)
1437{
1438 AssetManager* am = assetManagerForJavaObject(env, clazz);
1439 if (am == NULL) {
1440 return NULL;
1441 }
1442 const ResTable& res(am->getResources());
1443
1444 jclass cls = env->FindClass("java/lang/String");
1445 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1446 if (cls == NULL) {
1447 return NULL;
1448 }
1449
1450 const ResTable::bag_entry* startOfBag;
1451 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1452 if (N < 0) {
1453 return NULL;
1454 }
1455
1456 jobjectArray array = env->NewObjectArray(N, cls, NULL);
1457 if (array == NULL) {
1458 doThrow(env, "java/lang/OutOfMemoryError");
1459 res.unlockBag(startOfBag);
1460 return NULL;
1461 }
1462
1463 Res_value value;
1464 const ResTable::bag_entry* bag = startOfBag;
1465 size_t strLen = 0;
1466 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1467 value = bag->map.value;
1468 jstring str = NULL;
1469
1470 // Take care of resolving the found resource to its final value.
1471 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1472 if (value.dataType == Res_value::TYPE_STRING) {
1473 const char16_t* str16 = res.getTableStringBlock(block)->stringAt(value.data, &strLen);
1474 str = env->NewString(str16, strLen);
1475 if (str == NULL) {
1476 doThrow(env, "java/lang/OutOfMemoryError");
1477 res.unlockBag(startOfBag);
1478 return NULL;
1479 }
1480 }
1481
1482 env->SetObjectArrayElement(array, i, str);
1483 }
1484 res.unlockBag(startOfBag);
1485 return array;
1486}
1487
1488static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1489 jint arrayResId)
1490{
1491 AssetManager* am = assetManagerForJavaObject(env, clazz);
1492 if (am == NULL) {
1493 return NULL;
1494 }
1495 const ResTable& res(am->getResources());
1496
1497 const ResTable::bag_entry* startOfBag;
1498 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1499 if (N < 0) {
1500 return NULL;
1501 }
1502
1503 jintArray array = env->NewIntArray(N);
1504 if (array == NULL) {
1505 doThrow(env, "java/lang/OutOfMemoryError");
1506 res.unlockBag(startOfBag);
1507 return NULL;
1508 }
1509
1510 Res_value value;
1511 const ResTable::bag_entry* bag = startOfBag;
1512 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1513 value = bag->map.value;
1514
1515 // Take care of resolving the found resource to its final value.
1516 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1517 if (value.dataType >= Res_value::TYPE_FIRST_INT
1518 && value.dataType <= Res_value::TYPE_LAST_INT) {
1519 int intVal = value.data;
1520 env->SetIntArrayRegion(array, i, 1, &intVal);
1521 }
1522 }
1523 res.unlockBag(startOfBag);
1524 return array;
1525}
1526
1527static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1528{
1529 AssetManager* am = new AssetManager();
1530 if (am == NULL) {
1531 doThrow(env, "java/lang/OutOfMemoryError");
1532 return;
1533 }
1534
1535 am->addDefaultAssets();
1536
1537 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1538 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1539}
1540
1541static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1542{
1543 AssetManager* am = (AssetManager*)
1544 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1545 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1546 if (am != NULL) {
1547 delete am;
1548 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1549 }
1550}
1551
1552static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1553{
1554 return Asset::getGlobalCount();
1555}
1556
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001557static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz)
1558{
1559 String8 alloc = Asset::getAssetAllocations();
1560 if (alloc.length() <= 0) {
1561 return NULL;
1562 }
1563
1564 jstring str = env->NewStringUTF(alloc.string());
1565 if (str == NULL) {
1566 doThrow(env, "java/lang/OutOfMemoryError");
1567 return NULL;
1568 }
1569
1570 return str;
1571}
1572
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001573static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1574{
1575 return AssetManager::getGlobalCount();
1576}
1577
1578// ----------------------------------------------------------------------------
1579
1580/*
1581 * JNI registration.
1582 */
1583static JNINativeMethod gAssetManagerMethods[] = {
1584 /* name, signature, funcPtr */
1585
1586 // Basic asset stuff.
1587 { "openAsset", "(Ljava/lang/String;I)I",
1588 (void*) android_content_AssetManager_openAsset },
1589 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1590 (void*) android_content_AssetManager_openAssetFd },
1591 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1592 (void*) android_content_AssetManager_openNonAssetNative },
1593 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1594 (void*) android_content_AssetManager_openNonAssetFdNative },
1595 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1596 (void*) android_content_AssetManager_list },
1597 { "destroyAsset", "(I)V",
1598 (void*) android_content_AssetManager_destroyAsset },
1599 { "readAssetChar", "(I)I",
1600 (void*) android_content_AssetManager_readAssetChar },
1601 { "readAsset", "(I[BII)I",
1602 (void*) android_content_AssetManager_readAsset },
1603 { "seekAsset", "(IJI)J",
1604 (void*) android_content_AssetManager_seekAsset },
1605 { "getAssetLength", "(I)J",
1606 (void*) android_content_AssetManager_getAssetLength },
1607 { "getAssetRemainingLength", "(I)J",
1608 (void*) android_content_AssetManager_getAssetRemainingLength },
1609 { "addAssetPath", "(Ljava/lang/String;)I",
1610 (void*) android_content_AssetManager_addAssetPath },
1611 { "isUpToDate", "()Z",
1612 (void*) android_content_AssetManager_isUpToDate },
1613
1614 // Resources.
1615 { "setLocale", "(Ljava/lang/String;)V",
1616 (void*) android_content_AssetManager_setLocale },
1617 { "getLocales", "()[Ljava/lang/String;",
1618 (void*) android_content_AssetManager_getLocales },
Tobias Haamel27b28b32010-02-09 23:09:17 +01001619 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIII)V",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001620 (void*) android_content_AssetManager_setConfiguration },
1621 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1622 (void*) android_content_AssetManager_getResourceIdentifier },
1623 { "getResourceName","(I)Ljava/lang/String;",
1624 (void*) android_content_AssetManager_getResourceName },
1625 { "getResourcePackageName","(I)Ljava/lang/String;",
1626 (void*) android_content_AssetManager_getResourcePackageName },
1627 { "getResourceTypeName","(I)Ljava/lang/String;",
1628 (void*) android_content_AssetManager_getResourceTypeName },
1629 { "getResourceEntryName","(I)Ljava/lang/String;",
1630 (void*) android_content_AssetManager_getResourceEntryName },
1631 { "loadResourceValue","(ILandroid/util/TypedValue;Z)I",
1632 (void*) android_content_AssetManager_loadResourceValue },
1633 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1634 (void*) android_content_AssetManager_loadResourceBagValue },
1635 { "getStringBlockCount","()I",
1636 (void*) android_content_AssetManager_getStringBlockCount },
1637 { "getNativeStringBlock","(I)I",
1638 (void*) android_content_AssetManager_getNativeStringBlock },
1639 { "getCookieName","(I)Ljava/lang/String;",
1640 (void*) android_content_AssetManager_getCookieName },
1641
1642 // Themes.
1643 { "newTheme", "()I",
1644 (void*) android_content_AssetManager_newTheme },
1645 { "deleteTheme", "(I)V",
1646 (void*) android_content_AssetManager_deleteTheme },
1647 { "applyThemeStyle", "(IIZ)V",
1648 (void*) android_content_AssetManager_applyThemeStyle },
1649 { "copyTheme", "(II)V",
1650 (void*) android_content_AssetManager_copyTheme },
1651 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1652 (void*) android_content_AssetManager_loadThemeAttributeValue },
1653 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1654 (void*) android_content_AssetManager_dumpTheme },
1655 { "applyStyle","(IIII[I[I[I)Z",
1656 (void*) android_content_AssetManager_applyStyle },
1657 { "retrieveAttributes","(I[I[I[I)Z",
1658 (void*) android_content_AssetManager_retrieveAttributes },
1659 { "getArraySize","(I)I",
1660 (void*) android_content_AssetManager_getArraySize },
1661 { "retrieveArray","(I[I)I",
1662 (void*) android_content_AssetManager_retrieveArray },
1663
1664 // XML files.
1665 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1666 (void*) android_content_AssetManager_openXmlAssetNative },
1667
1668 // Arrays.
1669 { "getArrayStringResource","(I)[Ljava/lang/String;",
1670 (void*) android_content_AssetManager_getArrayStringResource },
1671 { "getArrayStringInfo","(I)[I",
1672 (void*) android_content_AssetManager_getArrayStringInfo },
1673 { "getArrayIntResource","(I)[I",
1674 (void*) android_content_AssetManager_getArrayIntResource },
1675
1676 // Bookkeeping.
1677 { "init", "()V",
1678 (void*) android_content_AssetManager_init },
1679 { "destroy", "()V",
1680 (void*) android_content_AssetManager_destroy },
1681 { "getGlobalAssetCount", "()I",
1682 (void*) android_content_AssetManager_getGlobalAssetCount },
Dianne Hackborn82e1ee92009-08-11 18:56:41 -07001683 { "getAssetAllocations", "()Ljava/lang/String;",
1684 (void*) android_content_AssetManager_getAssetAllocations },
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001685 { "getGlobalAssetManagerCount", "()I",
1686 (void*) android_content_AssetManager_getGlobalAssetCount },
1687};
1688
1689int register_android_content_AssetManager(JNIEnv* env)
1690{
1691 jclass typedValue = env->FindClass("android/util/TypedValue");
1692 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1693 gTypedValueOffsets.mType
1694 = env->GetFieldID(typedValue, "type", "I");
1695 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1696 gTypedValueOffsets.mData
1697 = env->GetFieldID(typedValue, "data", "I");
1698 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1699 gTypedValueOffsets.mString
1700 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1701 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1702 gTypedValueOffsets.mAssetCookie
1703 = env->GetFieldID(typedValue, "assetCookie", "I");
1704 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1705 gTypedValueOffsets.mResourceId
1706 = env->GetFieldID(typedValue, "resourceId", "I");
1707 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1708 gTypedValueOffsets.mChangingConfigurations
1709 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1710 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1711 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1712 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1713
1714 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1715 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1716 gAssetFileDescriptorOffsets.mFd
1717 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1718 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1719 gAssetFileDescriptorOffsets.mStartOffset
1720 = env->GetFieldID(assetFd, "mStartOffset", "J");
1721 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1722 gAssetFileDescriptorOffsets.mLength
1723 = env->GetFieldID(assetFd, "mLength", "J");
1724 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1725
1726 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1727 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1728 gAssetManagerOffsets.mObject
1729 = env->GetFieldID(assetManager, "mObject", "I");
1730 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1731
1732 g_stringClass = env->FindClass("java/lang/String");
1733
1734 return AndroidRuntime::registerNativeMethods(env,
1735 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1736}
1737
1738}; // namespace android