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