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