You've already forked android_translation_layer
mirror of
https://gitlab.com/android_translation_layer/android_translation_layer.git
synced 2025-10-27 11:48:10 -07:00
AssetManager: use libandroidfw to read assets straight from the apk file
they can still be put on the filesystem and will be read from there preferentially, though overriding assets in this way can confuse some creatively written apps and cause them to crash.
This commit is contained in:
@@ -63,6 +63,9 @@ libandroid_so = shared_library('android', [
|
|||||||
soversion: 0,
|
soversion: 0,
|
||||||
dependencies: [
|
dependencies: [
|
||||||
dependency('gtk4'), dependency('jni'), dependency('vulkan'), dependency('openxr').partial_dependency(includes: true)
|
dependency('gtk4'), dependency('jni'), dependency('vulkan'), dependency('openxr').partial_dependency(includes: true)
|
||||||
|
],
|
||||||
|
c_args: [
|
||||||
|
'-D_LARGEFILE64_SOURCE',
|
||||||
])
|
])
|
||||||
|
|
||||||
libtranslationlayer_so = shared_library('translation_layer_main', [
|
libtranslationlayer_so = shared_library('translation_layer_main', [
|
||||||
@@ -142,6 +145,9 @@ libtranslationlayer_so = shared_library('translation_layer_main', [
|
|||||||
link_with: [ libandroid_so ],
|
link_with: [ libandroid_so ],
|
||||||
link_args: [
|
link_args: [
|
||||||
'-lasound'
|
'-lasound'
|
||||||
|
],
|
||||||
|
c_args: [
|
||||||
|
'-D_LARGEFILE64_SOURCE',
|
||||||
])
|
])
|
||||||
|
|
||||||
executable('android-translation-layer', [
|
executable('android-translation-layer', [
|
||||||
|
|||||||
@@ -138,9 +138,10 @@ struct NativeCode * NativeCode_new(void* _dlhandle, ANativeActivity_createFunc*
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: this is currently in libandroid.so, which is not necessarily requested by the app and therefore loaded
|
// FIXME: this is in libandroid.so, should use header files
|
||||||
ANativeWindow * ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
|
ANativeWindow * ANativeWindow_fromSurface(JNIEnv* env, jobject surface);
|
||||||
void ANativeWindow_release(ANativeWindow *native_window);
|
void ANativeWindow_release(ANativeWindow *native_window);
|
||||||
|
struct AssetManager * AAssetManager_fromJava(JNIEnv *env, jobject asset_manager);
|
||||||
|
|
||||||
void NativeCode_setSurface(struct NativeCode *this, jobject _surface)
|
void NativeCode_setSurface(struct NativeCode *this, jobject _surface)
|
||||||
{
|
{
|
||||||
@@ -334,7 +335,7 @@ jlong Java_android_app_NativeActivity_loadNativeCode(JNIEnv* env, jobject clazz,
|
|||||||
|
|
||||||
code->native_activity.sdkVersion = sdkVersion;
|
code->native_activity.sdkVersion = sdkVersion;
|
||||||
|
|
||||||
code->native_activity.assetManager = NULL;//assetManagerForJavaObject(env, jAssetMgr);
|
code->native_activity.assetManager = AAssetManager_fromJava(env, jAssetMgr);
|
||||||
|
|
||||||
if (obbDir != NULL) {
|
if (obbDir != NULL) {
|
||||||
code->native_activity.obbPath = (*env)->GetStringUTFChars(env, obbDir, NULL);
|
code->native_activity.obbPath = (*env)->GetStringUTFChars(env, obbDir, NULL);
|
||||||
|
|||||||
@@ -18,100 +18,81 @@
|
|||||||
#define ASSET_DIR "assets/"
|
#define ASSET_DIR "assets/"
|
||||||
char *get_app_data_dir();
|
char *get_app_data_dir();
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_openAsset(JNIEnv *env, jobject this, jstring _file_name, jint mode)
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_openAsset(JNIEnv *env, jobject this, jstring _file_name, jint mode)
|
||||||
{
|
{
|
||||||
const char *file_name = _CSTRING(_file_name);
|
const char *file_name = _CSTRING(_file_name);
|
||||||
|
|
||||||
/* handle absolute paths */
|
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
|
||||||
if(file_name[0] == '/')
|
struct Asset *asset = AssetManager_openNonAsset(asset_manager, file_name, mode);
|
||||||
return open(file_name, O_CLOEXEC | O_RDWR);
|
printf("AssetManager_openAsset(%p, %s, %d)\n", asset_manager, file_name, mode);
|
||||||
|
|
||||||
char *app_data_dir = get_app_data_dir();
|
return _INTPTR(asset);
|
||||||
char *path = malloc(strlen(app_data_dir) + strlen(ASSET_DIR) + strlen(file_name) + 1);
|
}
|
||||||
|
|
||||||
|
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_openAssetFd(JNIEnv *env, jobject this, jstring _file_name, jint mode, jlongArray _offset, jlongArray _size)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
off_t offset;
|
||||||
|
off_t size;
|
||||||
|
|
||||||
strcpy(path, app_data_dir);
|
const char *file_name = _CSTRING(_file_name);
|
||||||
strcat(path, ASSET_DIR);
|
|
||||||
strcat(path, file_name);
|
|
||||||
|
|
||||||
printf("openning asset with filename: %s\n", _CSTRING(_file_name));
|
struct AssetManager *asset_manager = _PTR(_GET_LONG_FIELD(this, "mObject"));
|
||||||
|
struct Asset *asset = AssetManager_openNonAsset(asset_manager, file_name, mode);
|
||||||
|
printf("AssetManager_openAssetFd(%p, %s, %d, ...)\n", asset_manager, file_name, mode);
|
||||||
|
|
||||||
printf("openning asset at path: %s\n", path);
|
fd = Asset_openFileDescriptor(asset, &offset, &size);
|
||||||
|
|
||||||
fd = open(path, O_CLOEXEC | O_RDWR);
|
(*env)->SetLongArrayRegion(env, _offset, 0, 1, (jlong[]){offset});
|
||||||
|
(*env)->SetLongArrayRegion(env, _size, 0, 1, (jlong[]){size});
|
||||||
free(path);
|
|
||||||
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetLength(JNIEnv *env, jobject this, jint fd)
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetLength(JNIEnv *env, jobject this, jlong _asset)
|
||||||
{
|
{
|
||||||
int ret;
|
struct Asset *asset = _PTR(_asset);
|
||||||
struct stat statbuf;
|
return Asset_getLength(asset);
|
||||||
|
|
||||||
ret = fstat(fd, &statbuf);
|
|
||||||
if(ret)
|
|
||||||
printf("oopsie, fstat failed on fd: %d with errno: %d\n", fd, errno);
|
|
||||||
|
|
||||||
return statbuf.st_size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetRemainingLength(JNIEnv *env, jobject this, jint fd)
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetRemainingLength(JNIEnv *env, jobject this, jlong _asset)
|
||||||
{
|
{
|
||||||
jlong file_size = Java_android_content_res_AssetManager_getAssetLength(env, this, fd);
|
struct Asset *asset = _PTR(_asset);
|
||||||
off_t offset = lseek(fd, 0, SEEK_CUR);
|
return Asset_getRemainingLength(asset);
|
||||||
|
|
||||||
return file_size - offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAsset(JNIEnv *env, jobject this, jint fd, jbyteArray b, jint off, jint len)
|
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAsset(JNIEnv *env, jobject this, jlong _asset, jbyteArray b, jlong offset, jlong length)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int err;
|
|
||||||
|
|
||||||
|
struct Asset *asset = _PTR(_asset);
|
||||||
jbyte *array = _GET_BYTE_ARRAY_ELEMENTS(b);
|
jbyte *array = _GET_BYTE_ARRAY_ELEMENTS(b);
|
||||||
ret = read(fd, &array[off], len);
|
ret = Asset_read(asset, &array[offset], length);
|
||||||
_RELEASE_BYTE_ARRAY_ELEMENTS(b, array);
|
_RELEASE_BYTE_ARRAY_ELEMENTS(b, array);
|
||||||
|
|
||||||
if(ret < 0) {
|
return ret;
|
||||||
err = errno;
|
|
||||||
printf("oopsie, read failed on fd: %d with errno: %d\n", fd, err);
|
|
||||||
exit(err);
|
|
||||||
} else if (ret == 0) { //EOF
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAssetChar(JNIEnv *env, jobject this, jint fd)
|
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAssetChar(JNIEnv *env, jobject this, jlong _asset)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
int err;
|
uint8_t byte;
|
||||||
unsigned char byte;
|
|
||||||
|
|
||||||
ret = read(fd, &byte, 1);
|
struct Asset *asset = _PTR(_asset);
|
||||||
if(ret == 1)
|
ret = Asset_read(asset, &byte, 1);
|
||||||
return byte;
|
return (ret == 1) ? byte : ret;
|
||||||
else if(ret == 0)
|
|
||||||
return -1;
|
|
||||||
else {
|
|
||||||
err = errno;
|
|
||||||
printf("oopsie, read failed on fd: %d with errno: %d\n", fd, err);
|
|
||||||
exit(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_seekAsset(JNIEnv *env, jobject this, jint fd, jlong off, jint whence)
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_seekAsset(JNIEnv *env, jobject this, jlong _asset, jlong offset, jint whence)
|
||||||
{
|
{
|
||||||
return lseek(fd, off, (whence > 0) ? SEEK_END : (whence < 0 ? SEEK_SET : SEEK_CUR));
|
struct Asset *asset = _PTR(_asset);
|
||||||
|
return Asset_seek(asset, offset, whence);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_destroyAsset(JNIEnv *env, jobject this, jint fd)
|
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_destroyAsset(JNIEnv *env, jobject this, jlong _asset)
|
||||||
{
|
{
|
||||||
printf("closing asset with fd: %d\n", fd);
|
struct Asset *asset = _PTR(_asset);
|
||||||
close(fd);
|
Asset_delete(asset);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init(JNIEnv *env, jobject this)
|
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init(JNIEnv *env, jobject this)
|
||||||
|
|||||||
@@ -124,74 +124,66 @@ JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceEntry
|
|||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: openAsset
|
* Method: openAsset
|
||||||
* Signature: (Ljava/lang/String;I)I
|
* Signature: (Ljava/lang/String;I)J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_openAsset
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_openAsset
|
||||||
(JNIEnv *, jobject, jstring, jint);
|
(JNIEnv *, jobject, jstring, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: openAssetFd
|
* Method: openAssetFd
|
||||||
* Signature: (Ljava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
|
* Signature: (Ljava/lang/String;I[J[J)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jobject JNICALL Java_android_content_res_AssetManager_openAssetFd
|
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_openAssetFd
|
||||||
(JNIEnv *, jobject, jstring, jlongArray);
|
(JNIEnv *, jobject, jstring, jint, jlongArray, jlongArray);
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: android_content_res_AssetManager
|
|
||||||
* Method: openNonAssetFdNative
|
|
||||||
* Signature: (ILjava/lang/String;[J)Landroid/os/ParcelFileDescriptor;
|
|
||||||
*/
|
|
||||||
JNIEXPORT jobject JNICALL Java_android_content_res_AssetManager_openNonAssetFdNative
|
|
||||||
(JNIEnv *, jobject, jint, jstring, jlongArray);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: destroyAsset
|
* Method: destroyAsset
|
||||||
* Signature: (I)V
|
* Signature: (J)V
|
||||||
*/
|
*/
|
||||||
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_destroyAsset
|
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_destroyAsset
|
||||||
(JNIEnv *, jobject, jint);
|
(JNIEnv *, jobject, jlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: readAssetChar
|
* Method: readAssetChar
|
||||||
* Signature: (I)I
|
* Signature: (J)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAssetChar
|
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAssetChar
|
||||||
(JNIEnv *, jobject, jint);
|
(JNIEnv *, jobject, jlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: readAsset
|
* Method: readAsset
|
||||||
* Signature: (I[BII)I
|
* Signature: (J[BJJ)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAsset
|
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_readAsset
|
||||||
(JNIEnv *, jobject, jint, jbyteArray, jint, jint);
|
(JNIEnv *, jobject, jlong, jbyteArray, jlong, jlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: seekAsset
|
* Method: seekAsset
|
||||||
* Signature: (IJI)J
|
* Signature: (JJI)J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_seekAsset
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_seekAsset
|
||||||
(JNIEnv *, jobject, jint, jlong, jint);
|
(JNIEnv *, jobject, jlong, jlong, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: getAssetLength
|
* Method: getAssetLength
|
||||||
* Signature: (I)J
|
* Signature: (J)J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetLength
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetLength
|
||||||
(JNIEnv *, jobject, jint);
|
(JNIEnv *, jobject, jlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
* Method: getAssetRemainingLength
|
* Method: getAssetRemainingLength
|
||||||
* Signature: (I)J
|
* Signature: (J)J
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetRemainingLength
|
JNIEXPORT jlong JNICALL Java_android_content_res_AssetManager_getAssetRemainingLength
|
||||||
(JNIEnv *, jobject, jint);
|
(JNIEnv *, jobject, jlong);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: android_content_res_AssetManager
|
* Class: android_content_res_AssetManager
|
||||||
@@ -361,14 +353,6 @@ JNIEXPORT jintArray JNICALL Java_android_content_res_AssetManager_getArrayString
|
|||||||
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init
|
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_init
|
||||||
(JNIEnv *, jobject);
|
(JNIEnv *, jobject);
|
||||||
|
|
||||||
/*
|
|
||||||
* Class: android_content_res_AssetManager
|
|
||||||
* Method: destroy
|
|
||||||
* Signature: ()V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_destroy
|
|
||||||
(JNIEnv *, jobject);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
package android.content.res;
|
package android.content.res;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Environment;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
@@ -127,6 +128,7 @@ public final class AssetManager {
|
|||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
Log.e(TAG, "failed to load resources.arsc" + e);
|
Log.e(TAG, "failed to load resources.arsc" + e);
|
||||||
}
|
}
|
||||||
|
addAssetPath(android.os.Environment.getExternalStorageDirectory().getAbsolutePath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -308,48 +310,12 @@ public final class AssetManager {
|
|||||||
* @see #list
|
* @see #list
|
||||||
*/
|
*/
|
||||||
public final InputStream open(String fileName, int accessMode) throws IOException {
|
public final InputStream open(String fileName, int accessMode) throws IOException {
|
||||||
int asset;
|
long asset = openAsset("assets/" + fileName, accessMode);
|
||||||
// try loading from filesystem
|
return new AssetInputStream(asset);
|
||||||
synchronized (this) {
|
|
||||||
if (!mOpen) {
|
|
||||||
throw new RuntimeException("Assetmanager has been closed");
|
|
||||||
}
|
|
||||||
asset = openAsset(fileName, accessMode);
|
|
||||||
if (asset >= 0) {
|
|
||||||
AssetInputStream res = new AssetInputStream(asset, "/assets/" + fileName);
|
|
||||||
incRefsLocked(res.hashCode());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// alternatively load directly from APK
|
|
||||||
InputStream ret = ClassLoader.getSystemClassLoader().getResourceAsStream("assets/" + fileName);
|
|
||||||
if(ret == null)
|
|
||||||
throw new FileNotFoundException("Asset file: " + fileName + ", errno: " + asset);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final AssetFileDescriptor openFd(String fileName)
|
public final AssetFileDescriptor openFd(String fileName) throws IOException {
|
||||||
throws IOException {
|
return openFd_internal("assets/" + fileName, 0);
|
||||||
int asset;
|
|
||||||
synchronized (this) {
|
|
||||||
if (!mOpen) {
|
|
||||||
throw new RuntimeException("Assetmanager has been closed");
|
|
||||||
}
|
|
||||||
asset = openAsset(fileName, 0);
|
|
||||||
if (asset < 0)
|
|
||||||
throw new FileNotFoundException("Asset file: " + fileName + ", errno: " + asset);
|
|
||||||
|
|
||||||
FileDescriptor fd = new FileDescriptor();
|
|
||||||
fd.setInt$(asset);
|
|
||||||
ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
|
|
||||||
if (pfd != null) {
|
|
||||||
AssetFileDescriptor afd = new AssetFileDescriptor(pfd, 0, getAssetLength(asset));
|
|
||||||
afd.fileName = "/assets/" + fileName;
|
|
||||||
return afd;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new FileNotFoundException("Asset file: " + fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -415,21 +381,8 @@ public final class AssetManager {
|
|||||||
* @param accessMode Desired access mode for retrieving the data.
|
* @param accessMode Desired access mode for retrieving the data.
|
||||||
*/
|
*/
|
||||||
public final InputStream openNonAsset(int cookie, String fileName, int accessMode) throws IOException {
|
public final InputStream openNonAsset(int cookie, String fileName, int accessMode) throws IOException {
|
||||||
int asset;
|
long asset = openAsset(fileName, accessMode);
|
||||||
// try loading from filesystem
|
return new AssetInputStream(asset);
|
||||||
synchronized (this) {
|
|
||||||
if (!mOpen) {
|
|
||||||
throw new RuntimeException("Assetmanager has been closed");
|
|
||||||
}
|
|
||||||
asset = openNonAssetNative(cookie, fileName, accessMode);
|
|
||||||
if (asset >= 0) {
|
|
||||||
AssetInputStream res = new AssetInputStream(asset, fileName);
|
|
||||||
incRefsLocked(res.hashCode());
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// alternatively load directly from APK
|
|
||||||
return ClassLoader.getSystemClassLoader().getResourceAsStream(fileName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public final AssetFileDescriptor openNonAssetFd(String fileName)
|
public final AssetFileDescriptor openNonAssetFd(String fileName)
|
||||||
@@ -439,17 +392,33 @@ public final class AssetManager {
|
|||||||
|
|
||||||
public final AssetFileDescriptor openNonAssetFd(int cookie,
|
public final AssetFileDescriptor openNonAssetFd(int cookie,
|
||||||
String fileName) throws IOException {
|
String fileName) throws IOException {
|
||||||
|
return openFd_internal(fileName, 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private final AssetFileDescriptor openFd_internal(String fileName, int accessMode)
|
||||||
|
throws IOException {
|
||||||
|
int asset;
|
||||||
synchronized (this) {
|
synchronized (this) {
|
||||||
if (!mOpen) {
|
if (!mOpen) {
|
||||||
throw new RuntimeException("Assetmanager has been closed");
|
throw new RuntimeException("Assetmanager has been closed");
|
||||||
}
|
}
|
||||||
ParcelFileDescriptor pfd = openNonAssetFdNative(cookie,
|
long[] offset = new long[1];
|
||||||
fileName, mOffsets);
|
long[] length = new long[1];
|
||||||
|
asset = openAssetFd(fileName, accessMode, offset, length);
|
||||||
|
if (asset < 0)
|
||||||
|
throw new FileNotFoundException("file: " + fileName + ", error: " + asset);
|
||||||
|
|
||||||
|
FileDescriptor fd = new FileDescriptor();
|
||||||
|
fd.setInt$(asset);
|
||||||
|
ParcelFileDescriptor pfd = new ParcelFileDescriptor(fd);
|
||||||
if (pfd != null) {
|
if (pfd != null) {
|
||||||
return new AssetFileDescriptor(pfd, mOffsets[0], mOffsets[1]);
|
AssetFileDescriptor afd = new AssetFileDescriptor(pfd, offset[0], length[0]);
|
||||||
|
afd.fileName = fileName;
|
||||||
|
return afd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new FileNotFoundException("Asset absolute file: " + fileName);
|
throw new FileNotFoundException("file: " + fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -553,13 +522,9 @@ public final class AssetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class AssetInputStream extends InputStream {
|
public final class AssetInputStream extends InputStream {
|
||||||
public final int getAssetInt() {
|
private AssetInputStream(long asset) {
|
||||||
return mAsset;
|
|
||||||
}
|
|
||||||
private AssetInputStream(int asset, String fileName) {
|
|
||||||
mAsset = asset;
|
mAsset = asset;
|
||||||
mLength = getAssetLength(asset);
|
mLength = getAssetLength(asset);
|
||||||
this.fileName = fileName;
|
|
||||||
}
|
}
|
||||||
public final int read() throws IOException {
|
public final int read() throws IOException {
|
||||||
return readAssetChar(mAsset);
|
return readAssetChar(mAsset);
|
||||||
@@ -607,10 +572,9 @@ public final class AssetManager {
|
|||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private int mAsset;
|
private long mAsset;
|
||||||
private long mLength;
|
private long mLength;
|
||||||
private long mMarkPos;
|
private long mMarkPos;
|
||||||
public String fileName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -720,20 +684,15 @@ public final class AssetManager {
|
|||||||
/*package*/ native final String getResourceTypeName(int resid);
|
/*package*/ native final String getResourceTypeName(int resid);
|
||||||
/*package*/ native final String getResourceEntryName(int resid);
|
/*package*/ native final String getResourceEntryName(int resid);
|
||||||
|
|
||||||
private native final int openAsset(String fileName, int accessMode);
|
private native final long openAsset(String fileName, int accessMode);
|
||||||
private final native ParcelFileDescriptor openAssetFd(String fileName,
|
private native final int openAssetFd(String fileName, int accessMode, long[] offset, long[] length);
|
||||||
long[] outOffsets) throws IOException;
|
|
||||||
private /*native*/ final int openNonAssetNative(int cookie, String fileName, int accessMode) {
|
private native final void destroyAsset(long asset);
|
||||||
return openAsset("../" + fileName, accessMode);
|
private native final int readAssetChar(long asset);
|
||||||
}
|
private native final int readAsset(long asset, byte[] b, long offset, long length);
|
||||||
private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
|
private native final long seekAsset(long asset, long offset, int whence);
|
||||||
String fileName, long[] outOffsets) throws IOException;
|
private native final long getAssetLength(long asset);
|
||||||
private native final void destroyAsset(int asset);
|
private native final long getAssetRemainingLength(long asset);
|
||||||
private native final int readAssetChar(int asset);
|
|
||||||
private native final int readAsset(int asset, byte[] b, int off, int len);
|
|
||||||
private native final long seekAsset(int asset, long offset, int whence);
|
|
||||||
private native final long getAssetLength(int asset);
|
|
||||||
private native final long getAssetRemainingLength(int asset);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the resource was found, filling in mRetStringBlock and
|
* Returns true if the resource was found, filling in mRetStringBlock and
|
||||||
@@ -894,7 +853,9 @@ public final class AssetManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private native final void init();
|
private native final void init();
|
||||||
private native final void destroy();
|
private /*native*/ final void destroy() {
|
||||||
|
System.out.println("AssetManager.destroy(): STUB");
|
||||||
|
}
|
||||||
|
|
||||||
private final void incRefsLocked(int id) {
|
private final void incRefsLocked(int id) {
|
||||||
if (DEBUG_REFS) {
|
if (DEBUG_REFS) {
|
||||||
|
|||||||
@@ -559,12 +559,7 @@ public class BitmapFactory {
|
|||||||
|
|
||||||
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
|
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
|
||||||
try {
|
try {
|
||||||
if (is instanceof AssetManager.AssetInputStream) {
|
bm = decodeStreamInternal(is, outPadding, opts);
|
||||||
final String fileName = ((AssetManager.AssetInputStream)is).fileName;
|
|
||||||
bm = new Bitmap(fileName);
|
|
||||||
} else {
|
|
||||||
bm = decodeStreamInternal(is, outPadding, opts);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bm == null && opts != null && opts.inBitmap != null) {
|
if (bm == null && opts != null && opts.inBitmap != null) {
|
||||||
throw new IllegalArgumentException("Problem decoding into existing bitmap");
|
throw new IllegalArgumentException("Problem decoding into existing bitmap");
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
#define _LARGEFILE64_SOURCE
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
@@ -7,208 +6,122 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
struct AAssetManager {
|
#include <androidfw/androidfw_c_api.h>
|
||||||
char dummy;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AAssetManager dummy_asset_manager;
|
#include "../api-impl-jni/defines.h"
|
||||||
|
#include "../api-impl-jni/util.h"
|
||||||
struct AAsset{
|
|
||||||
int fd;
|
|
||||||
off64_t read;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct AAssetDir {
|
struct AAssetDir {
|
||||||
DIR *dp;
|
struct AssetDir *asset_dir;
|
||||||
const char *dirname;
|
size_t curr_index;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef int64_t off64_t;
|
|
||||||
typedef void JNIEnv;
|
|
||||||
typedef void * jobject;
|
|
||||||
|
|
||||||
#define ASSET_DIR "assets/"
|
#define ASSET_DIR "assets/"
|
||||||
char *get_app_data_dir();
|
|
||||||
|
|
||||||
int AAsset_openFileDescriptor(struct AAsset *asset, off_t *out_start, off_t *out_length)
|
int AAsset_openFileDescriptor(struct Asset *asset, off_t *out_start, off_t *out_length)
|
||||||
{
|
{
|
||||||
int ret;
|
return Asset_openFileDescriptor(asset, out_start, out_length);
|
||||||
int fd = asset->fd;
|
|
||||||
|
|
||||||
printf("openning asset's file descriptor: : %d\n", fd);
|
|
||||||
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
ret = fstat(fd, &statbuf);
|
|
||||||
if(ret)
|
|
||||||
printf("oopsie, fstat failed on fd: %d with errno: %d\n", fd, errno);
|
|
||||||
|
|
||||||
*out_start = 0; // on android, we would be returning the fd of the app's apk, and this would be the offset to a non-compressed archive member
|
|
||||||
*out_length = statbuf.st_size; // similarly, this would be the size of the section of memory containing the non-compressed archive member
|
|
||||||
|
|
||||||
return fd;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AAsset* AAssetManager_open(struct AAssetManager *amgr, const char *file_name, int mode)
|
struct Asset* AAssetManager_open(struct AssetManager *asset_manager, const char *file_name, int mode)
|
||||||
{
|
{
|
||||||
char *app_data_dir = get_app_data_dir();
|
char *path = malloc(strlen(ASSET_DIR) + strlen(file_name) + 1);
|
||||||
char *path = malloc(strlen(app_data_dir) + strlen(ASSET_DIR) + strlen(file_name) + 1);
|
sprintf(path, "%s%s", ASSET_DIR, file_name);
|
||||||
int fd;
|
|
||||||
strcpy(path, app_data_dir);
|
|
||||||
strcat(path, ASSET_DIR);
|
|
||||||
strcat(path, file_name);
|
|
||||||
|
|
||||||
printf("openning asset with filename: %s\n", file_name);
|
printf("AAssetManager_open called for %s\n", file_name);
|
||||||
|
struct Asset *asset = AssetManager_openNonAsset(asset_manager, path, mode);
|
||||||
printf("openning asset at path: %s\n", path);
|
|
||||||
|
|
||||||
fd = open(path, O_CLOEXEC | O_RDWR);
|
|
||||||
if(fd < 0) {
|
|
||||||
printf("oopsie, falied to open file: %s (errno: %d)\n", file_name, errno);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(path);
|
free(path);
|
||||||
|
|
||||||
struct AAsset* asset = malloc(sizeof(struct AAsset));
|
|
||||||
asset->fd = fd;
|
|
||||||
asset->read = 0;
|
|
||||||
|
|
||||||
return asset;
|
return asset;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct AAssetDir * AAssetManager_openDir(struct AAssetManager *amgr, const char *dirname)
|
const void * AAsset_getBuffer(struct Asset *asset)
|
||||||
{
|
{
|
||||||
char* app_data_dir = get_app_data_dir();
|
return Asset_getBuffer(asset, false);
|
||||||
char* dirpath = malloc(strlen(app_data_dir) + strlen(ASSET_DIR) + strlen(dirname) + 1);
|
}
|
||||||
|
|
||||||
|
off64_t AAsset_getLength64(struct Asset *asset)
|
||||||
|
{
|
||||||
|
return Asset_getLength(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t AAsset_getLength(struct Asset *asset)
|
||||||
|
{
|
||||||
|
return Asset_getLength(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AAsset_read(struct Asset *asset, void *buf, size_t count) {
|
||||||
|
return Asset_read(asset, buf, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t AAsset_seek(struct Asset *asset, off_t offset, int whence) {
|
||||||
|
return Asset_seek(asset, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
off64_t AAsset_seek64(struct Asset *asset, off64_t offset, int whence) {
|
||||||
|
return Asset_seek(asset, offset, whence);
|
||||||
|
}
|
||||||
|
|
||||||
|
off_t AAsset_getRemainingLength(struct Asset *asset)
|
||||||
|
{
|
||||||
|
return Asset_getRemainingLength(asset);
|
||||||
|
}
|
||||||
|
off64_t AAsset_getRemainingLength64(struct Asset *asset)
|
||||||
|
{
|
||||||
|
return Asset_getRemainingLength(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AAsset_close(struct Asset *asset)
|
||||||
|
{
|
||||||
|
Asset_delete(asset);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AAssetDir * AAssetManager_openDir(struct AssetManager *asset_manager, const char *dirname)
|
||||||
|
{
|
||||||
|
char* dirpath = malloc(strlen(ASSET_DIR) + strlen(dirname) + 1);
|
||||||
|
sprintf(dirpath, "%s%s", ASSET_DIR, dirname);
|
||||||
|
|
||||||
|
struct AssetDir *asset_dir = AssetManager_openDir(asset_manager, dirname);
|
||||||
|
|
||||||
struct AAssetDir* dir = malloc(sizeof(struct AAssetDir));
|
struct AAssetDir* dir = malloc(sizeof(struct AAssetDir));
|
||||||
dir->dirname = dirname;
|
dir->asset_dir = asset_dir;
|
||||||
|
dir->curr_index = 0;
|
||||||
|
|
||||||
strcpy(dirpath, app_data_dir);
|
printf("AAssetManager_openDir called for %s\n", dirpath);
|
||||||
strcat(dirpath, ASSET_DIR);
|
|
||||||
strcat(dirpath, dirname);
|
|
||||||
printf("open directory path %s\n", dirpath);
|
|
||||||
|
|
||||||
dir->dp = opendir(dirpath);
|
|
||||||
if (dir->dp < 0)
|
|
||||||
{
|
|
||||||
printf("failed to open directory %s: %d\n", dirpath, errno);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return dir;
|
return dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char * AAssetDir_getNextFileName(struct AAssetDir *dir)
|
const char * AAssetDir_getNextFileName(struct AAssetDir *dir)
|
||||||
{
|
{
|
||||||
struct dirent *ep = readdir(dir->dp);
|
size_t index = dir->curr_index;
|
||||||
if (ep == NULL)
|
const size_t max = AssetDir_getFileCount(dir->asset_dir);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (!strcmp(ep->d_name, ".") || !strcmp(ep->d_name, "..")) {
|
/* skip non-regular files */
|
||||||
return AAssetDir_getNextFileName(dir);
|
while ((index < max) && AssetDir_getFileType(dir->asset_dir, index) != FILE_TYPE_REGULAR)
|
||||||
|
index++;
|
||||||
|
|
||||||
|
if (index >= max) {
|
||||||
|
dir->curr_index = index;
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// google claims to return full path, but it really doesn't seem so
|
dir->curr_index = index + 1;
|
||||||
return ep->d_name;
|
return AssetDir_getFileName(dir->asset_dir, index);
|
||||||
/* char *asset_root_path = malloc(strlen(dir->dirname) + 1 + strlen(ep->d_name) + 1);
|
|
||||||
|
|
||||||
sprintf(asset_root_path, "%s/%s", dir->dirname, ep->d_name);
|
|
||||||
printf("AAssetDir_getNextFileName: returning >%s<\n", asset_root_path);
|
|
||||||
|
|
||||||
return asset_root_path;*/
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AAssetDir_close(struct AAssetDir *dir)
|
void AAssetDir_close(struct AAssetDir *dir)
|
||||||
{
|
{
|
||||||
closedir(dir->dp);
|
AssetDir_delete(dir->asset_dir);
|
||||||
free(dir);
|
free(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
const void * AAsset_getBuffer(struct AAsset *asset)
|
struct AssetManager * AAssetManager_fromJava(JNIEnv *env, jobject asset_manager)
|
||||||
{
|
{
|
||||||
int ret;
|
return _PTR(_GET_LONG_FIELD(asset_manager, "mObject"));
|
||||||
int err;
|
|
||||||
int fd = asset->fd;
|
|
||||||
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
ret = fstat(fd, &statbuf);
|
|
||||||
if(ret)
|
|
||||||
printf("oopsie, fstat failed on fd: %d with errno: %d\n", fd, errno);
|
|
||||||
|
|
||||||
uint8_t *buffer = malloc(statbuf.st_size);
|
|
||||||
ret = pread(fd, buffer, statbuf.st_size, 0);
|
|
||||||
if(ret < 0) {
|
|
||||||
err = errno;
|
|
||||||
printf("oopsie, read failed on fd: %d with errno: %d\n", fd, err);
|
|
||||||
exit(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
off64_t AAsset_getLength64(struct AAsset *asset)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
int fd = asset->fd;
|
|
||||||
|
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
ret = fstat(fd, &statbuf);
|
|
||||||
if(ret)
|
|
||||||
printf("oopsie, fstat failed on fd: %d with errno: %d\n", fd, errno);
|
|
||||||
|
|
||||||
return statbuf.st_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t AAsset_getLength(struct AAsset *asset)
|
|
||||||
{
|
|
||||||
return AAsset_getLength64(asset);
|
|
||||||
}
|
|
||||||
struct AAssetManager * AAssetManager_fromJava(JNIEnv *env, jobject assetManager)
|
|
||||||
{
|
|
||||||
// some apps don't like if we return NULL here
|
|
||||||
return &dummy_asset_manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AAsset_read(struct AAsset *asset, void *buf, size_t count) {
|
|
||||||
off64_t tmp = read(asset->fd, buf, count);
|
|
||||||
asset->read += tmp;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t AAsset_seek(struct AAsset *asset, off_t offset, int whence) {
|
|
||||||
off64_t tmp = lseek(asset->fd, offset, whence);
|
|
||||||
asset->read += tmp;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
off64_t AAsset_seek64(struct AAsset *asset, off64_t offset, int whence) {
|
|
||||||
off64_t tmp = lseek64(asset->fd, offset, whence);
|
|
||||||
asset->read += tmp;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
off_t AAsset_getRemainingLength(struct AAsset* asset)
|
|
||||||
{
|
|
||||||
return AAsset_getLength(asset) - asset->read;
|
|
||||||
}
|
|
||||||
off64_t AAsset_getRemainingLength64(struct AAsset* asset)
|
|
||||||
{
|
|
||||||
return AAsset_getLength64(asset) - asset->read;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AAsset_close(struct AAsset *asset)
|
|
||||||
{
|
|
||||||
int fd = asset->fd;
|
|
||||||
|
|
||||||
printf("closing asset with fd: %d\n", fd);
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
free(asset);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -403,7 +403,6 @@ static void open(GtkApplication *app, GFile** files, gint nfiles, const gchar* h
|
|||||||
if((*env)->ExceptionCheck(env))
|
if((*env)->ExceptionCheck(env))
|
||||||
(*env)->ExceptionDescribe(env);
|
(*env)->ExceptionDescribe(env);
|
||||||
|
|
||||||
extract_from_apk("assets/", "assets/");
|
|
||||||
/* extract native libraries from apk*/
|
/* extract native libraries from apk*/
|
||||||
if(!getenv("ATL_SKIP_NATIVES_EXTRACTION"))
|
if(!getenv("ATL_SKIP_NATIVES_EXTRACTION"))
|
||||||
extract_from_apk("lib/" NATIVE_ARCH "/", "lib/");
|
extract_from_apk("lib/" NATIVE_ARCH "/", "lib/");
|
||||||
|
|||||||
Reference in New Issue
Block a user