static int Android_JNI_FileClose(SDL_RWops* ctx, bool release) { LocalReferenceHolder refs; int result = 0; if (!refs.init(mEnv)) { SDL_SetError("Failed to allocate enough JVM local references"); return -1; } if (ctx) { if (release) { mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef); } jobject inputStream = (jobject)ctx->hidden.androidio.inputStreamRef; // inputStream.close(); jmethodID mid = mEnv->GetMethodID(mEnv->GetObjectClass(inputStream), "close", "()V"); mEnv->CallVoidMethod(inputStream, mid); mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.inputStreamRef); mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.readableByteChannelRef); if (Android_JNI_ExceptionOccurred()) { result = -1; } if (release) { SDL_FreeRW(ctx); } } return result; }
extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t maxnum) { LocalReferenceHolder refs; int bytesRemaining = size * maxnum; int bytesRead = 0; if (!refs.init(mEnv)) { return -1; } jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef; jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining); while (bytesRemaining > 0) { // result = readableByteChannel.read(...); int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer); if (Android_JNI_ExceptionOccurred()) { return 0; } if (result < 0) { break; } bytesRemaining -= result; bytesRead += result; ctx->hidden.androidio.position += result; } return bytesRead / size; }
extern "C" int Android_JNI_FileOpen(SDL_RWops* ctx, const char* fileName, const char*) { LocalReferenceHolder refs; if (!refs.init(mEnv)) { return -1; } if (!ctx) { return -1; } jstring fileNameJString = mEnv->NewStringUTF(fileName); ctx->hidden.androidio.fileNameRef = mEnv->NewGlobalRef(fileNameJString); ctx->hidden.androidio.inputStreamRef = NULL; return Android_JNI_FileOpen(ctx); }
extern "C" size_t Android_JNI_FileRead(SDL_RWops* ctx, void* buffer, size_t size, size_t maxnum) { LocalReferenceHolder refs; 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 (!refs.init(mEnv)) { return -1; } jobject readableByteChannel = (jobject)ctx->hidden.androidio.readableByteChannelRef; jmethodID readMethod = (jmethodID)ctx->hidden.androidio.readMethod; jobject byteBuffer = mEnv->NewDirectByteBuffer(buffer, bytesRemaining); while (bytesRemaining > 0) { // result = readableByteChannel.read(...); int result = mEnv->CallIntMethod(readableByteChannel, readMethod, byteBuffer); if (Android_JNI_ExceptionOccurred()) { return 0; } if (result < 0) { break; } bytesRemaining -= result; bytesRead += result; ctx->hidden.androidio.position += result; } return bytesRead / size; }
static int Android_JNI_FileOpen(SDL_RWops* ctx) { LocalReferenceHolder refs; int result = 0; jmethodID mid; jobject context; jobject assetManager; jobject inputStream; jclass channels; jobject readableByteChannel; jstring fileNameJString; if (!refs.init(mEnv)) { goto failure; } fileNameJString = (jstring)ctx->hidden.androidio.fileNameRef; // context = SDLActivity.getContext(); mid = mEnv->GetStaticMethodID(mActivityClass, "getContext","()Landroid/content/Context;"); context = mEnv->CallStaticObjectMethod(mActivityClass, mid); // assetManager = context.getAssets(); mid = mEnv->GetMethodID(mEnv->GetObjectClass(context), "getAssets", "()Landroid/content/res/AssetManager;"); assetManager = mEnv->CallObjectMethod(context, mid); // inputStream = assetManager.open(<filename>); mid = mEnv->GetMethodID(mEnv->GetObjectClass(assetManager), "open", "(Ljava/lang/String;)Ljava/io/InputStream;"); inputStream = mEnv->CallObjectMethod(assetManager, mid, fileNameJString); if (Android_JNI_ExceptionOccurred()) { goto failure; } ctx->hidden.androidio.inputStreamRef = mEnv->NewGlobalRef(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->GetObjectClass(inputStream), "available", "()I"); ctx->hidden.androidio.size = mEnv->CallIntMethod(inputStream, mid); if (Android_JNI_ExceptionOccurred()) { goto failure; } // readableByteChannel = Channels.newChannel(inputStream); channels = mEnv->FindClass("java/nio/channels/Channels"); mid = mEnv->GetStaticMethodID(channels, "newChannel", "(Ljava/io/InputStream;)Ljava/nio/channels/ReadableByteChannel;"); readableByteChannel = mEnv->CallStaticObjectMethod( channels, mid, inputStream); if (Android_JNI_ExceptionOccurred()) { goto failure; } ctx->hidden.androidio.readableByteChannelRef = mEnv->NewGlobalRef(readableByteChannel); // Store .read id for reading purposes mid = mEnv->GetMethodID(mEnv->GetObjectClass(readableByteChannel), "read", "(Ljava/nio/ByteBuffer;)I"); ctx->hidden.androidio.readMethod = mid; ctx->hidden.androidio.position = 0; if (false) { failure: result = -1; mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.fileNameRef); if(ctx->hidden.androidio.inputStreamRef != NULL) { mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.inputStreamRef); } if(ctx->hidden.androidio.readableByteChannelRef != NULL) { mEnv->DeleteGlobalRef((jobject)ctx->hidden.androidio.readableByteChannelRef); } } return result; }