blob: d147bcc883c281240d3f7a2bdec21c64a4e860c9 [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,
538 jint sdkVersion)
539{
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;
560 config.sdkVersion = (uint16_t)sdkVersion;
561 config.minorVersion = 0;
562 am->setConfiguration(config, locale8);
563
564 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8);
565}
566
567static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz,
568 jstring name,
569 jstring defType,
570 jstring defPackage)
571{
572 if (name == NULL) {
573 doThrow(env, "java/lang/NullPointerException");
574 return 0;
575 }
576
577 AssetManager* am = assetManagerForJavaObject(env, clazz);
578 if (am == NULL) {
579 return 0;
580 }
581
582 const char16_t* name16 = env->GetStringChars(name, NULL);
583 jsize nameLen = env->GetStringLength(name);
584 const char16_t* defType16 = defType
585 ? env->GetStringChars(defType, NULL) : NULL;
586 jsize defTypeLen = defType
587 ? env->GetStringLength(defType) : 0;
588 const char16_t* defPackage16 = defPackage
589 ? env->GetStringChars(defPackage, NULL) : NULL;
590 jsize defPackageLen = defPackage
591 ? env->GetStringLength(defPackage) : 0;
592
593 jint ident = am->getResources().identifierForName(
594 name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen);
595
596 if (defPackage16) {
597 env->ReleaseStringChars(defPackage, defPackage16);
598 }
599 if (defType16) {
600 env->ReleaseStringChars(defType, defType16);
601 }
602 env->ReleaseStringChars(name, name16);
603
604 return ident;
605}
606
607static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz,
608 jint resid)
609{
610 AssetManager* am = assetManagerForJavaObject(env, clazz);
611 if (am == NULL) {
612 return NULL;
613 }
614
615 ResTable::resource_name name;
616 if (!am->getResources().getResourceName(resid, &name)) {
617 return NULL;
618 }
619
620 String16 str;
621 if (name.package != NULL) {
622 str.setTo(name.package, name.packageLen);
623 }
624 if (name.type != NULL) {
625 if (str.size() > 0) {
626 char16_t div = ':';
627 str.append(&div, 1);
628 }
629 str.append(name.type, name.typeLen);
630 }
631 if (name.name != NULL) {
632 if (str.size() > 0) {
633 char16_t div = '/';
634 str.append(&div, 1);
635 }
636 str.append(name.name, name.nameLen);
637 }
638
639 return env->NewString((const jchar*)str.string(), str.size());
640}
641
642static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz,
643 jint resid)
644{
645 AssetManager* am = assetManagerForJavaObject(env, clazz);
646 if (am == NULL) {
647 return NULL;
648 }
649
650 ResTable::resource_name name;
651 if (!am->getResources().getResourceName(resid, &name)) {
652 return NULL;
653 }
654
655 if (name.package != NULL) {
656 return env->NewString((const jchar*)name.package, name.packageLen);
657 }
658
659 return NULL;
660}
661
662static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz,
663 jint resid)
664{
665 AssetManager* am = assetManagerForJavaObject(env, clazz);
666 if (am == NULL) {
667 return NULL;
668 }
669
670 ResTable::resource_name name;
671 if (!am->getResources().getResourceName(resid, &name)) {
672 return NULL;
673 }
674
675 if (name.type != NULL) {
676 return env->NewString((const jchar*)name.type, name.typeLen);
677 }
678
679 return NULL;
680}
681
682static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz,
683 jint resid)
684{
685 AssetManager* am = assetManagerForJavaObject(env, clazz);
686 if (am == NULL) {
687 return NULL;
688 }
689
690 ResTable::resource_name name;
691 if (!am->getResources().getResourceName(resid, &name)) {
692 return NULL;
693 }
694
695 if (name.name != NULL) {
696 return env->NewString((const jchar*)name.name, name.nameLen);
697 }
698
699 return NULL;
700}
701
702static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz,
703 jint ident,
704 jobject outValue,
705 jboolean resolve)
706{
707 AssetManager* am = assetManagerForJavaObject(env, clazz);
708 if (am == NULL) {
709 return 0;
710 }
711 const ResTable& res(am->getResources());
712
713 Res_value value;
714 ResTable_config config;
715 uint32_t typeSpecFlags;
716 ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config);
717 uint32_t ref = ident;
718 if (resolve) {
719 block = res.resolveReference(&value, block, &ref);
720 }
721 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block;
722}
723
724static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz,
725 jint ident, jint bagEntryId,
726 jobject outValue, jboolean resolve)
727{
728 AssetManager* am = assetManagerForJavaObject(env, clazz);
729 if (am == NULL) {
730 return 0;
731 }
732 const ResTable& res(am->getResources());
733
734 // Now lock down the resource object and start pulling stuff from it.
735 res.lock();
736
737 ssize_t block = -1;
738 Res_value value;
739
740 const ResTable::bag_entry* entry = NULL;
741 uint32_t typeSpecFlags;
742 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags);
743
744 for (ssize_t i=0; i<entryCount; i++) {
745 if (((uint32_t)bagEntryId) == entry->map.name.ident) {
746 block = entry->stringBlock;
747 value = entry->map.value;
748 }
749 entry++;
750 }
751
752 res.unlock();
753
754 if (block < 0) {
755 return block;
756 }
757
758 uint32_t ref = ident;
759 if (resolve) {
760 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
761 }
762 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
763}
764
765static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz)
766{
767 AssetManager* am = assetManagerForJavaObject(env, clazz);
768 if (am == NULL) {
769 return 0;
770 }
771 return am->getResources().getTableCount();
772}
773
774static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz,
775 jint block)
776{
777 AssetManager* am = assetManagerForJavaObject(env, clazz);
778 if (am == NULL) {
779 return 0;
780 }
781 return (jint)am->getResources().getTableStringBlock(block);
782}
783
784static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz,
785 jint cookie)
786{
787 AssetManager* am = assetManagerForJavaObject(env, clazz);
788 if (am == NULL) {
789 return NULL;
790 }
791 String8 name(am->getAssetPath((void*)cookie));
792 if (name.length() == 0) {
793 doThrow(env, "java/lang/IndexOutOfBoundsException");
794 return NULL;
795 }
796 jstring str = env->NewStringUTF(name.string());
797 if (str == NULL) {
798 doThrow(env, "java/lang/OutOfMemoryError");
799 return NULL;
800 }
801 return str;
802}
803
804static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz)
805{
806 AssetManager* am = assetManagerForJavaObject(env, clazz);
807 if (am == NULL) {
808 return 0;
809 }
810 return (jint)(new ResTable::Theme(am->getResources()));
811}
812
813static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz,
814 jint themeInt)
815{
816 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
817 delete theme;
818}
819
820static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz,
821 jint themeInt,
822 jint styleRes,
823 jboolean force)
824{
825 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
826 theme->applyStyle(styleRes, force ? true : false);
827}
828
829static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz,
830 jint destInt, jint srcInt)
831{
832 ResTable::Theme* dest = (ResTable::Theme*)destInt;
833 ResTable::Theme* src = (ResTable::Theme*)srcInt;
834 dest->setTo(*src);
835}
836
837static jint android_content_AssetManager_loadThemeAttributeValue(
838 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve)
839{
840 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
841 const ResTable& res(theme->getResTable());
842
843 Res_value value;
844 // XXX value could be different in different configs!
845 uint32_t typeSpecFlags = 0;
846 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags);
847 uint32_t ref = 0;
848 if (resolve) {
849 block = res.resolveReference(&value, block, &ref, &typeSpecFlags);
850 }
851 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block;
852}
853
854static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz,
855 jint themeInt, jint pri,
856 jstring tag, jstring prefix)
857{
858 ResTable::Theme* theme = (ResTable::Theme*)themeInt;
859 const ResTable& res(theme->getResTable());
860
861 if (tag == NULL) {
862 doThrow(env, "java/lang/NullPointerException");
863 return;
864 }
865
866 const char* tag8 = env->GetStringUTFChars(tag, NULL);
867 const char* prefix8 = NULL;
868 if (prefix != NULL) {
869 prefix8 = env->GetStringUTFChars(prefix, NULL);
870 }
871
872 // XXX Need to use params.
873 theme->dumpToLog();
874
875 if (prefix8 != NULL) {
876 env->ReleaseStringUTFChars(prefix, prefix8);
877 }
878 env->ReleaseStringUTFChars(tag, tag8);
879}
880
881static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz,
882 jint themeToken,
883 jint defStyleAttr,
884 jint defStyleRes,
885 jint xmlParserToken,
886 jintArray attrs,
887 jintArray outValues,
888 jintArray outIndices)
889{
890 if (themeToken == 0 || attrs == NULL || outValues == NULL) {
891 doThrow(env, "java/lang/NullPointerException");
892 return JNI_FALSE;
893 }
894
895 ResTable::Theme* theme = (ResTable::Theme*)themeToken;
896 const ResTable& res = theme->getResTable();
897 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
898 Res_value value;
899
900 const jsize NI = env->GetArrayLength(attrs);
901 const jsize NV = env->GetArrayLength(outValues);
902 if (NV < (NI*STYLE_NUM_ENTRIES)) {
903 doThrow(env, "java/lang/IndexOutOfBoundsException");
904 return JNI_FALSE;
905 }
906
907 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
908 if (src == NULL) {
909 doThrow(env, "java/lang/OutOfMemoryError");
910 return JNI_FALSE;
911 }
912
913 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
914 jint* dest = baseDest;
915 if (dest == NULL) {
916 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
917 doThrow(env, "java/lang/OutOfMemoryError");
918 return JNI_FALSE;
919 }
920
921 jint* indices = NULL;
922 int indicesIdx = 0;
923 if (outIndices != NULL) {
924 if (env->GetArrayLength(outIndices) > NI) {
925 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
926 }
927 }
928
929 // Load default style from attribute, if specified...
930 uint32_t defStyleBagTypeSetFlags = 0;
931 if (defStyleAttr != 0) {
932 Res_value value;
933 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) {
934 if (value.dataType == Res_value::TYPE_REFERENCE) {
935 defStyleRes = value.data;
936 }
937 }
938 }
939
940 // Retrieve the style class associated with the current XML tag.
941 int style = 0;
942 uint32_t styleBagTypeSetFlags = 0;
943 if (xmlParser != NULL) {
944 ssize_t idx = xmlParser->indexOfStyle();
945 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) {
946 if (value.dataType == value.TYPE_ATTRIBUTE) {
947 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) {
948 value.dataType = Res_value::TYPE_NULL;
949 }
950 }
951 if (value.dataType == value.TYPE_REFERENCE) {
952 style = value.data;
953 }
954 }
955 }
956
957 // Now lock down the resource object and start pulling stuff from it.
958 res.lock();
959
960 // Retrieve the default style bag, if requested.
961 const ResTable::bag_entry* defStyleEnt = NULL;
962 uint32_t defStyleTypeSetFlags = 0;
963 ssize_t bagOff = defStyleRes != 0
964 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1;
965 defStyleTypeSetFlags |= defStyleBagTypeSetFlags;
966 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt +
967 (bagOff >= 0 ? bagOff : 0);
968
969 // Retrieve the style class bag, if requested.
970 const ResTable::bag_entry* styleEnt = NULL;
971 uint32_t styleTypeSetFlags = 0;
972 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1;
973 styleTypeSetFlags |= styleBagTypeSetFlags;
974 const ResTable::bag_entry* endStyleEnt = styleEnt +
975 (bagOff >= 0 ? bagOff : 0);
976
977 // Retrieve the XML attributes, if requested.
978 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0;
979 jsize ix=0;
980 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0;
981
982 static const ssize_t kXmlBlock = 0x10000000;
983
984 // Now iterate through all of the attributes that the client has requested,
985 // filling in each with whatever data we can find.
986 ssize_t block = 0;
987 uint32_t typeSetFlags;
988 for (jsize ii=0; ii<NI; ii++) {
989 const uint32_t curIdent = (uint32_t)src[ii];
990
991 // Try to find a value for this attribute... we prioritize values
992 // coming from, first XML attributes, then XML style, then default
993 // style, and finally the theme.
994 value.dataType = Res_value::TYPE_NULL;
995 value.data = 0;
996 typeSetFlags = 0;
997
998 // Skip through XML attributes until the end or the next possible match.
999 while (ix < NX && curIdent > curXmlAttr) {
1000 ix++;
1001 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1002 }
1003 // Retrieve the current XML attribute if it matches, and step to next.
1004 if (ix < NX && curIdent == curXmlAttr) {
1005 block = kXmlBlock;
1006 xmlParser->getAttributeValue(ix, &value);
1007 ix++;
1008 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1009 }
1010
1011 // Skip through the style values until the end or the next possible match.
1012 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) {
1013 styleEnt++;
1014 }
1015 // Retrieve the current style attribute if it matches, and step to next.
1016 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) {
1017 if (value.dataType == Res_value::TYPE_NULL) {
1018 block = styleEnt->stringBlock;
1019 typeSetFlags = styleTypeSetFlags;
1020 value = styleEnt->map.value;
1021 }
1022 styleEnt++;
1023 }
1024
1025 // Skip through the default style values until the end or the next possible match.
1026 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) {
1027 defStyleEnt++;
1028 }
1029 // Retrieve the current default style attribute if it matches, and step to next.
1030 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) {
1031 if (value.dataType == Res_value::TYPE_NULL) {
1032 block = defStyleEnt->stringBlock;
1033 typeSetFlags = defStyleTypeSetFlags;
1034 value = defStyleEnt->map.value;
1035 }
1036 defStyleEnt++;
1037 }
1038
1039 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1040 uint32_t resid = 0;
1041 if (value.dataType != Res_value::TYPE_NULL) {
1042 // Take care of resolving the found resource to its final value.
1043 //printf("Resolving attribute reference\n");
1044 ssize_t newBlock = theme->resolveAttributeReference(&value, block, &resid, &typeSetFlags);
1045 if (newBlock >= 0) block = newBlock;
1046 } else {
1047 // If we still don't have a value for this attribute, try to find
1048 // it in the theme!
1049 //printf("Looking up in theme\n");
1050 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags);
1051 if (newBlock >= 0) {
1052 //printf("Resolving resource reference\n");
1053 newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
1054 if (newBlock >= 0) block = newBlock;
1055 }
1056 }
1057
1058 // Deal with the special @null value -- it turns back to TYPE_NULL.
1059 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1060 value.dataType = Res_value::TYPE_NULL;
1061 }
1062
1063 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1064
1065 // Write the final value back to Java.
1066 dest[STYLE_TYPE] = value.dataType;
1067 dest[STYLE_DATA] = value.data;
1068 dest[STYLE_ASSET_COOKIE] =
1069 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1070 dest[STYLE_RESOURCE_ID] = resid;
1071 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1072
1073 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1074 indicesIdx++;
1075 indices[indicesIdx] = ii;
1076 }
1077
1078 dest += STYLE_NUM_ENTRIES;
1079 }
1080
1081 res.unlock();
1082
1083 if (indices != NULL) {
1084 indices[0] = indicesIdx;
1085 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1086 }
1087 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1088 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1089
1090 return JNI_TRUE;
1091}
1092
1093static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz,
1094 jint xmlParserToken,
1095 jintArray attrs,
1096 jintArray outValues,
1097 jintArray outIndices)
1098{
1099 if (xmlParserToken == 0 || attrs == NULL || outValues == NULL) {
1100 doThrow(env, "java/lang/NullPointerException");
1101 return JNI_FALSE;
1102 }
1103
1104 AssetManager* am = assetManagerForJavaObject(env, clazz);
1105 if (am == NULL) {
1106 return JNI_FALSE;
1107 }
1108 const ResTable& res(am->getResources());
1109 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken;
1110 Res_value value;
1111
1112 const jsize NI = env->GetArrayLength(attrs);
1113 const jsize NV = env->GetArrayLength(outValues);
1114 if (NV < (NI*STYLE_NUM_ENTRIES)) {
1115 doThrow(env, "java/lang/IndexOutOfBoundsException");
1116 return JNI_FALSE;
1117 }
1118
1119 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0);
1120 if (src == NULL) {
1121 doThrow(env, "java/lang/OutOfMemoryError");
1122 return JNI_FALSE;
1123 }
1124
1125 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1126 jint* dest = baseDest;
1127 if (dest == NULL) {
1128 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1129 doThrow(env, "java/lang/OutOfMemoryError");
1130 return JNI_FALSE;
1131 }
1132
1133 jint* indices = NULL;
1134 int indicesIdx = 0;
1135 if (outIndices != NULL) {
1136 if (env->GetArrayLength(outIndices) > NI) {
1137 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0);
1138 }
1139 }
1140
1141 // Now lock down the resource object and start pulling stuff from it.
1142 res.lock();
1143
1144 // Retrieve the XML attributes, if requested.
1145 const jsize NX = xmlParser->getAttributeCount();
1146 jsize ix=0;
1147 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix);
1148
1149 static const ssize_t kXmlBlock = 0x10000000;
1150
1151 // Now iterate through all of the attributes that the client has requested,
1152 // filling in each with whatever data we can find.
1153 ssize_t block = 0;
1154 uint32_t typeSetFlags;
1155 for (jsize ii=0; ii<NI; ii++) {
1156 const uint32_t curIdent = (uint32_t)src[ii];
1157
1158 // Try to find a value for this attribute...
1159 value.dataType = Res_value::TYPE_NULL;
1160 value.data = 0;
1161 typeSetFlags = 0;
1162
1163 // Skip through XML attributes until the end or the next possible match.
1164 while (ix < NX && curIdent > curXmlAttr) {
1165 ix++;
1166 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1167 }
1168 // Retrieve the current XML attribute if it matches, and step to next.
1169 if (ix < NX && curIdent == curXmlAttr) {
1170 block = kXmlBlock;
1171 xmlParser->getAttributeValue(ix, &value);
1172 ix++;
1173 curXmlAttr = xmlParser->getAttributeNameResID(ix);
1174 }
1175
1176 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1177 uint32_t resid = 0;
1178 if (value.dataType != Res_value::TYPE_NULL) {
1179 // Take care of resolving the found resource to its final value.
1180 //printf("Resolving attribute reference\n");
1181 ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
1182 if (newBlock >= 0) block = newBlock;
1183 }
1184
1185 // Deal with the special @null value -- it turns back to TYPE_NULL.
1186 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1187 value.dataType = Res_value::TYPE_NULL;
1188 }
1189
1190 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1191
1192 // Write the final value back to Java.
1193 dest[STYLE_TYPE] = value.dataType;
1194 dest[STYLE_DATA] = value.data;
1195 dest[STYLE_ASSET_COOKIE] =
1196 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1;
1197 dest[STYLE_RESOURCE_ID] = resid;
1198 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1199
1200 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) {
1201 indicesIdx++;
1202 indices[indicesIdx] = ii;
1203 }
1204
1205 dest += STYLE_NUM_ENTRIES;
1206 }
1207
1208 res.unlock();
1209
1210 if (indices != NULL) {
1211 indices[0] = indicesIdx;
1212 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0);
1213 }
1214
1215 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1216 env->ReleasePrimitiveArrayCritical(attrs, src, 0);
1217
1218 return JNI_TRUE;
1219}
1220
1221static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz,
1222 jint id)
1223{
1224 AssetManager* am = assetManagerForJavaObject(env, clazz);
1225 if (am == NULL) {
1226 return NULL;
1227 }
1228 const ResTable& res(am->getResources());
1229
1230 res.lock();
1231 const ResTable::bag_entry* defStyleEnt = NULL;
1232 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt);
1233 res.unlock();
1234
1235 return bagOff;
1236}
1237
1238static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz,
1239 jint id,
1240 jintArray outValues)
1241{
1242 if (outValues == NULL) {
1243 doThrow(env, "java/lang/NullPointerException");
1244 return JNI_FALSE;
1245 }
1246
1247 AssetManager* am = assetManagerForJavaObject(env, clazz);
1248 if (am == NULL) {
1249 return JNI_FALSE;
1250 }
1251 const ResTable& res(am->getResources());
1252 Res_value value;
1253 ssize_t block;
1254
1255 const jsize NV = env->GetArrayLength(outValues);
1256
1257 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0);
1258 jint* dest = baseDest;
1259 if (dest == NULL) {
1260 doThrow(env, "java/lang/OutOfMemoryError");
1261 return JNI_FALSE;
1262 }
1263
1264 // Now lock down the resource object and start pulling stuff from it.
1265 res.lock();
1266
1267 const ResTable::bag_entry* arrayEnt = NULL;
1268 uint32_t arrayTypeSetFlags = 0;
1269 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags);
1270 const ResTable::bag_entry* endArrayEnt = arrayEnt +
1271 (bagOff >= 0 ? bagOff : 0);
1272
1273 int i = 0;
1274 uint32_t typeSetFlags;
1275 while (i < NV && arrayEnt < endArrayEnt) {
1276 block = arrayEnt->stringBlock;
1277 typeSetFlags = arrayTypeSetFlags;
1278 value = arrayEnt->map.value;
1279
1280 uint32_t resid = 0;
1281 if (value.dataType != Res_value::TYPE_NULL) {
1282 // Take care of resolving the found resource to its final value.
1283 //printf("Resolving attribute reference\n");
1284 ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags);
1285 if (newBlock >= 0) block = newBlock;
1286 }
1287
1288 // Deal with the special @null value -- it turns back to TYPE_NULL.
1289 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) {
1290 value.dataType = Res_value::TYPE_NULL;
1291 }
1292
1293 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data);
1294
1295 // Write the final value back to Java.
1296 dest[STYLE_TYPE] = value.dataType;
1297 dest[STYLE_DATA] = value.data;
1298 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block);
1299 dest[STYLE_RESOURCE_ID] = resid;
1300 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags;
1301 dest += STYLE_NUM_ENTRIES;
1302 i+= STYLE_NUM_ENTRIES;
1303 arrayEnt++;
1304 }
1305
1306 i /= STYLE_NUM_ENTRIES;
1307
1308 res.unlock();
1309
1310 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0);
1311
1312 return i;
1313}
1314
1315static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz,
1316 jint cookie,
1317 jstring fileName)
1318{
1319 AssetManager* am = assetManagerForJavaObject(env, clazz);
1320 if (am == NULL) {
1321 return 0;
1322 }
1323
1324 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz);
1325
1326 if (fileName == NULL || am == NULL) {
1327 doThrow(env, "java/lang/NullPointerException");
1328 return 0;
1329 }
1330
1331 const char* fileName8 = env->GetStringUTFChars(fileName, NULL);
1332 Asset* a = cookie
1333 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER)
1334 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER);
1335
1336 if (a == NULL) {
1337 doThrow(env, "java/io/FileNotFoundException", fileName8);
1338 env->ReleaseStringUTFChars(fileName, fileName8);
1339 return 0;
1340 }
1341 env->ReleaseStringUTFChars(fileName, fileName8);
1342
1343 ResXMLTree* block = new ResXMLTree();
1344 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true);
1345 a->close();
1346 delete a;
1347
1348 if (err != NO_ERROR) {
1349 doThrow(env, "java/io/FileNotFoundException", "Corrupt XML binary file");
1350 return 0;
1351 }
1352
1353 return (jint)block;
1354}
1355
1356static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz,
1357 jint arrayResId)
1358{
1359 AssetManager* am = assetManagerForJavaObject(env, clazz);
1360 if (am == NULL) {
1361 return NULL;
1362 }
1363 const ResTable& res(am->getResources());
1364
1365 const ResTable::bag_entry* startOfBag;
1366 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1367 if (N < 0) {
1368 return NULL;
1369 }
1370
1371 jintArray array = env->NewIntArray(N * 2);
1372 if (array == NULL) {
1373 doThrow(env, "java/lang/OutOfMemoryError");
1374 res.unlockBag(startOfBag);
1375 return NULL;
1376 }
1377
1378 Res_value value;
1379 const ResTable::bag_entry* bag = startOfBag;
1380 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) {
1381 jint stringIndex = -1;
1382 jint stringBlock = 0;
1383 value = bag->map.value;
1384
1385 // Take care of resolving the found resource to its final value.
1386 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL);
1387 if (value.dataType == Res_value::TYPE_STRING) {
1388 stringIndex = value.data;
1389 }
1390
1391 //todo: It might be faster to allocate a C array to contain
1392 // the blocknums and indices, put them in there and then
1393 // do just one SetIntArrayRegion()
1394 env->SetIntArrayRegion(array, j, 1, &stringBlock);
1395 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex);
1396 j = j + 2;
1397 }
1398 res.unlockBag(startOfBag);
1399 return array;
1400}
1401
1402static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz,
1403 jint arrayResId)
1404{
1405 AssetManager* am = assetManagerForJavaObject(env, clazz);
1406 if (am == NULL) {
1407 return NULL;
1408 }
1409 const ResTable& res(am->getResources());
1410
1411 jclass cls = env->FindClass("java/lang/String");
1412 LOG_FATAL_IF(cls == NULL, "No string class?!?");
1413 if (cls == NULL) {
1414 return NULL;
1415 }
1416
1417 const ResTable::bag_entry* startOfBag;
1418 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1419 if (N < 0) {
1420 return NULL;
1421 }
1422
1423 jobjectArray array = env->NewObjectArray(N, cls, NULL);
1424 if (array == NULL) {
1425 doThrow(env, "java/lang/OutOfMemoryError");
1426 res.unlockBag(startOfBag);
1427 return NULL;
1428 }
1429
1430 Res_value value;
1431 const ResTable::bag_entry* bag = startOfBag;
1432 size_t strLen = 0;
1433 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1434 value = bag->map.value;
1435 jstring str = NULL;
1436
1437 // Take care of resolving the found resource to its final value.
1438 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1439 if (value.dataType == Res_value::TYPE_STRING) {
1440 const char16_t* str16 = res.getTableStringBlock(block)->stringAt(value.data, &strLen);
1441 str = env->NewString(str16, strLen);
1442 if (str == NULL) {
1443 doThrow(env, "java/lang/OutOfMemoryError");
1444 res.unlockBag(startOfBag);
1445 return NULL;
1446 }
1447 }
1448
1449 env->SetObjectArrayElement(array, i, str);
1450 }
1451 res.unlockBag(startOfBag);
1452 return array;
1453}
1454
1455static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz,
1456 jint arrayResId)
1457{
1458 AssetManager* am = assetManagerForJavaObject(env, clazz);
1459 if (am == NULL) {
1460 return NULL;
1461 }
1462 const ResTable& res(am->getResources());
1463
1464 const ResTable::bag_entry* startOfBag;
1465 const ssize_t N = res.lockBag(arrayResId, &startOfBag);
1466 if (N < 0) {
1467 return NULL;
1468 }
1469
1470 jintArray array = env->NewIntArray(N);
1471 if (array == NULL) {
1472 doThrow(env, "java/lang/OutOfMemoryError");
1473 res.unlockBag(startOfBag);
1474 return NULL;
1475 }
1476
1477 Res_value value;
1478 const ResTable::bag_entry* bag = startOfBag;
1479 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) {
1480 value = bag->map.value;
1481
1482 // Take care of resolving the found resource to its final value.
1483 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL);
1484 if (value.dataType >= Res_value::TYPE_FIRST_INT
1485 && value.dataType <= Res_value::TYPE_LAST_INT) {
1486 int intVal = value.data;
1487 env->SetIntArrayRegion(array, i, 1, &intVal);
1488 }
1489 }
1490 res.unlockBag(startOfBag);
1491 return array;
1492}
1493
1494static void android_content_AssetManager_init(JNIEnv* env, jobject clazz)
1495{
1496 AssetManager* am = new AssetManager();
1497 if (am == NULL) {
1498 doThrow(env, "java/lang/OutOfMemoryError");
1499 return;
1500 }
1501
1502 am->addDefaultAssets();
1503
1504 LOGV("Created AssetManager %p for Java object %p\n", am, clazz);
1505 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am);
1506}
1507
1508static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz)
1509{
1510 AssetManager* am = (AssetManager*)
1511 (env->GetIntField(clazz, gAssetManagerOffsets.mObject));
1512 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz);
1513 if (am != NULL) {
1514 delete am;
1515 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0);
1516 }
1517}
1518
1519static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz)
1520{
1521 return Asset::getGlobalCount();
1522}
1523
1524static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz)
1525{
1526 return AssetManager::getGlobalCount();
1527}
1528
1529// ----------------------------------------------------------------------------
1530
1531/*
1532 * JNI registration.
1533 */
1534static JNINativeMethod gAssetManagerMethods[] = {
1535 /* name, signature, funcPtr */
1536
1537 // Basic asset stuff.
1538 { "openAsset", "(Ljava/lang/String;I)I",
1539 (void*) android_content_AssetManager_openAsset },
1540 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1541 (void*) android_content_AssetManager_openAssetFd },
1542 { "openNonAssetNative", "(ILjava/lang/String;I)I",
1543 (void*) android_content_AssetManager_openNonAssetNative },
1544 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;",
1545 (void*) android_content_AssetManager_openNonAssetFdNative },
1546 { "list", "(Ljava/lang/String;)[Ljava/lang/String;",
1547 (void*) android_content_AssetManager_list },
1548 { "destroyAsset", "(I)V",
1549 (void*) android_content_AssetManager_destroyAsset },
1550 { "readAssetChar", "(I)I",
1551 (void*) android_content_AssetManager_readAssetChar },
1552 { "readAsset", "(I[BII)I",
1553 (void*) android_content_AssetManager_readAsset },
1554 { "seekAsset", "(IJI)J",
1555 (void*) android_content_AssetManager_seekAsset },
1556 { "getAssetLength", "(I)J",
1557 (void*) android_content_AssetManager_getAssetLength },
1558 { "getAssetRemainingLength", "(I)J",
1559 (void*) android_content_AssetManager_getAssetRemainingLength },
1560 { "addAssetPath", "(Ljava/lang/String;)I",
1561 (void*) android_content_AssetManager_addAssetPath },
1562 { "isUpToDate", "()Z",
1563 (void*) android_content_AssetManager_isUpToDate },
1564
1565 // Resources.
1566 { "setLocale", "(Ljava/lang/String;)V",
1567 (void*) android_content_AssetManager_setLocale },
1568 { "getLocales", "()[Ljava/lang/String;",
1569 (void*) android_content_AssetManager_getLocales },
1570 { "setConfiguration", "(IILjava/lang/String;IIIIIIIII)V",
1571 (void*) android_content_AssetManager_setConfiguration },
1572 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
1573 (void*) android_content_AssetManager_getResourceIdentifier },
1574 { "getResourceName","(I)Ljava/lang/String;",
1575 (void*) android_content_AssetManager_getResourceName },
1576 { "getResourcePackageName","(I)Ljava/lang/String;",
1577 (void*) android_content_AssetManager_getResourcePackageName },
1578 { "getResourceTypeName","(I)Ljava/lang/String;",
1579 (void*) android_content_AssetManager_getResourceTypeName },
1580 { "getResourceEntryName","(I)Ljava/lang/String;",
1581 (void*) android_content_AssetManager_getResourceEntryName },
1582 { "loadResourceValue","(ILandroid/util/TypedValue;Z)I",
1583 (void*) android_content_AssetManager_loadResourceValue },
1584 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I",
1585 (void*) android_content_AssetManager_loadResourceBagValue },
1586 { "getStringBlockCount","()I",
1587 (void*) android_content_AssetManager_getStringBlockCount },
1588 { "getNativeStringBlock","(I)I",
1589 (void*) android_content_AssetManager_getNativeStringBlock },
1590 { "getCookieName","(I)Ljava/lang/String;",
1591 (void*) android_content_AssetManager_getCookieName },
1592
1593 // Themes.
1594 { "newTheme", "()I",
1595 (void*) android_content_AssetManager_newTheme },
1596 { "deleteTheme", "(I)V",
1597 (void*) android_content_AssetManager_deleteTheme },
1598 { "applyThemeStyle", "(IIZ)V",
1599 (void*) android_content_AssetManager_applyThemeStyle },
1600 { "copyTheme", "(II)V",
1601 (void*) android_content_AssetManager_copyTheme },
1602 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I",
1603 (void*) android_content_AssetManager_loadThemeAttributeValue },
1604 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V",
1605 (void*) android_content_AssetManager_dumpTheme },
1606 { "applyStyle","(IIII[I[I[I)Z",
1607 (void*) android_content_AssetManager_applyStyle },
1608 { "retrieveAttributes","(I[I[I[I)Z",
1609 (void*) android_content_AssetManager_retrieveAttributes },
1610 { "getArraySize","(I)I",
1611 (void*) android_content_AssetManager_getArraySize },
1612 { "retrieveArray","(I[I)I",
1613 (void*) android_content_AssetManager_retrieveArray },
1614
1615 // XML files.
1616 { "openXmlAssetNative", "(ILjava/lang/String;)I",
1617 (void*) android_content_AssetManager_openXmlAssetNative },
1618
1619 // Arrays.
1620 { "getArrayStringResource","(I)[Ljava/lang/String;",
1621 (void*) android_content_AssetManager_getArrayStringResource },
1622 { "getArrayStringInfo","(I)[I",
1623 (void*) android_content_AssetManager_getArrayStringInfo },
1624 { "getArrayIntResource","(I)[I",
1625 (void*) android_content_AssetManager_getArrayIntResource },
1626
1627 // Bookkeeping.
1628 { "init", "()V",
1629 (void*) android_content_AssetManager_init },
1630 { "destroy", "()V",
1631 (void*) android_content_AssetManager_destroy },
1632 { "getGlobalAssetCount", "()I",
1633 (void*) android_content_AssetManager_getGlobalAssetCount },
1634 { "getGlobalAssetManagerCount", "()I",
1635 (void*) android_content_AssetManager_getGlobalAssetCount },
1636};
1637
1638int register_android_content_AssetManager(JNIEnv* env)
1639{
1640 jclass typedValue = env->FindClass("android/util/TypedValue");
1641 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue");
1642 gTypedValueOffsets.mType
1643 = env->GetFieldID(typedValue, "type", "I");
1644 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type");
1645 gTypedValueOffsets.mData
1646 = env->GetFieldID(typedValue, "data", "I");
1647 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data");
1648 gTypedValueOffsets.mString
1649 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;");
1650 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string");
1651 gTypedValueOffsets.mAssetCookie
1652 = env->GetFieldID(typedValue, "assetCookie", "I");
1653 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie");
1654 gTypedValueOffsets.mResourceId
1655 = env->GetFieldID(typedValue, "resourceId", "I");
1656 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId");
1657 gTypedValueOffsets.mChangingConfigurations
1658 = env->GetFieldID(typedValue, "changingConfigurations", "I");
1659 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations");
1660 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I");
1661 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density");
1662
1663 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor");
1664 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor");
1665 gAssetFileDescriptorOffsets.mFd
1666 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;");
1667 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd");
1668 gAssetFileDescriptorOffsets.mStartOffset
1669 = env->GetFieldID(assetFd, "mStartOffset", "J");
1670 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset");
1671 gAssetFileDescriptorOffsets.mLength
1672 = env->GetFieldID(assetFd, "mLength", "J");
1673 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength");
1674
1675 jclass assetManager = env->FindClass("android/content/res/AssetManager");
1676 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager");
1677 gAssetManagerOffsets.mObject
1678 = env->GetFieldID(assetManager, "mObject", "I");
1679 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject");
1680
1681 g_stringClass = env->FindClass("java/lang/String");
1682
1683 return AndroidRuntime::registerNativeMethods(env,
1684 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods));
1685}
1686
1687}; // namespace android