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