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