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