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