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