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