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