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