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