android_util_AssetManager.cpp revision c4db95c077f826585d20be2f3db4043c53d30cf5
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 screenLayout, 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; 557 config.navigation = (uint8_t)navigation; 558 config.screenWidth = (uint16_t)screenWidth; 559 config.screenHeight = (uint16_t)screenHeight; 560 config.screenLayout = (uint8_t)screenLayout; 561 config.sdkVersion = (uint16_t)sdkVersion; 562 config.minorVersion = 0; 563 am->setConfiguration(config, locale8); 564 565 if (locale != NULL) env->ReleaseStringUTFChars(locale, locale8); 566} 567 568static jint android_content_AssetManager_getResourceIdentifier(JNIEnv* env, jobject clazz, 569 jstring name, 570 jstring defType, 571 jstring defPackage) 572{ 573 if (name == NULL) { 574 doThrow(env, "java/lang/NullPointerException"); 575 return 0; 576 } 577 578 AssetManager* am = assetManagerForJavaObject(env, clazz); 579 if (am == NULL) { 580 return 0; 581 } 582 583 const char16_t* name16 = env->GetStringChars(name, NULL); 584 jsize nameLen = env->GetStringLength(name); 585 const char16_t* defType16 = defType 586 ? env->GetStringChars(defType, NULL) : NULL; 587 jsize defTypeLen = defType 588 ? env->GetStringLength(defType) : 0; 589 const char16_t* defPackage16 = defPackage 590 ? env->GetStringChars(defPackage, NULL) : NULL; 591 jsize defPackageLen = defPackage 592 ? env->GetStringLength(defPackage) : 0; 593 594 jint ident = am->getResources().identifierForName( 595 name16, nameLen, defType16, defTypeLen, defPackage16, defPackageLen); 596 597 if (defPackage16) { 598 env->ReleaseStringChars(defPackage, defPackage16); 599 } 600 if (defType16) { 601 env->ReleaseStringChars(defType, defType16); 602 } 603 env->ReleaseStringChars(name, name16); 604 605 return ident; 606} 607 608static jstring android_content_AssetManager_getResourceName(JNIEnv* env, jobject clazz, 609 jint resid) 610{ 611 AssetManager* am = assetManagerForJavaObject(env, clazz); 612 if (am == NULL) { 613 return NULL; 614 } 615 616 ResTable::resource_name name; 617 if (!am->getResources().getResourceName(resid, &name)) { 618 return NULL; 619 } 620 621 String16 str; 622 if (name.package != NULL) { 623 str.setTo(name.package, name.packageLen); 624 } 625 if (name.type != NULL) { 626 if (str.size() > 0) { 627 char16_t div = ':'; 628 str.append(&div, 1); 629 } 630 str.append(name.type, name.typeLen); 631 } 632 if (name.name != NULL) { 633 if (str.size() > 0) { 634 char16_t div = '/'; 635 str.append(&div, 1); 636 } 637 str.append(name.name, name.nameLen); 638 } 639 640 return env->NewString((const jchar*)str.string(), str.size()); 641} 642 643static jstring android_content_AssetManager_getResourcePackageName(JNIEnv* env, jobject clazz, 644 jint resid) 645{ 646 AssetManager* am = assetManagerForJavaObject(env, clazz); 647 if (am == NULL) { 648 return NULL; 649 } 650 651 ResTable::resource_name name; 652 if (!am->getResources().getResourceName(resid, &name)) { 653 return NULL; 654 } 655 656 if (name.package != NULL) { 657 return env->NewString((const jchar*)name.package, name.packageLen); 658 } 659 660 return NULL; 661} 662 663static jstring android_content_AssetManager_getResourceTypeName(JNIEnv* env, jobject clazz, 664 jint resid) 665{ 666 AssetManager* am = assetManagerForJavaObject(env, clazz); 667 if (am == NULL) { 668 return NULL; 669 } 670 671 ResTable::resource_name name; 672 if (!am->getResources().getResourceName(resid, &name)) { 673 return NULL; 674 } 675 676 if (name.type != NULL) { 677 return env->NewString((const jchar*)name.type, name.typeLen); 678 } 679 680 return NULL; 681} 682 683static jstring android_content_AssetManager_getResourceEntryName(JNIEnv* env, jobject clazz, 684 jint resid) 685{ 686 AssetManager* am = assetManagerForJavaObject(env, clazz); 687 if (am == NULL) { 688 return NULL; 689 } 690 691 ResTable::resource_name name; 692 if (!am->getResources().getResourceName(resid, &name)) { 693 return NULL; 694 } 695 696 if (name.name != NULL) { 697 return env->NewString((const jchar*)name.name, name.nameLen); 698 } 699 700 return NULL; 701} 702 703static jint android_content_AssetManager_loadResourceValue(JNIEnv* env, jobject clazz, 704 jint ident, 705 jobject outValue, 706 jboolean resolve) 707{ 708 AssetManager* am = assetManagerForJavaObject(env, clazz); 709 if (am == NULL) { 710 return 0; 711 } 712 const ResTable& res(am->getResources()); 713 714 Res_value value; 715 ResTable_config config; 716 uint32_t typeSpecFlags; 717 ssize_t block = res.getResource(ident, &value, false, &typeSpecFlags, &config); 718 uint32_t ref = ident; 719 if (resolve) { 720 block = res.resolveReference(&value, block, &ref); 721 } 722 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags, &config) : block; 723} 724 725static jint android_content_AssetManager_loadResourceBagValue(JNIEnv* env, jobject clazz, 726 jint ident, jint bagEntryId, 727 jobject outValue, jboolean resolve) 728{ 729 AssetManager* am = assetManagerForJavaObject(env, clazz); 730 if (am == NULL) { 731 return 0; 732 } 733 const ResTable& res(am->getResources()); 734 735 // Now lock down the resource object and start pulling stuff from it. 736 res.lock(); 737 738 ssize_t block = -1; 739 Res_value value; 740 741 const ResTable::bag_entry* entry = NULL; 742 uint32_t typeSpecFlags; 743 ssize_t entryCount = res.getBagLocked(ident, &entry, &typeSpecFlags); 744 745 for (ssize_t i=0; i<entryCount; i++) { 746 if (((uint32_t)bagEntryId) == entry->map.name.ident) { 747 block = entry->stringBlock; 748 value = entry->map.value; 749 } 750 entry++; 751 } 752 753 res.unlock(); 754 755 if (block < 0) { 756 return block; 757 } 758 759 uint32_t ref = ident; 760 if (resolve) { 761 block = res.resolveReference(&value, block, &ref, &typeSpecFlags); 762 } 763 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block; 764} 765 766static jint android_content_AssetManager_getStringBlockCount(JNIEnv* env, jobject clazz) 767{ 768 AssetManager* am = assetManagerForJavaObject(env, clazz); 769 if (am == NULL) { 770 return 0; 771 } 772 return am->getResources().getTableCount(); 773} 774 775static jint android_content_AssetManager_getNativeStringBlock(JNIEnv* env, jobject clazz, 776 jint block) 777{ 778 AssetManager* am = assetManagerForJavaObject(env, clazz); 779 if (am == NULL) { 780 return 0; 781 } 782 return (jint)am->getResources().getTableStringBlock(block); 783} 784 785static jstring android_content_AssetManager_getCookieName(JNIEnv* env, jobject clazz, 786 jint cookie) 787{ 788 AssetManager* am = assetManagerForJavaObject(env, clazz); 789 if (am == NULL) { 790 return NULL; 791 } 792 String8 name(am->getAssetPath((void*)cookie)); 793 if (name.length() == 0) { 794 doThrow(env, "java/lang/IndexOutOfBoundsException"); 795 return NULL; 796 } 797 jstring str = env->NewStringUTF(name.string()); 798 if (str == NULL) { 799 doThrow(env, "java/lang/OutOfMemoryError"); 800 return NULL; 801 } 802 return str; 803} 804 805static jint android_content_AssetManager_newTheme(JNIEnv* env, jobject clazz) 806{ 807 AssetManager* am = assetManagerForJavaObject(env, clazz); 808 if (am == NULL) { 809 return 0; 810 } 811 return (jint)(new ResTable::Theme(am->getResources())); 812} 813 814static void android_content_AssetManager_deleteTheme(JNIEnv* env, jobject clazz, 815 jint themeInt) 816{ 817 ResTable::Theme* theme = (ResTable::Theme*)themeInt; 818 delete theme; 819} 820 821static void android_content_AssetManager_applyThemeStyle(JNIEnv* env, jobject clazz, 822 jint themeInt, 823 jint styleRes, 824 jboolean force) 825{ 826 ResTable::Theme* theme = (ResTable::Theme*)themeInt; 827 theme->applyStyle(styleRes, force ? true : false); 828} 829 830static void android_content_AssetManager_copyTheme(JNIEnv* env, jobject clazz, 831 jint destInt, jint srcInt) 832{ 833 ResTable::Theme* dest = (ResTable::Theme*)destInt; 834 ResTable::Theme* src = (ResTable::Theme*)srcInt; 835 dest->setTo(*src); 836} 837 838static jint android_content_AssetManager_loadThemeAttributeValue( 839 JNIEnv* env, jobject clazz, jint themeInt, jint ident, jobject outValue, jboolean resolve) 840{ 841 ResTable::Theme* theme = (ResTable::Theme*)themeInt; 842 const ResTable& res(theme->getResTable()); 843 844 Res_value value; 845 // XXX value could be different in different configs! 846 uint32_t typeSpecFlags = 0; 847 ssize_t block = theme->getAttribute(ident, &value, &typeSpecFlags); 848 uint32_t ref = 0; 849 if (resolve) { 850 block = res.resolveReference(&value, block, &ref, &typeSpecFlags); 851 } 852 return block >= 0 ? copyValue(env, outValue, &res, value, ref, block, typeSpecFlags) : block; 853} 854 855static void android_content_AssetManager_dumpTheme(JNIEnv* env, jobject clazz, 856 jint themeInt, jint pri, 857 jstring tag, jstring prefix) 858{ 859 ResTable::Theme* theme = (ResTable::Theme*)themeInt; 860 const ResTable& res(theme->getResTable()); 861 862 if (tag == NULL) { 863 doThrow(env, "java/lang/NullPointerException"); 864 return; 865 } 866 867 const char* tag8 = env->GetStringUTFChars(tag, NULL); 868 const char* prefix8 = NULL; 869 if (prefix != NULL) { 870 prefix8 = env->GetStringUTFChars(prefix, NULL); 871 } 872 873 // XXX Need to use params. 874 theme->dumpToLog(); 875 876 if (prefix8 != NULL) { 877 env->ReleaseStringUTFChars(prefix, prefix8); 878 } 879 env->ReleaseStringUTFChars(tag, tag8); 880} 881 882static jboolean android_content_AssetManager_applyStyle(JNIEnv* env, jobject clazz, 883 jint themeToken, 884 jint defStyleAttr, 885 jint defStyleRes, 886 jint xmlParserToken, 887 jintArray attrs, 888 jintArray outValues, 889 jintArray outIndices) 890{ 891 if (themeToken == 0 || attrs == NULL || outValues == NULL) { 892 doThrow(env, "java/lang/NullPointerException"); 893 return JNI_FALSE; 894 } 895 896 ResTable::Theme* theme = (ResTable::Theme*)themeToken; 897 const ResTable& res = theme->getResTable(); 898 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken; 899 Res_value value; 900 901 const jsize NI = env->GetArrayLength(attrs); 902 const jsize NV = env->GetArrayLength(outValues); 903 if (NV < (NI*STYLE_NUM_ENTRIES)) { 904 doThrow(env, "java/lang/IndexOutOfBoundsException"); 905 return JNI_FALSE; 906 } 907 908 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0); 909 if (src == NULL) { 910 doThrow(env, "java/lang/OutOfMemoryError"); 911 return JNI_FALSE; 912 } 913 914 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 915 jint* dest = baseDest; 916 if (dest == NULL) { 917 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 918 doThrow(env, "java/lang/OutOfMemoryError"); 919 return JNI_FALSE; 920 } 921 922 jint* indices = NULL; 923 int indicesIdx = 0; 924 if (outIndices != NULL) { 925 if (env->GetArrayLength(outIndices) > NI) { 926 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0); 927 } 928 } 929 930 // Load default style from attribute, if specified... 931 uint32_t defStyleBagTypeSetFlags = 0; 932 if (defStyleAttr != 0) { 933 Res_value value; 934 if (theme->getAttribute(defStyleAttr, &value, &defStyleBagTypeSetFlags) >= 0) { 935 if (value.dataType == Res_value::TYPE_REFERENCE) { 936 defStyleRes = value.data; 937 } 938 } 939 } 940 941 // Retrieve the style class associated with the current XML tag. 942 int style = 0; 943 uint32_t styleBagTypeSetFlags = 0; 944 if (xmlParser != NULL) { 945 ssize_t idx = xmlParser->indexOfStyle(); 946 if (idx >= 0 && xmlParser->getAttributeValue(idx, &value) >= 0) { 947 if (value.dataType == value.TYPE_ATTRIBUTE) { 948 if (theme->getAttribute(value.data, &value, &styleBagTypeSetFlags) < 0) { 949 value.dataType = Res_value::TYPE_NULL; 950 } 951 } 952 if (value.dataType == value.TYPE_REFERENCE) { 953 style = value.data; 954 } 955 } 956 } 957 958 // Now lock down the resource object and start pulling stuff from it. 959 res.lock(); 960 961 // Retrieve the default style bag, if requested. 962 const ResTable::bag_entry* defStyleEnt = NULL; 963 uint32_t defStyleTypeSetFlags = 0; 964 ssize_t bagOff = defStyleRes != 0 965 ? res.getBagLocked(defStyleRes, &defStyleEnt, &defStyleTypeSetFlags) : -1; 966 defStyleTypeSetFlags |= defStyleBagTypeSetFlags; 967 const ResTable::bag_entry* endDefStyleEnt = defStyleEnt + 968 (bagOff >= 0 ? bagOff : 0); 969 970 // Retrieve the style class bag, if requested. 971 const ResTable::bag_entry* styleEnt = NULL; 972 uint32_t styleTypeSetFlags = 0; 973 bagOff = style != 0 ? res.getBagLocked(style, &styleEnt, &styleTypeSetFlags) : -1; 974 styleTypeSetFlags |= styleBagTypeSetFlags; 975 const ResTable::bag_entry* endStyleEnt = styleEnt + 976 (bagOff >= 0 ? bagOff : 0); 977 978 // Retrieve the XML attributes, if requested. 979 const jsize NX = xmlParser ? xmlParser->getAttributeCount() : 0; 980 jsize ix=0; 981 uint32_t curXmlAttr = xmlParser ? xmlParser->getAttributeNameResID(ix) : 0; 982 983 static const ssize_t kXmlBlock = 0x10000000; 984 985 // Now iterate through all of the attributes that the client has requested, 986 // filling in each with whatever data we can find. 987 ssize_t block = 0; 988 uint32_t typeSetFlags; 989 for (jsize ii=0; ii<NI; ii++) { 990 const uint32_t curIdent = (uint32_t)src[ii]; 991 992 // Try to find a value for this attribute... we prioritize values 993 // coming from, first XML attributes, then XML style, then default 994 // style, and finally the theme. 995 value.dataType = Res_value::TYPE_NULL; 996 value.data = 0; 997 typeSetFlags = 0; 998 999 // Skip through XML attributes until the end or the next possible match. 1000 while (ix < NX && curIdent > curXmlAttr) { 1001 ix++; 1002 curXmlAttr = xmlParser->getAttributeNameResID(ix); 1003 } 1004 // Retrieve the current XML attribute if it matches, and step to next. 1005 if (ix < NX && curIdent == curXmlAttr) { 1006 block = kXmlBlock; 1007 xmlParser->getAttributeValue(ix, &value); 1008 ix++; 1009 curXmlAttr = xmlParser->getAttributeNameResID(ix); 1010 } 1011 1012 // Skip through the style values until the end or the next possible match. 1013 while (styleEnt < endStyleEnt && curIdent > styleEnt->map.name.ident) { 1014 styleEnt++; 1015 } 1016 // Retrieve the current style attribute if it matches, and step to next. 1017 if (styleEnt < endStyleEnt && curIdent == styleEnt->map.name.ident) { 1018 if (value.dataType == Res_value::TYPE_NULL) { 1019 block = styleEnt->stringBlock; 1020 typeSetFlags = styleTypeSetFlags; 1021 value = styleEnt->map.value; 1022 } 1023 styleEnt++; 1024 } 1025 1026 // Skip through the default style values until the end or the next possible match. 1027 while (defStyleEnt < endDefStyleEnt && curIdent > defStyleEnt->map.name.ident) { 1028 defStyleEnt++; 1029 } 1030 // Retrieve the current default style attribute if it matches, and step to next. 1031 if (defStyleEnt < endDefStyleEnt && curIdent == defStyleEnt->map.name.ident) { 1032 if (value.dataType == Res_value::TYPE_NULL) { 1033 block = defStyleEnt->stringBlock; 1034 typeSetFlags = defStyleTypeSetFlags; 1035 value = defStyleEnt->map.value; 1036 } 1037 defStyleEnt++; 1038 } 1039 1040 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1041 uint32_t resid = 0; 1042 if (value.dataType != Res_value::TYPE_NULL) { 1043 // Take care of resolving the found resource to its final value. 1044 //printf("Resolving attribute reference\n"); 1045 ssize_t newBlock = theme->resolveAttributeReference(&value, block, &resid, &typeSetFlags); 1046 if (newBlock >= 0) block = newBlock; 1047 } else { 1048 // If we still don't have a value for this attribute, try to find 1049 // it in the theme! 1050 //printf("Looking up in theme\n"); 1051 ssize_t newBlock = theme->getAttribute(curIdent, &value, &typeSetFlags); 1052 if (newBlock >= 0) { 1053 //printf("Resolving resource reference\n"); 1054 newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags); 1055 if (newBlock >= 0) block = newBlock; 1056 } 1057 } 1058 1059 // Deal with the special @null value -- it turns back to TYPE_NULL. 1060 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { 1061 value.dataType = Res_value::TYPE_NULL; 1062 } 1063 1064 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1065 1066 // Write the final value back to Java. 1067 dest[STYLE_TYPE] = value.dataType; 1068 dest[STYLE_DATA] = value.data; 1069 dest[STYLE_ASSET_COOKIE] = 1070 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1; 1071 dest[STYLE_RESOURCE_ID] = resid; 1072 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1073 1074 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) { 1075 indicesIdx++; 1076 indices[indicesIdx] = ii; 1077 } 1078 1079 dest += STYLE_NUM_ENTRIES; 1080 } 1081 1082 res.unlock(); 1083 1084 if (indices != NULL) { 1085 indices[0] = indicesIdx; 1086 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1087 } 1088 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1089 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1090 1091 return JNI_TRUE; 1092} 1093 1094static jboolean android_content_AssetManager_retrieveAttributes(JNIEnv* env, jobject clazz, 1095 jint xmlParserToken, 1096 jintArray attrs, 1097 jintArray outValues, 1098 jintArray outIndices) 1099{ 1100 if (xmlParserToken == 0 || attrs == NULL || outValues == NULL) { 1101 doThrow(env, "java/lang/NullPointerException"); 1102 return JNI_FALSE; 1103 } 1104 1105 AssetManager* am = assetManagerForJavaObject(env, clazz); 1106 if (am == NULL) { 1107 return JNI_FALSE; 1108 } 1109 const ResTable& res(am->getResources()); 1110 ResXMLParser* xmlParser = (ResXMLParser*)xmlParserToken; 1111 Res_value value; 1112 1113 const jsize NI = env->GetArrayLength(attrs); 1114 const jsize NV = env->GetArrayLength(outValues); 1115 if (NV < (NI*STYLE_NUM_ENTRIES)) { 1116 doThrow(env, "java/lang/IndexOutOfBoundsException"); 1117 return JNI_FALSE; 1118 } 1119 1120 jint* src = (jint*)env->GetPrimitiveArrayCritical(attrs, 0); 1121 if (src == NULL) { 1122 doThrow(env, "java/lang/OutOfMemoryError"); 1123 return JNI_FALSE; 1124 } 1125 1126 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1127 jint* dest = baseDest; 1128 if (dest == NULL) { 1129 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1130 doThrow(env, "java/lang/OutOfMemoryError"); 1131 return JNI_FALSE; 1132 } 1133 1134 jint* indices = NULL; 1135 int indicesIdx = 0; 1136 if (outIndices != NULL) { 1137 if (env->GetArrayLength(outIndices) > NI) { 1138 indices = (jint*)env->GetPrimitiveArrayCritical(outIndices, 0); 1139 } 1140 } 1141 1142 // Now lock down the resource object and start pulling stuff from it. 1143 res.lock(); 1144 1145 // Retrieve the XML attributes, if requested. 1146 const jsize NX = xmlParser->getAttributeCount(); 1147 jsize ix=0; 1148 uint32_t curXmlAttr = xmlParser->getAttributeNameResID(ix); 1149 1150 static const ssize_t kXmlBlock = 0x10000000; 1151 1152 // Now iterate through all of the attributes that the client has requested, 1153 // filling in each with whatever data we can find. 1154 ssize_t block = 0; 1155 uint32_t typeSetFlags; 1156 for (jsize ii=0; ii<NI; ii++) { 1157 const uint32_t curIdent = (uint32_t)src[ii]; 1158 1159 // Try to find a value for this attribute... 1160 value.dataType = Res_value::TYPE_NULL; 1161 value.data = 0; 1162 typeSetFlags = 0; 1163 1164 // Skip through XML attributes until the end or the next possible match. 1165 while (ix < NX && curIdent > curXmlAttr) { 1166 ix++; 1167 curXmlAttr = xmlParser->getAttributeNameResID(ix); 1168 } 1169 // Retrieve the current XML attribute if it matches, and step to next. 1170 if (ix < NX && curIdent == curXmlAttr) { 1171 block = kXmlBlock; 1172 xmlParser->getAttributeValue(ix, &value); 1173 ix++; 1174 curXmlAttr = xmlParser->getAttributeNameResID(ix); 1175 } 1176 1177 //printf("Attribute 0x%08x: type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1178 uint32_t resid = 0; 1179 if (value.dataType != Res_value::TYPE_NULL) { 1180 // Take care of resolving the found resource to its final value. 1181 //printf("Resolving attribute reference\n"); 1182 ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags); 1183 if (newBlock >= 0) block = newBlock; 1184 } 1185 1186 // Deal with the special @null value -- it turns back to TYPE_NULL. 1187 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { 1188 value.dataType = Res_value::TYPE_NULL; 1189 } 1190 1191 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1192 1193 // Write the final value back to Java. 1194 dest[STYLE_TYPE] = value.dataType; 1195 dest[STYLE_DATA] = value.data; 1196 dest[STYLE_ASSET_COOKIE] = 1197 block != kXmlBlock ? (jint)res.getTableCookie(block) : (jint)-1; 1198 dest[STYLE_RESOURCE_ID] = resid; 1199 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1200 1201 if (indices != NULL && value.dataType != Res_value::TYPE_NULL) { 1202 indicesIdx++; 1203 indices[indicesIdx] = ii; 1204 } 1205 1206 dest += STYLE_NUM_ENTRIES; 1207 } 1208 1209 res.unlock(); 1210 1211 if (indices != NULL) { 1212 indices[0] = indicesIdx; 1213 env->ReleasePrimitiveArrayCritical(outIndices, indices, 0); 1214 } 1215 1216 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1217 env->ReleasePrimitiveArrayCritical(attrs, src, 0); 1218 1219 return JNI_TRUE; 1220} 1221 1222static jint android_content_AssetManager_getArraySize(JNIEnv* env, jobject clazz, 1223 jint id) 1224{ 1225 AssetManager* am = assetManagerForJavaObject(env, clazz); 1226 if (am == NULL) { 1227 return NULL; 1228 } 1229 const ResTable& res(am->getResources()); 1230 1231 res.lock(); 1232 const ResTable::bag_entry* defStyleEnt = NULL; 1233 ssize_t bagOff = res.getBagLocked(id, &defStyleEnt); 1234 res.unlock(); 1235 1236 return bagOff; 1237} 1238 1239static jint android_content_AssetManager_retrieveArray(JNIEnv* env, jobject clazz, 1240 jint id, 1241 jintArray outValues) 1242{ 1243 if (outValues == NULL) { 1244 doThrow(env, "java/lang/NullPointerException"); 1245 return JNI_FALSE; 1246 } 1247 1248 AssetManager* am = assetManagerForJavaObject(env, clazz); 1249 if (am == NULL) { 1250 return JNI_FALSE; 1251 } 1252 const ResTable& res(am->getResources()); 1253 Res_value value; 1254 ssize_t block; 1255 1256 const jsize NV = env->GetArrayLength(outValues); 1257 1258 jint* baseDest = (jint*)env->GetPrimitiveArrayCritical(outValues, 0); 1259 jint* dest = baseDest; 1260 if (dest == NULL) { 1261 doThrow(env, "java/lang/OutOfMemoryError"); 1262 return JNI_FALSE; 1263 } 1264 1265 // Now lock down the resource object and start pulling stuff from it. 1266 res.lock(); 1267 1268 const ResTable::bag_entry* arrayEnt = NULL; 1269 uint32_t arrayTypeSetFlags = 0; 1270 ssize_t bagOff = res.getBagLocked(id, &arrayEnt, &arrayTypeSetFlags); 1271 const ResTable::bag_entry* endArrayEnt = arrayEnt + 1272 (bagOff >= 0 ? bagOff : 0); 1273 1274 int i = 0; 1275 uint32_t typeSetFlags; 1276 while (i < NV && arrayEnt < endArrayEnt) { 1277 block = arrayEnt->stringBlock; 1278 typeSetFlags = arrayTypeSetFlags; 1279 value = arrayEnt->map.value; 1280 1281 uint32_t resid = 0; 1282 if (value.dataType != Res_value::TYPE_NULL) { 1283 // Take care of resolving the found resource to its final value. 1284 //printf("Resolving attribute reference\n"); 1285 ssize_t newBlock = res.resolveReference(&value, block, &resid, &typeSetFlags); 1286 if (newBlock >= 0) block = newBlock; 1287 } 1288 1289 // Deal with the special @null value -- it turns back to TYPE_NULL. 1290 if (value.dataType == Res_value::TYPE_REFERENCE && value.data == 0) { 1291 value.dataType = Res_value::TYPE_NULL; 1292 } 1293 1294 //printf("Attribute 0x%08x: final type=0x%x, data=0x%08x\n", curIdent, value.dataType, value.data); 1295 1296 // Write the final value back to Java. 1297 dest[STYLE_TYPE] = value.dataType; 1298 dest[STYLE_DATA] = value.data; 1299 dest[STYLE_ASSET_COOKIE] = (jint)res.getTableCookie(block); 1300 dest[STYLE_RESOURCE_ID] = resid; 1301 dest[STYLE_CHANGING_CONFIGURATIONS] = typeSetFlags; 1302 dest += STYLE_NUM_ENTRIES; 1303 i+= STYLE_NUM_ENTRIES; 1304 arrayEnt++; 1305 } 1306 1307 i /= STYLE_NUM_ENTRIES; 1308 1309 res.unlock(); 1310 1311 env->ReleasePrimitiveArrayCritical(outValues, baseDest, 0); 1312 1313 return i; 1314} 1315 1316static jint android_content_AssetManager_openXmlAssetNative(JNIEnv* env, jobject clazz, 1317 jint cookie, 1318 jstring fileName) 1319{ 1320 AssetManager* am = assetManagerForJavaObject(env, clazz); 1321 if (am == NULL) { 1322 return 0; 1323 } 1324 1325 LOGV("openXmlAsset in %p (Java object %p)\n", am, clazz); 1326 1327 if (fileName == NULL || am == NULL) { 1328 doThrow(env, "java/lang/NullPointerException"); 1329 return 0; 1330 } 1331 1332 const char* fileName8 = env->GetStringUTFChars(fileName, NULL); 1333 Asset* a = cookie 1334 ? am->openNonAsset((void*)cookie, fileName8, Asset::ACCESS_BUFFER) 1335 : am->openNonAsset(fileName8, Asset::ACCESS_BUFFER); 1336 1337 if (a == NULL) { 1338 doThrow(env, "java/io/FileNotFoundException", fileName8); 1339 env->ReleaseStringUTFChars(fileName, fileName8); 1340 return 0; 1341 } 1342 env->ReleaseStringUTFChars(fileName, fileName8); 1343 1344 ResXMLTree* block = new ResXMLTree(); 1345 status_t err = block->setTo(a->getBuffer(true), a->getLength(), true); 1346 a->close(); 1347 delete a; 1348 1349 if (err != NO_ERROR) { 1350 doThrow(env, "java/io/FileNotFoundException", "Corrupt XML binary file"); 1351 return 0; 1352 } 1353 1354 return (jint)block; 1355} 1356 1357static jintArray android_content_AssetManager_getArrayStringInfo(JNIEnv* env, jobject clazz, 1358 jint arrayResId) 1359{ 1360 AssetManager* am = assetManagerForJavaObject(env, clazz); 1361 if (am == NULL) { 1362 return NULL; 1363 } 1364 const ResTable& res(am->getResources()); 1365 1366 const ResTable::bag_entry* startOfBag; 1367 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1368 if (N < 0) { 1369 return NULL; 1370 } 1371 1372 jintArray array = env->NewIntArray(N * 2); 1373 if (array == NULL) { 1374 doThrow(env, "java/lang/OutOfMemoryError"); 1375 res.unlockBag(startOfBag); 1376 return NULL; 1377 } 1378 1379 Res_value value; 1380 const ResTable::bag_entry* bag = startOfBag; 1381 for (size_t i = 0, j = 0; ((ssize_t)i)<N; i++, bag++) { 1382 jint stringIndex = -1; 1383 jint stringBlock = 0; 1384 value = bag->map.value; 1385 1386 // Take care of resolving the found resource to its final value. 1387 stringBlock = res.resolveReference(&value, bag->stringBlock, NULL); 1388 if (value.dataType == Res_value::TYPE_STRING) { 1389 stringIndex = value.data; 1390 } 1391 1392 //todo: It might be faster to allocate a C array to contain 1393 // the blocknums and indices, put them in there and then 1394 // do just one SetIntArrayRegion() 1395 env->SetIntArrayRegion(array, j, 1, &stringBlock); 1396 env->SetIntArrayRegion(array, j + 1, 1, &stringIndex); 1397 j = j + 2; 1398 } 1399 res.unlockBag(startOfBag); 1400 return array; 1401} 1402 1403static jobjectArray android_content_AssetManager_getArrayStringResource(JNIEnv* env, jobject clazz, 1404 jint arrayResId) 1405{ 1406 AssetManager* am = assetManagerForJavaObject(env, clazz); 1407 if (am == NULL) { 1408 return NULL; 1409 } 1410 const ResTable& res(am->getResources()); 1411 1412 jclass cls = env->FindClass("java/lang/String"); 1413 LOG_FATAL_IF(cls == NULL, "No string class?!?"); 1414 if (cls == NULL) { 1415 return NULL; 1416 } 1417 1418 const ResTable::bag_entry* startOfBag; 1419 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1420 if (N < 0) { 1421 return NULL; 1422 } 1423 1424 jobjectArray array = env->NewObjectArray(N, cls, NULL); 1425 if (array == NULL) { 1426 doThrow(env, "java/lang/OutOfMemoryError"); 1427 res.unlockBag(startOfBag); 1428 return NULL; 1429 } 1430 1431 Res_value value; 1432 const ResTable::bag_entry* bag = startOfBag; 1433 size_t strLen = 0; 1434 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1435 value = bag->map.value; 1436 jstring str = NULL; 1437 1438 // Take care of resolving the found resource to its final value. 1439 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); 1440 if (value.dataType == Res_value::TYPE_STRING) { 1441 const char16_t* str16 = res.getTableStringBlock(block)->stringAt(value.data, &strLen); 1442 str = env->NewString(str16, strLen); 1443 if (str == NULL) { 1444 doThrow(env, "java/lang/OutOfMemoryError"); 1445 res.unlockBag(startOfBag); 1446 return NULL; 1447 } 1448 } 1449 1450 env->SetObjectArrayElement(array, i, str); 1451 } 1452 res.unlockBag(startOfBag); 1453 return array; 1454} 1455 1456static jintArray android_content_AssetManager_getArrayIntResource(JNIEnv* env, jobject clazz, 1457 jint arrayResId) 1458{ 1459 AssetManager* am = assetManagerForJavaObject(env, clazz); 1460 if (am == NULL) { 1461 return NULL; 1462 } 1463 const ResTable& res(am->getResources()); 1464 1465 const ResTable::bag_entry* startOfBag; 1466 const ssize_t N = res.lockBag(arrayResId, &startOfBag); 1467 if (N < 0) { 1468 return NULL; 1469 } 1470 1471 jintArray array = env->NewIntArray(N); 1472 if (array == NULL) { 1473 doThrow(env, "java/lang/OutOfMemoryError"); 1474 res.unlockBag(startOfBag); 1475 return NULL; 1476 } 1477 1478 Res_value value; 1479 const ResTable::bag_entry* bag = startOfBag; 1480 for (size_t i=0; ((ssize_t)i)<N; i++, bag++) { 1481 value = bag->map.value; 1482 1483 // Take care of resolving the found resource to its final value. 1484 ssize_t block = res.resolveReference(&value, bag->stringBlock, NULL); 1485 if (value.dataType >= Res_value::TYPE_FIRST_INT 1486 && value.dataType <= Res_value::TYPE_LAST_INT) { 1487 int intVal = value.data; 1488 env->SetIntArrayRegion(array, i, 1, &intVal); 1489 } 1490 } 1491 res.unlockBag(startOfBag); 1492 return array; 1493} 1494 1495static void android_content_AssetManager_init(JNIEnv* env, jobject clazz) 1496{ 1497 AssetManager* am = new AssetManager(); 1498 if (am == NULL) { 1499 doThrow(env, "java/lang/OutOfMemoryError"); 1500 return; 1501 } 1502 1503 am->addDefaultAssets(); 1504 1505 LOGV("Created AssetManager %p for Java object %p\n", am, clazz); 1506 env->SetIntField(clazz, gAssetManagerOffsets.mObject, (jint)am); 1507} 1508 1509static void android_content_AssetManager_destroy(JNIEnv* env, jobject clazz) 1510{ 1511 AssetManager* am = (AssetManager*) 1512 (env->GetIntField(clazz, gAssetManagerOffsets.mObject)); 1513 LOGV("Destroying AssetManager %p for Java object %p\n", am, clazz); 1514 if (am != NULL) { 1515 delete am; 1516 env->SetIntField(clazz, gAssetManagerOffsets.mObject, 0); 1517 } 1518} 1519 1520static jint android_content_AssetManager_getGlobalAssetCount(JNIEnv* env, jobject clazz) 1521{ 1522 return Asset::getGlobalCount(); 1523} 1524 1525static jint android_content_AssetManager_getGlobalAssetManagerCount(JNIEnv* env, jobject clazz) 1526{ 1527 return AssetManager::getGlobalCount(); 1528} 1529 1530// ---------------------------------------------------------------------------- 1531 1532/* 1533 * JNI registration. 1534 */ 1535static JNINativeMethod gAssetManagerMethods[] = { 1536 /* name, signature, funcPtr */ 1537 1538 // Basic asset stuff. 1539 { "openAsset", "(Ljava/lang/String;I)I", 1540 (void*) android_content_AssetManager_openAsset }, 1541 { "openAssetFd", "(Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1542 (void*) android_content_AssetManager_openAssetFd }, 1543 { "openNonAssetNative", "(ILjava/lang/String;I)I", 1544 (void*) android_content_AssetManager_openNonAssetNative }, 1545 { "openNonAssetFdNative", "(ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;", 1546 (void*) android_content_AssetManager_openNonAssetFdNative }, 1547 { "list", "(Ljava/lang/String;)[Ljava/lang/String;", 1548 (void*) android_content_AssetManager_list }, 1549 { "destroyAsset", "(I)V", 1550 (void*) android_content_AssetManager_destroyAsset }, 1551 { "readAssetChar", "(I)I", 1552 (void*) android_content_AssetManager_readAssetChar }, 1553 { "readAsset", "(I[BII)I", 1554 (void*) android_content_AssetManager_readAsset }, 1555 { "seekAsset", "(IJI)J", 1556 (void*) android_content_AssetManager_seekAsset }, 1557 { "getAssetLength", "(I)J", 1558 (void*) android_content_AssetManager_getAssetLength }, 1559 { "getAssetRemainingLength", "(I)J", 1560 (void*) android_content_AssetManager_getAssetRemainingLength }, 1561 { "addAssetPath", "(Ljava/lang/String;)I", 1562 (void*) android_content_AssetManager_addAssetPath }, 1563 { "isUpToDate", "()Z", 1564 (void*) android_content_AssetManager_isUpToDate }, 1565 1566 // Resources. 1567 { "setLocale", "(Ljava/lang/String;)V", 1568 (void*) android_content_AssetManager_setLocale }, 1569 { "getLocales", "()[Ljava/lang/String;", 1570 (void*) android_content_AssetManager_getLocales }, 1571 { "setConfiguration", "(IILjava/lang/String;IIIIIIIIII)V", 1572 (void*) android_content_AssetManager_setConfiguration }, 1573 { "getResourceIdentifier","(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", 1574 (void*) android_content_AssetManager_getResourceIdentifier }, 1575 { "getResourceName","(I)Ljava/lang/String;", 1576 (void*) android_content_AssetManager_getResourceName }, 1577 { "getResourcePackageName","(I)Ljava/lang/String;", 1578 (void*) android_content_AssetManager_getResourcePackageName }, 1579 { "getResourceTypeName","(I)Ljava/lang/String;", 1580 (void*) android_content_AssetManager_getResourceTypeName }, 1581 { "getResourceEntryName","(I)Ljava/lang/String;", 1582 (void*) android_content_AssetManager_getResourceEntryName }, 1583 { "loadResourceValue","(ILandroid/util/TypedValue;Z)I", 1584 (void*) android_content_AssetManager_loadResourceValue }, 1585 { "loadResourceBagValue","(IILandroid/util/TypedValue;Z)I", 1586 (void*) android_content_AssetManager_loadResourceBagValue }, 1587 { "getStringBlockCount","()I", 1588 (void*) android_content_AssetManager_getStringBlockCount }, 1589 { "getNativeStringBlock","(I)I", 1590 (void*) android_content_AssetManager_getNativeStringBlock }, 1591 { "getCookieName","(I)Ljava/lang/String;", 1592 (void*) android_content_AssetManager_getCookieName }, 1593 1594 // Themes. 1595 { "newTheme", "()I", 1596 (void*) android_content_AssetManager_newTheme }, 1597 { "deleteTheme", "(I)V", 1598 (void*) android_content_AssetManager_deleteTheme }, 1599 { "applyThemeStyle", "(IIZ)V", 1600 (void*) android_content_AssetManager_applyThemeStyle }, 1601 { "copyTheme", "(II)V", 1602 (void*) android_content_AssetManager_copyTheme }, 1603 { "loadThemeAttributeValue", "(IILandroid/util/TypedValue;Z)I", 1604 (void*) android_content_AssetManager_loadThemeAttributeValue }, 1605 { "dumpTheme", "(IILjava/lang/String;Ljava/lang/String;)V", 1606 (void*) android_content_AssetManager_dumpTheme }, 1607 { "applyStyle","(IIII[I[I[I)Z", 1608 (void*) android_content_AssetManager_applyStyle }, 1609 { "retrieveAttributes","(I[I[I[I)Z", 1610 (void*) android_content_AssetManager_retrieveAttributes }, 1611 { "getArraySize","(I)I", 1612 (void*) android_content_AssetManager_getArraySize }, 1613 { "retrieveArray","(I[I)I", 1614 (void*) android_content_AssetManager_retrieveArray }, 1615 1616 // XML files. 1617 { "openXmlAssetNative", "(ILjava/lang/String;)I", 1618 (void*) android_content_AssetManager_openXmlAssetNative }, 1619 1620 // Arrays. 1621 { "getArrayStringResource","(I)[Ljava/lang/String;", 1622 (void*) android_content_AssetManager_getArrayStringResource }, 1623 { "getArrayStringInfo","(I)[I", 1624 (void*) android_content_AssetManager_getArrayStringInfo }, 1625 { "getArrayIntResource","(I)[I", 1626 (void*) android_content_AssetManager_getArrayIntResource }, 1627 1628 // Bookkeeping. 1629 { "init", "()V", 1630 (void*) android_content_AssetManager_init }, 1631 { "destroy", "()V", 1632 (void*) android_content_AssetManager_destroy }, 1633 { "getGlobalAssetCount", "()I", 1634 (void*) android_content_AssetManager_getGlobalAssetCount }, 1635 { "getGlobalAssetManagerCount", "()I", 1636 (void*) android_content_AssetManager_getGlobalAssetCount }, 1637}; 1638 1639int register_android_content_AssetManager(JNIEnv* env) 1640{ 1641 jclass typedValue = env->FindClass("android/util/TypedValue"); 1642 LOG_FATAL_IF(typedValue == NULL, "Unable to find class android/util/TypedValue"); 1643 gTypedValueOffsets.mType 1644 = env->GetFieldID(typedValue, "type", "I"); 1645 LOG_FATAL_IF(gTypedValueOffsets.mType == NULL, "Unable to find TypedValue.type"); 1646 gTypedValueOffsets.mData 1647 = env->GetFieldID(typedValue, "data", "I"); 1648 LOG_FATAL_IF(gTypedValueOffsets.mData == NULL, "Unable to find TypedValue.data"); 1649 gTypedValueOffsets.mString 1650 = env->GetFieldID(typedValue, "string", "Ljava/lang/CharSequence;"); 1651 LOG_FATAL_IF(gTypedValueOffsets.mString == NULL, "Unable to find TypedValue.string"); 1652 gTypedValueOffsets.mAssetCookie 1653 = env->GetFieldID(typedValue, "assetCookie", "I"); 1654 LOG_FATAL_IF(gTypedValueOffsets.mAssetCookie == NULL, "Unable to find TypedValue.assetCookie"); 1655 gTypedValueOffsets.mResourceId 1656 = env->GetFieldID(typedValue, "resourceId", "I"); 1657 LOG_FATAL_IF(gTypedValueOffsets.mResourceId == NULL, "Unable to find TypedValue.resourceId"); 1658 gTypedValueOffsets.mChangingConfigurations 1659 = env->GetFieldID(typedValue, "changingConfigurations", "I"); 1660 LOG_FATAL_IF(gTypedValueOffsets.mChangingConfigurations == NULL, "Unable to find TypedValue.changingConfigurations"); 1661 gTypedValueOffsets.mDensity = env->GetFieldID(typedValue, "density", "I"); 1662 LOG_FATAL_IF(gTypedValueOffsets.mDensity == NULL, "Unable to find TypedValue.density"); 1663 1664 jclass assetFd = env->FindClass("android/content/res/AssetFileDescriptor"); 1665 LOG_FATAL_IF(assetFd == NULL, "Unable to find class android/content/res/AssetFileDescriptor"); 1666 gAssetFileDescriptorOffsets.mFd 1667 = env->GetFieldID(assetFd, "mFd", "Landroid/os/ParcelFileDescriptor;"); 1668 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mFd == NULL, "Unable to find AssetFileDescriptor.mFd"); 1669 gAssetFileDescriptorOffsets.mStartOffset 1670 = env->GetFieldID(assetFd, "mStartOffset", "J"); 1671 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mStartOffset == NULL, "Unable to find AssetFileDescriptor.mStartOffset"); 1672 gAssetFileDescriptorOffsets.mLength 1673 = env->GetFieldID(assetFd, "mLength", "J"); 1674 LOG_FATAL_IF(gAssetFileDescriptorOffsets.mLength == NULL, "Unable to find AssetFileDescriptor.mLength"); 1675 1676 jclass assetManager = env->FindClass("android/content/res/AssetManager"); 1677 LOG_FATAL_IF(assetManager == NULL, "Unable to find class android/content/res/AssetManager"); 1678 gAssetManagerOffsets.mObject 1679 = env->GetFieldID(assetManager, "mObject", "I"); 1680 LOG_FATAL_IF(gAssetManagerOffsets.mObject == NULL, "Unable to find AssetManager.mObject"); 1681 1682 g_stringClass = env->FindClass("java/lang/String"); 1683 1684 return AndroidRuntime::registerNativeMethods(env, 1685 "android/content/res/AssetManager", gAssetManagerMethods, NELEM(gAssetManagerMethods)); 1686} 1687 1688}; // namespace android 1689