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