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