From 88b3e68f93fad5681b27b11ddacc562b03d5ef45 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Mon, 8 Apr 2024 22:09:34 +0300 Subject: [PATCH] [FileAccess] Implement `resize` method. --- core/io/file_access.cpp | 1 + core/io/file_access.h | 1 + core/io/file_access_compressed.h | 1 + core/io/file_access_encrypted.h | 1 + core/io/file_access_memory.h | 1 + core/io/file_access_pack.h | 1 + core/io/file_access_zip.h | 1 + doc/classes/FileAccess.xml | 7 ++++++ drivers/unix/file_access_unix.cpp | 17 ++++++++++++++ drivers/unix/file_access_unix.h | 1 + drivers/unix/file_access_unix_pipe.h | 1 + drivers/windows/file_access_windows.cpp | 19 +++++++++++++++ drivers/windows/file_access_windows.h | 1 + drivers/windows/file_access_windows_pipe.h | 1 + platform/android/file_access_android.h | 1 + .../file_access_filesystem_jandroid.cpp | 23 +++++++++++++++++++ .../android/file_access_filesystem_jandroid.h | 2 ++ .../godotengine/godot/io/file/DataAccess.kt | 22 ++++++++++++++++++ .../godot/io/file/FileAccessHandler.kt | 9 ++++++++ 19 files changed, 111 insertions(+) diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index d2a5103953f..1cf388b33a7 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -867,6 +867,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_bytes", "path"), &FileAccess::_get_file_as_bytes); ClassDB::bind_static_method("FileAccess", D_METHOD("get_file_as_string", "path"), &FileAccess::_get_file_as_string); + ClassDB::bind_method(D_METHOD("resize", "length"), &FileAccess::resize); ClassDB::bind_method(D_METHOD("flush"), &FileAccess::flush); ClassDB::bind_method(D_METHOD("get_path"), &FileAccess::get_path); ClassDB::bind_method(D_METHOD("get_path_absolute"), &FileAccess::get_path_absolute); diff --git a/core/io/file_access.h b/core/io/file_access.h index 0b631f68b17..2ab84db4b63 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -166,6 +166,7 @@ public: virtual Error get_error() const = 0; ///< get last error + virtual Error resize(int64_t p_length) = 0; virtual void flush() = 0; virtual void store_8(uint8_t p_dest) = 0; ///< store a byte virtual void store_16(uint16_t p_dest); ///< store 16 bits uint diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index bf57eaa07c0..f706c82f8e6 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -88,6 +88,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 489d213b8fd..42afe49a5e7 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -78,6 +78,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index d9efb354c33..e9fbc26d751 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -61,6 +61,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_byte) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index 0deacfebab0..594ac8f089b 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -177,6 +177,7 @@ public: virtual Error get_error() const override; + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index e9ea74e01d6..88b63e93e2d 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -100,6 +100,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index 6b9c0bcc766..c28cbfa1beb 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -324,6 +324,13 @@ Returns [code]null[/code] if opening the file failed. You can use [method get_open_error] to check the error that occurred. + + + + + Resizes the file to a specified length. The file must be open in a mode that permits writing. If the file is extended, NUL characters are appended. If the file is truncated, all data from the end file to the original length of the file is lost. + + diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index a35d8bfddec..210507c2c63 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -286,6 +286,23 @@ Error FileAccessUnix::get_error() const { return last_error; } +Error FileAccessUnix::resize(int64_t p_length) { + ERR_FAIL_NULL_V_MSG(f, FAILED, "File must be opened before use."); + int res = ::ftruncate(fileno(f), p_length); + switch (res) { + case 0: + return OK; + case EBADF: + return ERR_FILE_CANT_OPEN; + case EFBIG: + return ERR_OUT_OF_MEMORY; + case EINVAL: + return ERR_INVALID_PARAMETER; + default: + return FAILED; + } +} + void FileAccessUnix::flush() { ERR_FAIL_NULL_MSG(f, "File must be opened before use."); fflush(f); diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 553fbcf3552..c0286dbff34 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -75,6 +75,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override; virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte virtual void store_16(uint16_t p_dest) override; diff --git a/drivers/unix/file_access_unix_pipe.h b/drivers/unix/file_access_unix_pipe.h index d14f897d8f2..8e7988791b9 100644 --- a/drivers/unix/file_access_unix_pipe.h +++ b/drivers/unix/file_access_unix_pipe.h @@ -70,6 +70,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override {} virtual void store_8(uint8_t p_src) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index dd8bceb573b..726e0fdc5a5 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -41,6 +41,7 @@ #include #include +#include #include #include #include @@ -369,6 +370,24 @@ Error FileAccessWindows::get_error() const { return last_error; } +Error FileAccessWindows::resize(int64_t p_length) { + ERR_FAIL_NULL_V_MSG(f, FAILED, "File must be opened before use."); + errno_t res = _chsize_s(_fileno(f), p_length); + switch (res) { + case 0: + return OK; + case EACCES: + case EBADF: + return ERR_FILE_CANT_OPEN; + case ENOSPC: + return ERR_OUT_OF_MEMORY; + case EINVAL: + return ERR_INVALID_PARAMETER; + default: + return FAILED; + } +} + void FileAccessWindows::flush() { ERR_FAIL_NULL(f); diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 173423fb068..a25bbcfb3ac 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -77,6 +77,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override; virtual void flush() override; virtual void store_8(uint8_t p_dest) override; ///< store a byte virtual void store_16(uint16_t p_dest) override; diff --git a/drivers/windows/file_access_windows_pipe.h b/drivers/windows/file_access_windows_pipe.h index e6abe61fa33..b885ef78e64 100644 --- a/drivers/windows/file_access_windows_pipe.h +++ b/drivers/windows/file_access_windows_pipe.h @@ -69,6 +69,7 @@ public: virtual Error get_error() const override; ///< get last error + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override {} virtual void store_8(uint8_t p_src) override; ///< store a byte virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index ec613b6687b..bfe590b22f6 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -65,6 +65,7 @@ public: virtual bool eof_reached() const override; // reading passed EOF + virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual uint8_t get_8() const override; // get a byte virtual uint16_t get_16() const override; virtual uint32_t get_32() const override; diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index 46d9728632d..cc7acffdad0 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -53,6 +53,7 @@ jmethodID FileAccessFilesystemJAndroid::_file_write = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_flush = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_exists = nullptr; jmethodID FileAccessFilesystemJAndroid::_file_last_modified = nullptr; +jmethodID FileAccessFilesystemJAndroid::_file_resize = nullptr; String FileAccessFilesystemJAndroid::get_path() const { return path_src; @@ -324,6 +325,27 @@ Error FileAccessFilesystemJAndroid::get_error() const { return OK; } +Error FileAccessFilesystemJAndroid::resize(int64_t p_length) { + if (_file_resize) { + JNIEnv *env = get_jni_env(); + ERR_FAIL_NULL_V(env, FAILED); + ERR_FAIL_COND_V_MSG(!is_open(), FAILED, "File must be opened before use."); + int res = env->CallIntMethod(file_access_handler, _file_resize, id, p_length); + switch (res) { + case 0: + return OK; + case -3: + return ERR_INVALID_PARAMETER; + case -2: + return ERR_FILE_CANT_OPEN; + default: + return FAILED; + } + } else { + return ERR_UNAVAILABLE; + } +} + void FileAccessFilesystemJAndroid::flush() { if (_file_flush) { JNIEnv *env = get_jni_env(); @@ -383,6 +405,7 @@ void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) { _file_flush = env->GetMethodID(cls, "fileFlush", "(I)V"); _file_exists = env->GetMethodID(cls, "fileExists", "(Ljava/lang/String;)Z"); _file_last_modified = env->GetMethodID(cls, "fileLastModified", "(Ljava/lang/String;)J"); + _file_resize = env->GetMethodID(cls, "fileResize", "(IJ)I"); } void FileAccessFilesystemJAndroid::close() { diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index f33aa64ebe0..4a28b6e3d54 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -52,6 +52,7 @@ class FileAccessFilesystemJAndroid : public FileAccess { static jmethodID _file_close; static jmethodID _file_exists; static jmethodID _file_last_modified; + static jmethodID _file_resize; int id; String absolute_path; @@ -76,6 +77,7 @@ public: virtual bool eof_reached() const override; ///< reading passed EOF + virtual Error resize(int64_t p_length) override; virtual uint8_t get_8() const override; ///< get a byte virtual uint16_t get_16() const override; virtual uint32_t get_32() const override; diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt index 0f447f0b052..b155c4e4880 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt @@ -36,7 +36,9 @@ import android.util.Log import org.godotengine.godot.io.StorageScope import java.io.IOException import java.nio.ByteBuffer +import java.nio.channels.ClosedChannelException import java.nio.channels.FileChannel +import java.nio.channels.NonWritableChannelException import kotlin.math.max /** @@ -50,6 +52,11 @@ internal abstract class DataAccess(private val filePath: String) { companion object { private val TAG = DataAccess::class.java.simpleName + private const val OK_ERROR_ID = 0; + private const val FAILED_ERROR_ID = -1; + private const val FILE_CANT_OPEN_ERROR_ID = -2; + private const val INVALID_PARAMETER_ERROR_ID = -3; + fun generateDataAccess( storageScope: StorageScope, context: Context, @@ -135,6 +142,21 @@ internal abstract class DataAccess(private val filePath: String) { seek(positionFromBeginning) } + fun resize(length: Long): Int { + return try { + fileChannel.truncate(length) + OK_ERROR_ID + } catch (e: NonWritableChannelException) { + FILE_CANT_OPEN_ERROR_ID + } catch (e: ClosedChannelException) { + FILE_CANT_OPEN_ERROR_ID + } catch (e: IllegalArgumentException) { + INVALID_PARAMETER_ERROR_ID + } catch (e: IOException) { + FAILED_ERROR_ID + } + } + fun position(): Long { return try { fileChannel.position() diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt index 50741c1aab3..6a8a10e56f1 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt @@ -45,6 +45,7 @@ class FileAccessHandler(val context: Context) { companion object { private val TAG = FileAccessHandler::class.java.simpleName + private const val FAILED_ERROR_ID = -1; private const val FILE_NOT_FOUND_ERROR_ID = -1 internal const val INVALID_FILE_ID = 0 private const val STARTING_FILE_ID = 1 @@ -190,6 +191,14 @@ class FileAccessHandler(val context: Context) { } } + fun fileResize(fileId: Int, length: Long): Int { + if (!hasFileId(fileId)) { + return FAILED_ERROR_ID + } + + return files[fileId].resize(length) + } + fun fileGetPosition(fileId: Int): Long { if (!hasFileId(fileId)) { return 0L