Path: blob/master/platform/android/file_access_filesystem_jandroid.cpp
10277 views
/**************************************************************************/1/* file_access_filesystem_jandroid.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "file_access_filesystem_jandroid.h"3132#include "thread_jandroid.h"3334#include "core/os/os.h"35#include "core/templates/local_vector.h"3637#include <unistd.h>3839jobject FileAccessFilesystemJAndroid::file_access_handler = nullptr;40jclass FileAccessFilesystemJAndroid::cls;4142jmethodID FileAccessFilesystemJAndroid::_file_open = nullptr;43jmethodID FileAccessFilesystemJAndroid::_file_get_size = nullptr;44jmethodID FileAccessFilesystemJAndroid::_file_seek = nullptr;45jmethodID FileAccessFilesystemJAndroid::_file_seek_end = nullptr;46jmethodID FileAccessFilesystemJAndroid::_file_read = nullptr;47jmethodID FileAccessFilesystemJAndroid::_file_tell = nullptr;48jmethodID FileAccessFilesystemJAndroid::_file_eof = nullptr;49jmethodID FileAccessFilesystemJAndroid::_file_set_eof = nullptr;50jmethodID FileAccessFilesystemJAndroid::_file_close = nullptr;51jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr;52jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr;53jmethodID FileAccessFilesystemJAndroid::_file_exists = nullptr;54jmethodID FileAccessFilesystemJAndroid::_file_last_modified = nullptr;55jmethodID FileAccessFilesystemJAndroid::_file_last_accessed = nullptr;56jmethodID FileAccessFilesystemJAndroid::_file_resize = nullptr;57jmethodID FileAccessFilesystemJAndroid::_file_size = nullptr;5859String FileAccessFilesystemJAndroid::get_path() const {60return path_src;61}6263String FileAccessFilesystemJAndroid::get_path_absolute() const {64return absolute_path;65}6667Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mode_flags) {68if (is_open()) {69_close();70}7172if (_file_open) {73JNIEnv *env = get_jni_env();74ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);7576String path = fix_path(p_path).simplify_path();77jstring js = env->NewStringUTF(path.utf8().get_data());78int res = env->CallIntMethod(file_access_handler, _file_open, js, p_mode_flags);79env->DeleteLocalRef(js);8081if (res < 0) {82// Errors are passed back as their negative value to differentiate from the positive file id.83return static_cast<Error>(-res);84}8586id = res;87path_src = p_path;88absolute_path = path;89return OK;90} else {91return ERR_UNCONFIGURED;92}93}9495void FileAccessFilesystemJAndroid::_close() {96if (!is_open()) {97return;98}99100if (_file_close) {101JNIEnv *env = get_jni_env();102ERR_FAIL_NULL(env);103env->CallVoidMethod(file_access_handler, _file_close, id);104}105id = 0;106}107108bool FileAccessFilesystemJAndroid::is_open() const {109return id != 0;110}111112void FileAccessFilesystemJAndroid::seek(uint64_t p_position) {113if (_file_seek) {114JNIEnv *env = get_jni_env();115ERR_FAIL_NULL(env);116ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");117env->CallVoidMethod(file_access_handler, _file_seek, id, p_position);118}119}120121void FileAccessFilesystemJAndroid::seek_end(int64_t p_position) {122if (_file_seek_end) {123JNIEnv *env = get_jni_env();124ERR_FAIL_NULL(env);125ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");126env->CallVoidMethod(file_access_handler, _file_seek_end, id, p_position);127}128}129130uint64_t FileAccessFilesystemJAndroid::get_position() const {131if (_file_tell) {132JNIEnv *env = get_jni_env();133ERR_FAIL_NULL_V(env, 0);134ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");135return env->CallLongMethod(file_access_handler, _file_tell, id);136} else {137return 0;138}139}140141uint64_t FileAccessFilesystemJAndroid::get_length() const {142if (_file_get_size) {143JNIEnv *env = get_jni_env();144ERR_FAIL_NULL_V(env, 0);145ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");146return env->CallLongMethod(file_access_handler, _file_get_size, id);147} else {148return 0;149}150}151152bool FileAccessFilesystemJAndroid::eof_reached() const {153if (_file_eof) {154JNIEnv *env = get_jni_env();155ERR_FAIL_NULL_V(env, false);156ERR_FAIL_COND_V_MSG(!is_open(), false, "File must be opened before use.");157return env->CallBooleanMethod(file_access_handler, _file_eof, id);158} else {159return false;160}161}162163void FileAccessFilesystemJAndroid::_set_eof(bool eof) {164if (_file_set_eof) {165ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");166167JNIEnv *env = get_jni_env();168ERR_FAIL_NULL(env);169env->CallVoidMethod(file_access_handler, _file_set_eof, id, eof);170}171}172173String FileAccessFilesystemJAndroid::get_line() const {174ERR_FAIL_COND_V_MSG(!is_open(), String(), "File must be opened before use.");175176const size_t buffer_size_limit = 2048;177const uint64_t file_size = get_length();178const uint64_t start_position = get_position();179180String result;181LocalVector<uint8_t> line_buffer;182size_t current_buffer_size = 0;183uint64_t line_buffer_position = 0;184185while (true) {186size_t line_buffer_size = MIN(buffer_size_limit, file_size - get_position());187if (line_buffer_size <= 0) {188const_cast<FileAccessFilesystemJAndroid *>(this)->_set_eof(true);189break;190}191192current_buffer_size += line_buffer_size;193line_buffer.resize(current_buffer_size);194195uint64_t bytes_read = get_buffer(&line_buffer[line_buffer_position], current_buffer_size - line_buffer_position);196if (bytes_read <= 0) {197break;198}199200for (; bytes_read > 0; line_buffer_position++, bytes_read--) {201uint8_t elem = line_buffer[line_buffer_position];202if (elem == '\n' || elem == '\0') {203// Found the end of the line204const_cast<FileAccessFilesystemJAndroid *>(this)->seek(start_position + line_buffer_position + 1);205if (result.append_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) {206return String();207}208return result;209}210}211}212213if (result.append_utf8((const char *)line_buffer.ptr(), line_buffer_position, true)) {214return String();215}216return result;217}218219uint64_t FileAccessFilesystemJAndroid::get_buffer(uint8_t *p_dst, uint64_t p_length) const {220if (_file_read) {221ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");222if (p_length == 0) {223return 0;224}225226JNIEnv *env = get_jni_env();227ERR_FAIL_NULL_V(env, 0);228229jobject j_buffer = env->NewDirectByteBuffer(p_dst, p_length);230int length = env->CallIntMethod(file_access_handler, _file_read, id, j_buffer);231env->DeleteLocalRef(j_buffer);232return length;233} else {234return 0;235}236}237238bool FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) {239if (_file_write) {240ERR_FAIL_COND_V_MSG(!is_open(), false, "File must be opened before use.");241ERR_FAIL_COND_V(!p_src && p_length > 0, false);242if (p_length == 0) {243return true;244}245246JNIEnv *env = get_jni_env();247ERR_FAIL_NULL_V(env, false);248249jobject j_buffer = env->NewDirectByteBuffer((void *)p_src, p_length);250bool ok = env->CallBooleanMethod(file_access_handler, _file_write, id, j_buffer);251env->DeleteLocalRef(j_buffer);252return ok;253} else {254return false;255}256}257258Error FileAccessFilesystemJAndroid::get_error() const {259if (eof_reached()) {260return ERR_FILE_EOF;261}262return OK;263}264265Error FileAccessFilesystemJAndroid::resize(int64_t p_length) {266if (_file_resize) {267JNIEnv *env = get_jni_env();268ERR_FAIL_NULL_V(env, FAILED);269ERR_FAIL_COND_V_MSG(!is_open(), FAILED, "File must be opened before use.");270int res = env->CallIntMethod(file_access_handler, _file_resize, id, p_length);271return static_cast<Error>(res);272} else {273return ERR_UNAVAILABLE;274}275}276277void FileAccessFilesystemJAndroid::flush() {278if (_file_flush) {279JNIEnv *env = get_jni_env();280ERR_FAIL_NULL(env);281ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");282env->CallVoidMethod(file_access_handler, _file_flush, id);283}284}285286bool FileAccessFilesystemJAndroid::file_exists(const String &p_path) {287if (_file_exists) {288JNIEnv *env = get_jni_env();289ERR_FAIL_NULL_V(env, false);290291String path = fix_path(p_path).simplify_path();292jstring js = env->NewStringUTF(path.utf8().get_data());293bool result = env->CallBooleanMethod(file_access_handler, _file_exists, js);294env->DeleteLocalRef(js);295return result;296} else {297return false;298}299}300301uint64_t FileAccessFilesystemJAndroid::_get_modified_time(const String &p_file) {302if (_file_last_modified) {303JNIEnv *env = get_jni_env();304ERR_FAIL_NULL_V(env, 0);305306String path = fix_path(p_file).simplify_path();307jstring js = env->NewStringUTF(path.utf8().get_data());308uint64_t result = env->CallLongMethod(file_access_handler, _file_last_modified, js);309env->DeleteLocalRef(js);310return result;311} else {312return 0;313}314}315316uint64_t FileAccessFilesystemJAndroid::_get_access_time(const String &p_file) {317if (_file_last_accessed) {318JNIEnv *env = get_jni_env();319ERR_FAIL_NULL_V(env, 0);320321String path = fix_path(p_file).simplify_path();322jstring js = env->NewStringUTF(path.utf8().get_data());323uint64_t result = env->CallLongMethod(file_access_handler, _file_last_accessed, js);324env->DeleteLocalRef(js);325return result;326} else {327return 0;328}329}330331int64_t FileAccessFilesystemJAndroid::_get_size(const String &p_file) {332if (_file_size) {333JNIEnv *env = get_jni_env();334ERR_FAIL_NULL_V(env, -1);335336String path = fix_path(p_file).simplify_path();337jstring js = env->NewStringUTF(path.utf8().get_data());338int64_t result = env->CallLongMethod(file_access_handler, _file_size, js);339env->DeleteLocalRef(js);340return result;341} else {342return -1;343}344}345346void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) {347JNIEnv *env = get_jni_env();348file_access_handler = env->NewGlobalRef(p_file_access_handler);349350jclass c = env->GetObjectClass(file_access_handler);351cls = (jclass)env->NewGlobalRef(c);352353_file_open = env->GetMethodID(cls, "fileOpen", "(Ljava/lang/String;I)I");354_file_get_size = env->GetMethodID(cls, "fileGetSize", "(I)J");355_file_tell = env->GetMethodID(cls, "fileGetPosition", "(I)J");356_file_eof = env->GetMethodID(cls, "isFileEof", "(I)Z");357_file_set_eof = env->GetMethodID(cls, "setFileEof", "(IZ)V");358_file_seek = env->GetMethodID(cls, "fileSeek", "(IJ)V");359_file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V");360_file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I");361_file_close = env->GetMethodID(cls, "fileClose", "(I)V");362_file_write = env->GetMethodID(cls, "fileWrite", "(ILjava/nio/ByteBuffer;)Z");363_file_flush = env->GetMethodID(cls, "fileFlush", "(I)V");364_file_exists = env->GetMethodID(cls, "fileExists", "(Ljava/lang/String;)Z");365_file_last_modified = env->GetMethodID(cls, "fileLastModified", "(Ljava/lang/String;)J");366_file_last_accessed = env->GetMethodID(cls, "fileLastAccessed", "(Ljava/lang/String;)J");367_file_resize = env->GetMethodID(cls, "fileResize", "(IJ)I");368_file_size = env->GetMethodID(cls, "fileSize", "(Ljava/lang/String;)J");369}370371void FileAccessFilesystemJAndroid::terminate() {372JNIEnv *env = get_jni_env();373ERR_FAIL_NULL(env);374375env->DeleteGlobalRef(cls);376env->DeleteGlobalRef(file_access_handler);377}378379void FileAccessFilesystemJAndroid::close() {380if (is_open()) {381_close();382}383}384385FileAccessFilesystemJAndroid::FileAccessFilesystemJAndroid() {386id = 0;387}388389FileAccessFilesystemJAndroid::~FileAccessFilesystemJAndroid() {390if (is_open()) {391_close();392}393}394395396