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