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