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