Skip to content

Instantly share code, notes, and snippets.

@seven332
Last active June 21, 2016 09:10
Show Gist options
  • Save seven332/10e48beb8d667cb5cbf4b401216d9203 to your computer and use it in GitHub Desktop.
Save seven332/10e48beb8d667cb5cbf4b401216d9203 to your computer and use it in GitHub Desktop.
Base on SDL release-2.0.4
Index: include/SDL_rwops.h
===================================================================
--- include/SDL_rwops.h (revision 8be6e5ca9041dfcf8b20c85e43eb3beaa6efdd2b)
+++ include/SDL_rwops.h (revision )
@@ -96,15 +96,7 @@
#if defined(__ANDROID__)
struct
{
- void *fileNameRef;
- void *inputStreamRef;
- void *readableByteChannelRef;
- void *readMethod;
- void *assetFileDescriptorRef;
- long position;
- long size;
- long offset;
- int fd;
+ void *asset;
} androidio;
#elif defined(__WIN32__)
struct
Index: src/core/android/SDL_android.c
===================================================================
--- src/core/android/SDL_android.c (revision 8be6e5ca9041dfcf8b20c85e43eb3beaa6efdd2b)
+++ src/core/android/SDL_android.c (revision )
@@ -38,6 +38,7 @@
#include "../../video/android/SDL_androidwindow.h"
#include "../../joystick/android/SDL_sysjoystick_c.h"
+#include <android/asset_manager_jni.h>
#include <android/log.h>
#include <pthread.h>
#include <sys/types.h>
@@ -77,6 +78,9 @@
static jmethodID midAudioQuit;
static jmethodID midPollInputDevices;
+/* AAssetManager */
+static AAssetManager *mAssetManager;
+
/* Accelerometer data storage */
static float fLastAccelerometer[3];
static SDL_bool bHasNewData;
@@ -110,6 +114,10 @@
/* Called before SDL_main() to initialize JNI bindings */
JNIEXPORT void JNICALL SDL_Android_Init(JNIEnv* mEnv, jclass cls)
{
+ jmethodID mid;
+ jobject context;
+ jobject assetManager;
+
__android_log_print(ANDROID_LOG_INFO, "SDL", "SDL_Android_Init()");
Android_JNI_SetupThread();
@@ -129,6 +137,18 @@
midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"pollInputDevices", "()V");
+ /* context = SDLActivity.getContext(); */
+ mid = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
+ "getContext","()Landroid/content/Context;");
+ context = (*mEnv)->CallStaticObjectMethod(mEnv, mActivityClass, mid);
+
+ /* assetManager = context.getAssets(); */
+ mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
+ "getAssets", "()Landroid/content/res/AssetManager;");
+ assetManager = (*mEnv)->CallObjectMethod(mEnv, context, mid);
+
+ mAssetManager = AAssetManager_fromJava(mEnv, assetManager);
+
bHasNewData = SDL_FALSE;
if (!midGetNativeSurface || !midAudioInit ||
@@ -691,251 +711,27 @@
return SDL_FALSE;
}
-static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx)
-{
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
-
- int result = 0;
-
- jmethodID mid;
- jobject context;
- jobject assetManager;
- jobject inputStream;
- jclass channels;
- jobject readableByteChannel;
- jstring fileNameJString;
- jobject fd;
- jclass fdCls;
- jfieldID descriptor;
-
- JNIEnv *mEnv = Android_JNI_GetEnv();
- if (!LocalReferenceHolder_Init(&refs, mEnv)) {
- goto failure;
- }
-
- fileNameJString = (jstring)ctx->hidden.androidio.fileNameRef;
- ctx->hidden.androidio.position = 0;
-
- /* context = SDLActivity.getContext(); */
- mid = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "getContext","()Landroid/content/Context;");
- context = (*mEnv)->CallStaticObjectMethod(mEnv, mActivityClass, mid);
-
-
- /* assetManager = context.getAssets(); */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
- "getAssets", "()Landroid/content/res/AssetManager;");
- assetManager = (*mEnv)->CallObjectMethod(mEnv, context, mid);
-
- /* First let's try opening the file to obtain an AssetFileDescriptor.
- * This method reads the files directly from the APKs using standard *nix calls
- */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager), "openFd", "(Ljava/lang/String;)Landroid/content/res/AssetFileDescriptor;");
- inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString);
- if (Android_JNI_ExceptionOccurred(SDL_TRUE)) {
- goto fallback;
- }
-
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getStartOffset", "()J");
- ctx->hidden.androidio.offset = (*mEnv)->CallLongMethod(mEnv, inputStream, mid);
- if (Android_JNI_ExceptionOccurred(SDL_TRUE)) {
- goto fallback;
- }
-
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getDeclaredLength", "()J");
- ctx->hidden.androidio.size = (*mEnv)->CallLongMethod(mEnv, inputStream, mid);
- if (Android_JNI_ExceptionOccurred(SDL_TRUE)) {
- goto fallback;
- }
-
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream), "getFileDescriptor", "()Ljava/io/FileDescriptor;");
- fd = (*mEnv)->CallObjectMethod(mEnv, inputStream, mid);
- fdCls = (*mEnv)->GetObjectClass(mEnv, fd);
- descriptor = (*mEnv)->GetFieldID(mEnv, fdCls, "descriptor", "I");
- ctx->hidden.androidio.fd = (*mEnv)->GetIntField(mEnv, fd, descriptor);
- ctx->hidden.androidio.assetFileDescriptorRef = (*mEnv)->NewGlobalRef(mEnv, inputStream);
-
- /* Seek to the correct offset in the file. */
- lseek(ctx->hidden.androidio.fd, (off_t)ctx->hidden.androidio.offset, SEEK_SET);
-
- if (0) {
-fallback:
- /* Disabled log message because of spam on the Nexus 7 */
- /* __android_log_print(ANDROID_LOG_DEBUG, "SDL", "Falling back to legacy InputStream method for opening file"); */
-
- /* Try the old method using InputStream */
- ctx->hidden.androidio.assetFileDescriptorRef = NULL;
-
- /* inputStream = assetManager.open(<filename>); */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, assetManager),
- "open", "(Ljava/lang/String;I)Ljava/io/InputStream;");
- inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */);
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
- /* Try fallback to APK expansion files */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
- "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
- if (!mid) {
- SDL_SetError("No openAPKExpansionInputStream() in Java class");
- goto failure; /* Java class is missing the required method */
- }
- inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString);
-
- /* Exception is checked first because it always needs to be cleared.
- * If no exception occurred then the last SDL error message is kept.
- */
- if (Android_JNI_ExceptionOccurred(SDL_FALSE) || !inputStream) {
- goto failure;
- }
- }
-
- ctx->hidden.androidio.inputStreamRef = (*mEnv)->NewGlobalRef(mEnv, inputStream);
-
- /* Despite all the visible documentation on [Asset]InputStream claiming
- * that the .available() method is not guaranteed to return the entire file
- * size, comments in <sdk>/samples/<ver>/ApiDemos/src/com/example/ ...
- * android/apis/content/ReadAsset.java imply that Android's
- * AssetInputStream.available() /will/ always return the total file size
- */
-
- /* size = inputStream.available(); */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream),
- "available", "()I");
- ctx->hidden.androidio.size = (long)(*mEnv)->CallIntMethod(mEnv, inputStream, mid);
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
- goto failure;
- }
-
- /* readableByteChannel = Channels.newChannel(inputStream); */
- channels = (*mEnv)->FindClass(mEnv, "java/nio/channels/Channels");
- mid = (*mEnv)->GetStaticMethodID(mEnv, channels,
- "newChannel",
- "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;");
- readableByteChannel = (*mEnv)->CallStaticObjectMethod(
- mEnv, channels, mid, inputStream);
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
- goto failure;
- }
-
- ctx->hidden.androidio.readableByteChannelRef =
- (*mEnv)->NewGlobalRef(mEnv, readableByteChannel);
-
- /* Store .read id for reading purposes */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, readableByteChannel),
- "read", "(Ljava/nio/ByteBuffer;)I");
- ctx->hidden.androidio.readMethod = mid;
- }
-
- if (0) {
-failure:
- result = -1;
-
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.fileNameRef);
-
- if(ctx->hidden.androidio.inputStreamRef != NULL) {
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.inputStreamRef);
- }
-
- if(ctx->hidden.androidio.readableByteChannelRef != NULL) {
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.readableByteChannelRef);
- }
-
- if(ctx->hidden.androidio.assetFileDescriptorRef != NULL) {
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.assetFileDescriptorRef);
- }
-
- }
-
- LocalReferenceHolder_Cleanup(&refs);
- return result;
-}
-
int Android_JNI_FileOpen(SDL_RWops* ctx,
const char* fileName, const char* mode)
{
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
- JNIEnv *mEnv = Android_JNI_GetEnv();
- int retval;
-
- if (!LocalReferenceHolder_Init(&refs, mEnv)) {
- LocalReferenceHolder_Cleanup(&refs);
+ AAsset *asset = AAssetManager_open(mAssetManager, fileName, AASSET_MODE_BUFFER);
+ if (asset == NULL) {
return -1;
}
-
- if (!ctx) {
- LocalReferenceHolder_Cleanup(&refs);
- return -1;
+ ctx->hidden.androidio.asset = asset;
+ return 0;
- }
+}
- jstring fileNameJString = (*mEnv)->NewStringUTF(mEnv, fileName);
- ctx->hidden.androidio.fileNameRef = (*mEnv)->NewGlobalRef(mEnv, fileNameJString);
- ctx->hidden.androidio.inputStreamRef = NULL;
- ctx->hidden.androidio.readableByteChannelRef = NULL;
- ctx->hidden.androidio.readMethod = NULL;
- ctx->hidden.androidio.assetFileDescriptorRef = NULL;
-
- retval = Internal_Android_JNI_FileOpen(ctx);
- LocalReferenceHolder_Cleanup(&refs);
- return retval;
-}
-
size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer,
size_t size, size_t maxnum)
{
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
-
- if (ctx->hidden.androidio.assetFileDescriptorRef) {
- size_t bytesMax = size * maxnum;
- if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && ctx->hidden.androidio.position + bytesMax > ctx->hidden.androidio.size) {
- bytesMax = ctx->hidden.androidio.size - ctx->hidden.androidio.position;
- }
- size_t result = read(ctx->hidden.androidio.fd, buffer, bytesMax );
- if (result > 0) {
- ctx->hidden.androidio.position += result;
- LocalReferenceHolder_Cleanup(&refs);
- return result / size;
- }
- LocalReferenceHolder_Cleanup(&refs);
+ if (ctx->hidden.androidio.asset == NULL) {
return 0;
} else {
- jlong bytesRemaining = (jlong) (size * maxnum);
- jlong bytesMax = (jlong) (ctx->hidden.androidio.size - ctx->hidden.androidio.position);
- int bytesRead = 0;
-
- /* Don't read more bytes than those that remain in the file, otherwise we get an exception */
- if (bytesRemaining > bytesMax) bytesRemaining = bytesMax;
-
- JNIEnv *mEnv = Android_JNI_GetEnv();
- if (!LocalReferenceHolder_Init(&refs, mEnv)) {
- LocalReferenceHolder_Cleanup(&refs);
- return 0;
+ return AAsset_read((AAsset *)ctx->hidden.androidio.asset, buffer, size * maxnum) / size;
- }
+ }
-
- jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef;
- jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod;
- jobject byteBuffer = (*mEnv)->NewDirectByteBuffer(mEnv, buffer, bytesRemaining);
-
- while (bytesRemaining > 0) {
- /* result = readableByteChannel.read(...); */
- int result = (*mEnv)->CallIntMethod(mEnv, readableByteChannel, readMethod, byteBuffer);
-
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
- LocalReferenceHolder_Cleanup(&refs);
- return 0;
- }
+}
- if (result < 0) {
- break;
- }
-
- bytesRemaining -= result;
- bytesRead += result;
- ctx->hidden.androidio.position += result;
- }
- LocalReferenceHolder_Cleanup(&refs);
- return bytesRead / size;
- }
-}
-
size_t Android_JNI_FileWrite(SDL_RWops* ctx, const void* buffer,
size_t size, size_t num)
{
@@ -943,146 +739,20 @@
return 0;
}
-static int Internal_Android_JNI_FileClose(SDL_RWops* ctx, SDL_bool release)
-{
- struct LocalReferenceHolder refs = LocalReferenceHolder_Setup(__FUNCTION__);
-
- int result = 0;
- JNIEnv *mEnv = Android_JNI_GetEnv();
-
- if (!LocalReferenceHolder_Init(&refs, mEnv)) {
- LocalReferenceHolder_Cleanup(&refs);
- return SDL_SetError("Failed to allocate enough JVM local references");
- }
-
- if (ctx) {
- if (release) {
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.fileNameRef);
- }
-
- if (ctx->hidden.androidio.assetFileDescriptorRef) {
- jobject inputStream = (jobject)ctx->hidden.androidio.assetFileDescriptorRef;
- jmethodID mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream),
- "close", "()V");
- (*mEnv)->CallVoidMethod(mEnv, inputStream, mid);
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.assetFileDescriptorRef);
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
- result = -1;
- }
- }
- else {
- jobject inputStream = (jobject)ctx->hidden.androidio.inputStreamRef;
-
- /* inputStream.close(); */
- jmethodID mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, inputStream),
- "close", "()V");
- (*mEnv)->CallVoidMethod(mEnv, inputStream, mid);
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.inputStreamRef);
- (*mEnv)->DeleteGlobalRef(mEnv, (jobject)ctx->hidden.androidio.readableByteChannelRef);
- if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
- result = -1;
- }
- }
-
- if (release) {
- SDL_FreeRW(ctx);
- }
- }
-
- LocalReferenceHolder_Cleanup(&refs);
- return result;
-}
-
-
Sint64 Android_JNI_FileSize(SDL_RWops* ctx)
{
- return ctx->hidden.androidio.size;
+ return AAsset_getLength((AAsset *) ctx->hidden.androidio.asset);
}
Sint64 Android_JNI_FileSeek(SDL_RWops* ctx, Sint64 offset, int whence)
{
- if (ctx->hidden.androidio.assetFileDescriptorRef) {
- switch (whence) {
- case RW_SEEK_SET:
- if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
- offset += ctx->hidden.androidio.offset;
- break;
- case RW_SEEK_CUR:
- offset += ctx->hidden.androidio.position;
- if (ctx->hidden.androidio.size != -1 /* UNKNOWN_LENGTH */ && offset > ctx->hidden.androidio.size) offset = ctx->hidden.androidio.size;
- offset += ctx->hidden.androidio.offset;
- break;
- case RW_SEEK_END:
- offset = ctx->hidden.androidio.offset + ctx->hidden.androidio.size + offset;
- break;
- default:
- return SDL_SetError("Unknown value for 'whence'");
+ return AAsset_seek((AAsset *) ctx->hidden.androidio.asset, offset, whence);
- }
+}
- whence = SEEK_SET;
- off_t ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET);
- if (ret == -1) return -1;
- ctx->hidden.androidio.position = ret - ctx->hidden.androidio.offset;
- } else {
- Sint64 newPosition;
-
- switch (whence) {
- case RW_SEEK_SET:
- newPosition = offset;
- break;
- case RW_SEEK_CUR:
- newPosition = ctx->hidden.androidio.position + offset;
- break;
- case RW_SEEK_END:
- newPosition = ctx->hidden.androidio.size + offset;
- break;
- default:
- return SDL_SetError("Unknown value for 'whence'");
- }
-
- /* Validate the new position */
- if (newPosition < 0) {
- return SDL_Error(SDL_EFSEEK);
- }
- if (newPosition > ctx->hidden.androidio.size) {
- newPosition = ctx->hidden.androidio.size;
- }
-
- Sint64 movement = newPosition - ctx->hidden.androidio.position;
- if (movement > 0) {
- unsigned char buffer[4096];
-
- /* The easy case where we're seeking forwards */
- while (movement > 0) {
- Sint64 amount = sizeof (buffer);
- if (amount > movement) {
- amount = movement;
- }
- size_t result = Android_JNI_FileRead(ctx, buffer, 1, amount);
- if (result <= 0) {
- /* Failed to read/skip the required amount, so fail */
- return -1;
- }
-
- movement -= result;
- }
-
- } else if (movement < 0) {
- /* We can't seek backwards so we have to reopen the file and seek */
- /* forwards which obviously isn't very efficient */
- Internal_Android_JNI_FileClose(ctx, SDL_FALSE);
- Internal_Android_JNI_FileOpen(ctx);
- Android_JNI_FileSeek(ctx, newPosition, RW_SEEK_SET);
- }
- }
-
- return ctx->hidden.androidio.position;
-
-}
-
int Android_JNI_FileClose(SDL_RWops* ctx)
{
- return Internal_Android_JNI_FileClose(ctx, SDL_TRUE);
+ AAsset_close((AAsset *) ctx->hidden.androidio.asset);
+ return (int) NULL;
}
/* returns a new global reference which needs to be released later */
@@ -1621,4 +1291,3 @@
#endif /* __ANDROID__ */
/* vi: set ts=4 sw=4 expandtab: */
-
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment