#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers /***************************************************************************** * OpenRCT2, an open source clone of Roller Coaster Tycoon 2. * * OpenRCT2 is the work of many authors, a full list can be found in contributors.md * For more information, visit https://github.com/OpenRCT2/OpenRCT2 * * OpenRCT2 is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * A full copy of the GNU General Public License can be found in licence.txt *****************************************************************************/ #pragma endregion #ifdef __ANDROID__ #include #include #include "IStream.hpp" #include "Zip.h" class ZipArchive final : public IZipArchive { private: jobject _zip; public: ZipArchive(const std::string_view& path, ZIP_ACCESS access) { // retrieve the JNI environment. JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jclass jniClass = env->FindClass("website/openrct2/ZipArchive"); jmethodID constructor = env->GetMethodID(jniClass, "", "(Ljava/lang/String;)V"); jstring jniPath = env->NewStringUTF(path.data()); // TODO: Catch exceptions. Should probably be done on Java side, and just return null from a static method jobject zip = env->NewObject(jniClass, constructor, jniPath); _zip = env->NewGlobalRef(zip); } ~ZipArchive() override { // retrieve the JNI environment. JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jclass zipClass = env->GetObjectClass(_zip); jmethodID closeMethod = env->GetMethodID(zipClass, "close", "()V"); env->CallVoidMethod(_zip, closeMethod); env->DeleteGlobalRef(_zip); } size_t GetNumFiles() const override { // retrieve the JNI environment. JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jclass zipClass = env->GetObjectClass(_zip); jmethodID fileCountMethod = env->GetMethodID(zipClass, "getNumFiles", "()I"); return (size_t) env->CallIntMethod(_zip, fileCountMethod); } std::string GetFileName(size_t index) const override { // retrieve the JNI environment. JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jclass zipClass = env->GetObjectClass(_zip); jmethodID fileNameMethod = env->GetMethodID(zipClass, "getFileName", "(I)Ljava/lang/String;"); jstring jniString = (jstring) env->CallObjectMethod(_zip, fileNameMethod, (jint) index); const char *jniChars = env->GetStringUTFChars(jniString, nullptr); utf8 *string = (char *) malloc(strlen(jniChars) + 1); memcpy((void *) string, jniChars, strlen(jniChars)); string[strlen(jniChars)] = 0x00; env->ReleaseStringUTFChars(jniString, jniChars); return string; } uint64 GetFileSize(size_t index) const override { // retrieve the JNI environment. JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jclass zipClass = env->GetObjectClass(_zip); jmethodID fileSizeMethod = env->GetMethodID(zipClass, "getFileSize", "(I)J"); return (size_t) env->CallLongMethod(_zip, fileSizeMethod, (jint) index); } std::vector GetFileData(const std::string_view& path) const override { // retrieve the JNI environment. JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv(); jclass zipClass = env->GetObjectClass(_zip); jstring javaPath = env->NewStringUTF(path.data()); jmethodID indexMethod = env->GetMethodID(zipClass, "getFileIndex", "(Ljava/lang/String;)I"); jint index = env->CallIntMethod(_zip, indexMethod, javaPath); jmethodID fileMethod = env->GetMethodID(zipClass, "getFile", "(I)J"); jlong ptr = env->CallLongMethod(_zip, fileMethod, index); auto dataPtr = reinterpret_cast(ptr); auto dataSize = this->GetFileSize(index); return std::vector(dataPtr, dataPtr + dataSize); } void SetFileData(const std::string_view& path, std::vector&& data) override { STUB(); } void DeleteFile(const std::string_view&) override { STUB(); } void RenameFile(const std::string_view&, const std::string_view&) override { STUB(); } }; namespace Zip { std::unique_ptr Open(const std::string_view& path, ZIP_ACCESS access) { return std::make_unique(path, access); } std::unique_ptr TryOpen(const std::string_view& path, ZIP_ACCESS access) { std::unique_ptr result; try { result = std::make_unique(path, access); } catch (const std::exception&) { } return result; } } extern "C" { JNIEXPORT jlong JNICALL Java_website_openrct2_ZipArchive_allocBytes(JNIEnv *env, jclass, jbyteArray input, jint numBytes); } JNIEXPORT jlong JNICALL Java_website_openrct2_ZipArchive_allocBytes(JNIEnv *env, jclass, jbyteArray input, jint numBytes) { jbyte *bufferPtr = env->GetByteArrayElements(input, nullptr); void *data = Memory::Allocate((size_t) numBytes); memcpy(data, bufferPtr, numBytes); env->ReleaseByteArrayElements(input, bufferPtr, 0); return (uintptr_t) data; } #endif // __ANDROID__