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