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