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