android_util_AssetManager.cpp revision d7c8672ccc8ccd1f99da60accc63d6817d41ac52
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 off_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 } 1115 1116 DEBUG_STYLES(LOGI("Attribute 0x%08x: type=0x%x, data=0x%08x", 1117 curIdent, value.dataType, value.data)); 1118 1119 // Write the final value back to Java. 1120 dest[STYLE_TYPE] = value.dataType; 1121 dest[STYLE_DATA] = value.data; 1122 dest[STYLE_ASSET_COOKIE] = 1123 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1; 1124 dest[STYLE_RESOURCE_ID] = resid; 1125 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1126 dest[STYLE_DENSITY] = config.density; 1127 1128 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) { 1129 indicesIdx++; 1130 indices[indicesIdx] = ii; 1131 } 1132 1133 dest += STYLE_NUM_ENTRIES; 1134 } 1135 1136 res.unlock(); 1137 1138 if (indices != NULL) { 1139 indices[0] = indicesIdx; 1140 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1141 } 1142 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1143 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1144 1145 return JNI_TRUE; 1146} 1147 1148static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz, 1149 jint xmlParserToken, 1150 jintArray attrs, 1151 jintArray outValues, 1152 jintArray outIndices) 1153{ 1154 if (xmlParserToken == 0) { 1155 jniThrowException(env, "java/lang/NullPointerException", "xmlParserToken"); 1156 return JNI_FALSE; 1157 } 1158 if (attrs == NULL) { 1159 jniThrowException(env, "java/lang/NullPointerException", "attrs"); 1160 return JNI_FALSE; 1161 } 1162 if (outValues == NULL) { 1163 jniThrowException(env, "java/lang/NullPointerException", "out values"); 1164 return JNI_FALSE; 1165 } 1166 1167 AssetManager* am = assetManagerForJavaObject(env, clazz); 1168 if (am == NULL) { 1169 return JNI_FALSE; 1170 } 1171 const ResTable& res(am->getResources()); 1172 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken; 1173 ResTable_config config; 1174 Res_value value; 1175 1176 const jsize NI = env->GetArrayLength(attrs); 1177 const jsize NV = env->GetArrayLength(outValues); 1178 if (NV < (NI*STYLE_NUM_ENTRIES)) { 1179 jniThrowException(env, "java/lang/IndexOutOfBoundsException", "out values too small"); 1180 return JNI_FALSE; 1181 } 1182 1183 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0); 1184 if (src == NULL) { 1185 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1186 return JNI_FALSE; 1187 } 1188 1189 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1190 jint* dest = baseDest; 1191 if (dest == NULL) { 1192 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1193 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1194 return JNI_FALSE; 1195 } 1196 1197 jint* indices = NULL; 1198 int indicesIdx = 0; 1199 if (outIndices != NULL) { 1200 if (env->GetArrayLength(outIndices) > NI) { 1201 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0); 1202 } 1203 } 1204 1205 // Now lock down the resource object and start pulling stuff from it. 1206 res.lock(); 1207 1208 // Retrieve the XML attributes, if requested. 1209 const jsize NX = xmlParser->getAttributeCount(); 1210 jsize ix=0; 1211 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix); 1212 1213 static const ssize_t kXmlBlock = 0x10000000; 1214 1215 // Now iterate through all of the attributes that the client has requested, 1216 // filling in each with whatever data we can find. 1217 ssize_t block = 0; 1218 uint32_t typeSetFlags; 1219 for (jsize ii=0; ii<NI; ii++) { 1220 const uint32_t curIdent = (uint32_t)src[ii]; 1221 1222 // Try to find a value for this attribute... 1223 value.dataType = Res_value::TYPE_NULL; 1224 value.data = 0; 1225 typeSetFlags = 0; 1226 config.density = 0; 1227 1228 // Skip through XML attributes until the end or the next possible match. 1229 while (ix < NX && curIdent > curXmlAttr) { 1230 ix++; 1231 curXmlAttr = xmlParser->getAttributeNameResID(ix); 1232 } 1233 // Retrieve the current XML attribute if it matches, and step to next. 1234 if (ix < NX && curIdent == curXmlAttr) { 1235 block = kXmlBlock; 1236 xmlParser->getAttributeValue(ix, &value); 1237 ix++; 1238 curXmlAttr = xmlParser->getAttributeNameResID(ix); 1239 } 1240 1241 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1242 uint32_t resid = 0; 1243 if (value.dataType != Res_value::TYPE_NULL) { 1244 // Take care of resolving the found resource to its final value. 1245 //printf("Resolving attribute reference\n"); 1246 ssize_t newBlock = res.resolveReference(&value, block, &resid, 1247 &typeSetFlags, &config); 1248#if THROW_ON_BAD_ID 1249 if (newBlock == BAD_INDEX) { 1250 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1251 return JNI_FALSE; 1252 } 1253#endif 1254 if (newBlock >= 0) block = newBlock; 1255 } 1256 1257 // Deal with the special @null value -- it turns back to TYPE_NULL. 1258 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { 1259 value.dataType = Res_value::TYPE_NULL; 1260 } 1261 1262 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1263 1264 // Write the final value back to Java. 1265 dest[STYLE_TYPE] = value.dataType; 1266 dest[STYLE_DATA] = value.data; 1267 dest[STYLE_ASSET_COOKIE] = 1268 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1; 1269 dest[STYLE_RESOURCE_ID] = resid; 1270 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1271 dest[STYLE_DENSITY] = config.density; 1272 1273 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) { 1274 indicesIdx++; 1275 indices[indicesIdx] = ii; 1276 } 1277 1278 dest += STYLE_NUM_ENTRIES; 1279 } 1280 1281 res.unlock(); 1282 1283 if (indices != NULL) { 1284 indices[0] = indicesIdx; 1285 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1286 } 1287 1288 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1289 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1290 1291 return JNI_TRUE; 1292} 1293 1294static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz, 1295 jint id) 1296{ 1297 AssetManager* am = assetManagerForJavaObject(env, clazz); 1298 if (am == NULL) { 1299 return 0; 1300 } 1301 const ResTable& res(am->getResources()); 1302 1303 res.lock(); 1304 const ResTable::bag_entry* defStyleEnt = NULL; 1305 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt); 1306 res.unlock(); 1307 1308 return bagOff; 1309} 1310 1311static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz, 1312 jint id, 1313 jintArray outValues) 1314{ 1315 if (outValues == NULL) { 1316 jniThrowException(env, "java/lang/NullPointerException", "out values"); 1317 return JNI_FALSE; 1318 } 1319 1320 AssetManager* am = assetManagerForJavaObject(env, clazz); 1321 if (am == NULL) { 1322 return JNI_FALSE; 1323 } 1324 const ResTable& res(am->getResources()); 1325 ResTable_config config; 1326 Res_value value; 1327 ssize_t block; 1328 1329 const jsize NV = env->GetArrayLength(outValues); 1330 1331 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1332 jint* dest = baseDest; 1333 if (dest == NULL) { 1334 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1335 return JNI_FALSE; 1336 } 1337 1338 // Now lock down the resource object and start pulling stuff from it. 1339 res.lock(); 1340 1341 const ResTable::bag_entry* arrayEnt = NULL; 1342 uint32_t arrayTypeSetFlags = 0; 1343 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags); 1344 const ResTable::bag_entry* endArrayEnt = arrayEnt + 1345 (bagOff >= 0 ? bagOff : 0); 1346 1347 int i = 0; 1348 uint32_t typeSetFlags; 1349 while (i < NV && arrayEnt < endArrayEnt) { 1350 block = arrayEnt->stringBlock; 1351 typeSetFlags = arrayTypeSetFlags; 1352 config.density = 0; 1353 value = arrayEnt->map.value; 1354 1355 uint32_t resid = 0; 1356 if (value.dataType != Res_value::TYPE_NULL) { 1357 // Take care of resolving the found resource to its final value. 1358 //printf("Resolving attribute reference\n"); 1359 ssize_t newBlock = res.resolveReference(&value, block, &resid, 1360 &typeSetFlags, &config); 1361#if THROW_ON_BAD_ID 1362 if (newBlock == BAD_INDEX) { 1363 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1364 return JNI_FALSE; 1365 } 1366#endif 1367 if (newBlock >= 0) block = newBlock; 1368 } 1369 1370 // Deal with the special @null value -- it turns back to TYPE_NULL. 1371 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { 1372 value.dataType = Res_value::TYPE_NULL; 1373 } 1374 1375 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1376 1377 // Write the final value back to Java. 1378 dest[STYLE_TYPE] = value.dataType; 1379 dest[STYLE_DATA] = value.data; 1380 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block); 1381 dest[STYLE_RESOURCE_ID] = resid; 1382 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1383 dest[STYLE_DENSITY] = config.density; 1384 dest += STYLE_NUM_ENTRIES; 1385 i+= STYLE_NUM_ENTRIES; 1386 arrayEnt++; 1387 } 1388 1389 i /= STYLE_NUM_ENTRIES; 1390 1391 res.unlock(); 1392 1393 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1394 1395 return i; 1396} 1397 1398static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz, 1399 jint cookie, 1400 jstring fileName) 1401{ 1402 AssetManager* am = assetManagerForJavaObject(env, clazz); 1403 if (am == NULL) { 1404 return 0; 1405 } 1406 1407 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz); 1408 1409 if (fileName == NULL) { 1410 jniThrowException(env, "java/lang/NullPointerException", "fileName"); 1411 return 0; 1412 } 1413 1414 const char* fileName8 = env->GetStringUTFChars(fileName, NULL); 1415 Asset* a = cookie 1416 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER) 1417 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER); 1418 1419 if (a == NULL) { 1420 jniThrowException(env, "java/io/FileNotFoundException", fileName8); 1421 env->ReleaseStringUTFChars(fileName, fileName8); 1422 return 0; 1423 } 1424 env->ReleaseStringUTFChars(fileName, fileName8); 1425 1426 ResXMLTree* block = new ResXMLTree(); 1427 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true); 1428 a->close(); 1429 delete a; 1430 1431 if (err != NO_ERROR) { 1432 jniThrowException(env, "java/io/FileNotFoundException", "Corrupt XML binary file"); 1433 return 0; 1434 } 1435 1436 return (jint)block; 1437} 1438 1439static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz, 1440 jint arrayResId) 1441{ 1442 AssetManager* am = assetManagerForJavaObject(env, clazz); 1443 if (am == NULL) { 1444 return NULL; 1445 } 1446 const ResTable& res(am->getResources()); 1447 1448 const ResTable::bag_entry* startOfBag; 1449 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1450 if (N < 0) { 1451 return NULL; 1452 } 1453 1454 jintArray array = env->NewIntArray(N * 2); 1455 if (array == NULL) { 1456 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1457 res.unlockBag(startOfBag); 1458 return NULL; 1459 } 1460 1461 Res_value value; 1462 const ResTable::bag_entry* bag = startOfBag; 1463 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) { 1464 jint stringIndex = -1; 1465 jint stringBlock = 0; 1466 value = bag->map.value; 1467 1468 // Take care of resolving the found resource to its final value. 1469 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL); 1470 if (value.dataType == Res_value::TYPE_STRING) { 1471 stringIndex = value.data; 1472 } 1473 1474#if THROW_ON_BAD_ID 1475 if (stringBlock == BAD_INDEX) { 1476 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1477 return array; 1478 } 1479#endif 1480 1481 //todo: It might be faster to allocate a C array to contain 1482 // the blocknums and indices, put them in there and then 1483 // do just one SetIntArrayRegion() 1484 env->SetIntArrayRegion(array, j, 1, &stringBlock); 1485 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex); 1486 j = j + 2; 1487 } 1488 res.unlockBag(startOfBag); 1489 return array; 1490} 1491 1492static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz, 1493 jint arrayResId) 1494{ 1495 AssetManager* am = assetManagerForJavaObject(env, clazz); 1496 if (am == NULL) { 1497 return NULL; 1498 } 1499 const ResTable& res(am->getResources()); 1500 1501 jclass cls = env->FindClass("java/lang/String"); 1502 LOG_FATAL_IF(cls == NULL, "No string class?!?"); 1503 if (cls == NULL) { 1504 return NULL; 1505 } 1506 1507 const ResTable::bag_entry* startOfBag; 1508 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1509 if (N < 0) { 1510 return NULL; 1511 } 1512 1513 jobjectArray array = env->NewObjectArray(N, cls, NULL); 1514 if (env->ExceptionCheck()) { 1515 res.unlockBag(startOfBag); 1516 return NULL; 1517 } 1518 1519 Res_value value; 1520 const ResTable::bag_entry* bag = startOfBag; 1521 size_t strLen = 0; 1522 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1523 value = bag->map.value; 1524 jstring str = NULL; 1525 1526 // Take care of resolving the found resource to its final value. 1527 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); 1528#if THROW_ON_BAD_ID 1529 if (block == BAD_INDEX) { 1530 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1531 return array; 1532 } 1533#endif 1534 if (value.dataType == Res_value::TYPE_STRING) { 1535 const ResStringPool* pool = res.getTableStringBlock(block); 1536 const char* str8 = pool->string8At(value.data, &strLen); 1537 if (str8 != NULL) { 1538 str = env->NewStringUTF(str8); 1539 } else { 1540 const char16_t* str16 = pool->stringAt(value.data, &strLen); 1541 str = env->NewString(str16, strLen); 1542 } 1543 1544 // If one of our NewString{UTF} calls failed due to memory, an 1545 // exception will be pending. 1546 if (env->ExceptionCheck()) { 1547 res.unlockBag(startOfBag); 1548 return NULL; 1549 } 1550 1551 env->SetObjectArrayElement(array, i, str); 1552 1553 // str is not NULL at that point, otherwise ExceptionCheck would have been true. 1554 // If we have a large amount of strings in our array, we might 1555 // overflow the local reference table of the VM. 1556 env->DeleteLocalRef(str); 1557 } 1558 } 1559 res.unlockBag(startOfBag); 1560 return array; 1561} 1562 1563static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz, 1564 jint arrayResId) 1565{ 1566 AssetManager* am = assetManagerForJavaObject(env, clazz); 1567 if (am == NULL) { 1568 return NULL; 1569 } 1570 const ResTable& res(am->getResources()); 1571 1572 const ResTable::bag_entry* startOfBag; 1573 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1574 if (N < 0) { 1575 return NULL; 1576 } 1577 1578 jintArray array = env->NewIntArray(N); 1579 if (array == NULL) { 1580 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1581 res.unlockBag(startOfBag); 1582 return NULL; 1583 } 1584 1585 Res_value value; 1586 const ResTable::bag_entry* bag = startOfBag; 1587 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1588 value = bag->map.value; 1589 1590 // Take care of resolving the found resource to its final value. 1591 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); 1592#if THROW_ON_BAD_ID 1593 if (block == BAD_INDEX) { 1594 jniThrowException(env, "java/lang/IllegalStateException", "Bad resource!"); 1595 return array; 1596 } 1597#endif 1598 if (value.dataType >= Res_value::TYPE_FIRST_INT 1599 && value.dataType <= Res_value::TYPE_LAST_INT) { 1600 int intVal = value.data; 1601 env->SetIntArrayRegion(array, i, 1, &intVal); 1602 } 1603 } 1604 res.unlockBag(startOfBag); 1605 return array; 1606} 1607 1608static void android_content_AssetManager_init(JNIEnv* env, jobject clazz) 1609{ 1610 AssetManager* am = new AssetManager(); 1611 if (am == NULL) { 1612 jniThrowException(env, "java/lang/OutOfMemoryError", ""); 1613 return; 1614 } 1615 1616 am->addDefaultAssets(); 1617 1618 LOGV("Created AssetManager %p for Java object %p\n", am, clazz); 1619 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am); 1620} 1621 1622static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz) 1623{ 1624 AssetManager* am = (AssetManager*) 1625 (env->GetIntField(clazz, gAssetManagerOffsets.mObject)); 1626 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz); 1627 if (am != NULL) { 1628 delete am; 1629 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0); 1630 } 1631} 1632 1633static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz) 1634{ 1635 return Asset::getGlobalCount(); 1636} 1637 1638static jobject android_content_AssetManager_getAssetAllocations(JNIEnv* env, jobject clazz) 1639{ 1640 String8 alloc = Asset::getAssetAllocations(); 1641 if (alloc.length() <= 0) { 1642 return NULL; 1643 } 1644 1645 jstring str = env->NewStringUTF(alloc.string()); 1646 return str; 1647} 1648 1649static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz) 1650{ 1651 return AssetManager::getGlobalCount(); 1652} 1653 1654// ---------------------------------------------------------------------------- 1655 1656/* 1657 * JNI registration. 1658 */ 1659static JNINativeMethod gAssetManagerMethods[] = { 1660 /* name, signature, funcPtr */ 1661 1662 // Basic asset stuff. 1663 { "openAsset", "(Ljava/lang/String;I)I", 1664 (void*) android_content_AssetManager_openAsset }, 1665 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1666 (void*) android_content_AssetManager_openAssetFd }, 1667 { "openNonAssetNative", "(ILjava/lang/String;I)I", 1668 (void*) android_content_AssetManager_openNonAssetNative }, 1669 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1670 (void*) android_content_AssetManager_openNonAssetFdNative }, 1671 { "list", "(Ljava/lang/String;)[Ljava/lang/String;", 1672 (void*) android_content_AssetManager_list }, 1673 { "destroyAsset", "(I)V", 1674 (void*) android_content_AssetManager_destroyAsset }, 1675 { "readAssetChar", "(I)I", 1676 (void*) android_content_AssetManager_readAssetChar }, 1677 { "readAsset", "(I[BII)I", 1678 (void*) android_content_AssetManager_readAsset }, 1679 { "seekAsset", "(IJI)J", 1680 (void*) android_content_AssetManager_seekAsset }, 1681 { "getAssetLength", "(I)J", 1682 (void*) android_content_AssetManager_getAssetLength }, 1683 { "getAssetRemainingLength", "(I)J", 1684 (void*) android_content_AssetManager_getAssetRemainingLength }, 1685 { "addAssetPath", "(Ljava/lang/String;)I", 1686 (void*) android_content_AssetManager_addAssetPath }, 1687 { "isUpToDate", "()Z", 1688 (void*) android_content_AssetManager_isUpToDate }, 1689 1690 // Resources. 1691 { "setLocale", "(Ljava/lang/String;)V", 1692 (void*) android_content_AssetManager_setLocale }, 1693 { "getLocales", "()[Ljava/lang/String;", 1694 (void*) android_content_AssetManager_getLocales }, 1695 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIIII)V", 1696 (void*) android_content_AssetManager_setConfiguration }, 1697 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", 1698 (void*) android_content_AssetManager_getResourceIdentifier }, 1699 { "getResourceName","(I)Ljava/lang/String;", 1700 (void*) android_content_AssetManager_getResourceName }, 1701 { "getResourcePackageName","(I)Ljava/lang/String;", 1702 (void*) android_content_AssetManager_getResourcePackageName }, 1703 { "getResourceTypeName","(I)Ljava/lang/String;", 1704 (void*) android_content_AssetManager_getResourceTypeName }, 1705 { "getResourceEntryName","(I)Ljava/lang/String;", 1706 (void*) android_content_AssetManager_getResourceEntryName }, 1707 { "loadResourceValue","(ISLandroid/util/TypedValue;Z)I", 1708 (void*) android_content_AssetManager_loadResourceValue }, 1709 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I", 1710 (void*) android_content_AssetManager_loadResourceBagValue }, 1711 { "getStringBlockCount","()I", 1712 (void*) android_content_AssetManager_getStringBlockCount }, 1713 { "getNativeStringBlock","(I)I", 1714 (void*) android_content_AssetManager_getNativeStringBlock }, 1715 { "getCookieName","(I)Ljava/lang/String;", 1716 (void*) android_content_AssetManager_getCookieName }, 1717 1718 // Themes. 1719 { "newTheme", "()I", 1720 (void*) android_content_AssetManager_newTheme }, 1721 { "deleteTheme", "(I)V", 1722 (void*) android_content_AssetManager_deleteTheme }, 1723 { "applyThemeStyle", "(IIZ)V", 1724 (void*) android_content_AssetManager_applyThemeStyle }, 1725 { "copyTheme", "(II)V", 1726 (void*) android_content_AssetManager_copyTheme }, 1727 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I", 1728 (void*) android_content_AssetManager_loadThemeAttributeValue }, 1729 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V", 1730 (void*) android_content_AssetManager_dumpTheme }, 1731 { "applyStyle","(IIII[I[I[I)Z", 1732 (void*) android_content_AssetManager_applyStyle }, 1733 { "retrieveAttributes","(I[I[I[I)Z", 1734 (void*) android_content_AssetManager_retrieveAttributes }, 1735 { "getArraySize","(I)I", 1736 (void*) android_content_AssetManager_getArraySize }, 1737 { "retrieveArray","(I[I)I", 1738 (void*) android_content_AssetManager_retrieveArray }, 1739 1740 // XML files. 1741 { "openXmlAssetNative", "(ILjava/lang/String;)I", 1742 (void*) android_content_AssetManager_openXmlAssetNative }, 1743 1744 // Arrays. 1745 { "getArrayStringResource","(I)[Ljava/lang/String;", 1746 (void*) android_content_AssetManager_getArrayStringResource }, 1747 { "getArrayStringInfo","(I)[I", 1748 (void*) android_content_AssetManager_getArrayStringInfo }, 1749 { "getArrayIntResource","(I)[I", 1750 (void*) android_content_AssetManager_getArrayIntResource }, 1751 1752 // Bookkeeping. 1753 { "init", "()V", 1754 (void*) android_content_AssetManager_init }, 1755 { "destroy", "()V", 1756 (void*) android_content_AssetManager_destroy }, 1757 { "getGlobalAssetCount", "()I", 1758 (void*) android_content_AssetManager_getGlobalAssetCount }, 1759 { "getAssetAllocations", "()Ljava/lang/String;", 1760 (void*) android_content_AssetManager_getAssetAllocations }, 1761 { "getGlobalAssetManagerCount", "()I", 1762 (void*) android_content_AssetManager_getGlobalAssetCount }, 1763}; 1764 1765int register_android_content_AssetManager(JNIEnv* env) 1766{ 1767 jclass typedValue = env->FindClass("android/util/TypedValue"); 1768 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue"); 1769 gTypedValueOffsets.mType 1770 = env->GetFieldID(typedValue, "type", "I"); 1771 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type"); 1772 gTypedValueOffsets.mData 1773 = env->GetFieldID(typedValue, "data", "I"); 1774 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data"); 1775 gTypedValueOffsets.mString 1776 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;"); 1777 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string"); 1778 gTypedValueOffsets.mAssetCookie 1779 = env->GetFieldID(typedValue, "assetCookie", "I"); 1780 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie"); 1781 gTypedValueOffsets.mResourceId 1782 = env->GetFieldID(typedValue, "resourceId", "I"); 1783 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId"); 1784 gTypedValueOffsets.mChangingConfigurations 1785 = env->GetFieldID(typedValue, "changingConfigurations", "I"); 1786 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations"); 1787 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I"); 1788 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density"); 1789 1790 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor"); 1791 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor"); 1792 gAssetFileDescriptorOffsets.mFd 1793 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;"); 1794 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd"); 1795 gAssetFileDescriptorOffsets.mStartOffset 1796 = env->GetFieldID(assetFd, "mStartOffset", "J"); 1797 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset"); 1798 gAssetFileDescriptorOffsets.mLength 1799 = env->GetFieldID(assetFd, "mLength", "J"); 1800 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength"); 1801 1802 jclass assetManager = env->FindClass("android/content/res/AssetManager"); 1803 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager"); 1804 gAssetManagerOffsets.mObject 1805 = env->GetFieldID(assetManager, "mObject", "I"); 1806 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject"); 1807 1808 g_stringClass = env->FindClass("java/lang/String"); 1809 1810 return AndroidRuntime::registerNativeMethods(env, 1811 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods)); 1812} 1813 1814}; // namespace android 1815