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