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