diff --git a/CMakeLists.txt b/CMakeLists.txt index b20c2ba2..5ab54547 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,6 +79,7 @@ set(QSP_SOURCES qsp/bindings/default/qsp_default.h qsp/bindings/java/java_callbacks.c qsp/bindings/java/java_control.c + qsp/bindings/java/java_files.c qsp/bindings/java/qsp_java.h qsp/bindings/qsp.h qsp/actions.c qsp/actions.h diff --git a/qsp/bindings/java/QSPLib.java b/qsp/bindings/java/QSPLib.java index 28a53890..689ba2e1 100644 --- a/qsp/bindings/java/QSPLib.java +++ b/qsp/bindings/java/QSPLib.java @@ -135,9 +135,16 @@ public class ErrorInfo { public native boolean execUserInput(boolean toRefreshUI); public native ErrorInfo getLastErrorData(); public native String getErrorDesc(int errorNum); + public native boolean loadGameWorldFromData(byte[] data, boolean isNewGame); + public native boolean loadGameWorldFromFD(int fileDescriptor, boolean isNewGame); + public native byte[] saveGameAsData(boolean toRefreshUI); + public native boolean saveGameByFD(int fileDescriptor, boolean toRefreshUI); + public native boolean openSavedGameFromData(byte[] data, boolean toRefreshUI); + public native boolean openSavedGameFromFD(int fileDescriptor, boolean toRefreshUI); + public native boolean restartGame(boolean toRefreshUI); // Callbacks diff --git a/qsp/bindings/java/com_libqsp_jni_QSPLib.h b/qsp/bindings/java/com_libqsp_jni_QSPLib.h index 6c750c9d..8cb41a94 100644 --- a/qsp/bindings/java/com_libqsp_jni_QSPLib.h +++ b/qsp/bindings/java/com_libqsp_jni_QSPLib.h @@ -255,6 +255,14 @@ JNIEXPORT jstring JNICALL Java_com_libqsp_jni_QSPLib_getErrorDesc JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_loadGameWorldFromData (JNIEnv *, jobject, jbyteArray, jboolean); +/* + * Class: com_libqsp_jni_QSPLib + * Method: loadGameWorldFromFD + * Signature: (IZ)Z + */ +JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_loadGameWorldFromFD + (JNIEnv *, jobject, jint, jboolean); + /* * Class: com_libqsp_jni_QSPLib * Method: saveGameAsData @@ -263,6 +271,14 @@ JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_loadGameWorldFromData JNIEXPORT jbyteArray JNICALL Java_com_libqsp_jni_QSPLib_saveGameAsData (JNIEnv *, jobject, jboolean); +/* + * Class: com_libqsp_jni_QSPLib + * Method: saveGameByFD + * Signature: (IZ)Z + */ +JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_saveGameByFD + (JNIEnv *, jobject, jint, jboolean); + /* * Class: com_libqsp_jni_QSPLib * Method: openSavedGameFromData @@ -271,6 +287,14 @@ JNIEXPORT jbyteArray JNICALL Java_com_libqsp_jni_QSPLib_saveGameAsData JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_openSavedGameFromData (JNIEnv *, jobject, jbyteArray, jboolean); +/* + * Class: com_libqsp_jni_QSPLib + * Method: openSavedGameFromFD + * Signature: (IZ)Z + */ +JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_openSavedGameFromFD + (JNIEnv *, jobject, jint, jboolean); + /* * Class: com_libqsp_jni_QSPLib * Method: restartGame diff --git a/qsp/bindings/java/java_control.c b/qsp/bindings/java/java_control.c index b7bbb8b4..57a82347 100644 --- a/qsp/bindings/java/java_control.c +++ b/qsp/bindings/java/java_control.c @@ -444,6 +444,64 @@ JNIEXPORT jstring JNICALL Java_com_libqsp_jni_QSPLib_getErrorDesc(JNIEnv *env, j /* ------------------------------------------------------------ */ /* Game controls */ +#ifdef __ANDROID__ + +#include + +/* Loading a new game from FileDescriptor */ +JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_loadGameWorldFromFD(JNIEnv *env, jobject api, jint fileDescriptor, jboolean isNewGame) +{ + if (fileDescriptor < 0) return QSP_FALSE; + const int native_fd = dup(fileDescriptor); + if (native_fd < 0) return QSP_FALSE; + FILE *f = fdopen(native_fd, "rb"); + if (f == NULL) + { + close(native_fd); + return QSP_FALSE; + } + QSP_BOOL res = qspOpenQuestFromFILE(f, isNewGame); + fclose(f); + return res; +} +/* Saving state by FileDescriptor */ +JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_saveGameByFD(JNIEnv *env, jobject api, jint fileDescriptor, jboolean toRefreshUI) +{ + if (fileDescriptor < 0) return QSP_FALSE; + const int native_fd = dup(fileDescriptor); + if (native_fd < 0) return QSP_FALSE; + FILE *f = fdopen(native_fd, "wb"); + if (!f) { + close(native_fd); + return QSP_FALSE; + } + qspPrepareExecution(QSP_FALSE); + QSP_BOOL res = qspSaveGameStatusToFILE(f); + fclose(f); + if (toRefreshUI) qspCallRefreshInt(QSP_FALSE); + return res; +} +/* Loading state from FileDescriptor */ +JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_openSavedGameFromFD(JNIEnv *env, jobject api, jint fileDescriptor, jboolean toRefreshUI) +{ + if (fileDescriptor < 0) return QSP_FALSE; + const int native_fd = dup(fileDescriptor); + if (native_fd < 0) return QSP_FALSE; + FILE *f = fdopen(native_fd, "rb"); + if (!f) + { + close(native_fd); + return QSP_FALSE; + } + qspPrepareExecution(QSP_FALSE); + QSP_BOOL res = qspOpenGameStatusFromFILE(f); + fclose(f); + if (!res) return JNI_FALSE; + if (qspErrorNum) return JNI_FALSE; + if (toRefreshUI) qspCallRefreshInt(QSP_FALSE); + return JNI_TRUE; +} +#endif /* Load game from data */ JNIEXPORT jboolean JNICALL Java_com_libqsp_jni_QSPLib_loadGameWorldFromData(JNIEnv *env, jobject api, jbyteArray data, jboolean isNewGame) { diff --git a/qsp/bindings/java/java_files.c b/qsp/bindings/java/java_files.c new file mode 100644 index 00000000..a309c06e --- /dev/null +++ b/qsp/bindings/java/java_files.c @@ -0,0 +1,76 @@ +#include "../../declarations.h" + +#ifdef _JAVA_BINDING + +#include "../../errors.h" +#include "../../game.h" + +QSP_BOOL qspOpenQuestFromFILE(FILE *f, const QSP_BOOL isNewGame) +{ + fseek(f, 0, SEEK_END); + const int fileSize = ftell(f); + + char *buf = malloc(fileSize); + if (buf == NULL) return QSP_FALSE; + + fseek(f, 0, SEEK_SET); + fread(buf, 1, fileSize, f); + + QSP_BOOL res = qspOpenGame(buf, fileSize, isNewGame); + free(buf); + + return res; +} + +QSP_BOOL qspOpenGameStatusFromFILE(FILE *f) +{ + fseek(f, 0, SEEK_END); + const int fileSize = ftell(f); + + char *buf = malloc(fileSize); + if (buf == NULL) return QSP_FALSE; + + fseek(f, 0, SEEK_SET); + fread(buf, 1, fileSize, f); + + QSP_BOOL res = qspOpenGameStatus(buf, fileSize); + free(buf); + + return res; +} + +QSP_BOOL qspSaveGameStatusToFILE(FILE *f) +{ + void *dataBuf; + int dataBufSize = 64 * 1024; + QSP_BOOL res = QSP_FALSE; + + dataBuf = malloc(dataBufSize); + if (dataBuf == NULL) return QSP_FALSE; + + while (1) + { + if (qspSaveGameStatus(dataBuf, &dataBufSize, QSP_TRUE)) + { + res = QSP_TRUE; + break; + } + if (!dataBufSize) + { + free(dataBuf); + return QSP_FALSE; + } + dataBufSize += QSP_SAVEDGAMEDATAEXTRASPACE; + dataBuf = realloc(dataBuf, dataBufSize); + } + + if (res) + { + fwrite(dataBuf, 1, dataBufSize, f); + } + + free(dataBuf); + return res; +} + +#endif \ No newline at end of file diff --git a/qsp/bindings/java/qsp_java.h b/qsp/bindings/java/qsp_java.h index a9e86bdb..fc65b2ac 100644 --- a/qsp/bindings/java/qsp_java.h +++ b/qsp/bindings/java/qsp_java.h @@ -67,4 +67,8 @@ JNIListItem qspToJavaObjectItem(JNIEnv *env, QSPString name, QSPString title, QSPString image); void qspReleaseJavaListItem(JNIEnv *env, JNIListItem *listItem); + QSP_BOOL qspOpenQuestFromFILE(FILE *, QSP_BOOL); + QSP_BOOL qspSaveGameStatusToFILE(FILE *); + QSP_BOOL qspOpenGameStatusFromFILE(FILE *); + #endif