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