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