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