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