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