From a4b17e7852c99cdbf108c77fe407cb78ed08159c Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Thu, 15 Jun 2023 21:21:43 +0300 Subject: [PATCH] [FileAccess] Return error codes from `store_*` methods. --- core/io/file_access.compat.inc | 77 ++++++++++++++++- core/io/file_access.cpp | 85 +++++++++++-------- core/io/file_access.h | 46 ++++++---- core/io/file_access_compressed.cpp | 30 +++---- core/io/file_access_compressed.h | 2 +- core/io/file_access_encrypted.cpp | 9 +- core/io/file_access_encrypted.h | 2 +- core/io/file_access_memory.cpp | 12 +-- core/io/file_access_memory.h | 2 +- core/io/file_access_pack.cpp | 4 +- core/io/file_access_pack.h | 2 +- core/io/file_access_zip.cpp | 4 +- core/io/file_access_zip.h | 2 +- doc/classes/FileAccess.xml | 41 ++++++--- drivers/unix/file_access_unix.cpp | 8 +- drivers/unix/file_access_unix.h | 2 +- drivers/unix/file_access_unix_pipe.cpp | 8 +- drivers/unix/file_access_unix_pipe.h | 2 +- drivers/windows/file_access_windows.cpp | 8 +- drivers/windows/file_access_windows.h | 2 +- drivers/windows/file_access_windows_pipe.cpp | 8 +- drivers/windows/file_access_windows_pipe.h | 2 +- .../4.3-stable.expected | 20 +++++ platform/android/file_access_android.cpp | 4 +- platform/android/file_access_android.h | 2 +- .../file_access_filesystem_jandroid.cpp | 16 ++-- .../android/file_access_filesystem_jandroid.h | 2 +- .../godotengine/godot/io/file/AssetData.kt | 3 +- .../godotengine/godot/io/file/DataAccess.kt | 6 +- .../godot/io/file/FileAccessHandler.kt | 6 +- 30 files changed, 279 insertions(+), 138 deletions(-) diff --git a/core/io/file_access.compat.inc b/core/io/file_access.compat.inc index ed16050126..97c7849e67 100644 --- a/core/io/file_access.compat.inc +++ b/core/io/file_access.compat.inc @@ -34,8 +34,79 @@ Ref FileAccess::_open_encrypted_bind_compat_98918(const String &p_pa return open_encrypted(p_path, p_mode_flags, p_key, Vector()); } -void FileAccess::_bind_compatibility_methods() { - ClassDB::bind_compatibility_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::_open_encrypted_bind_compat_98918); +void FileAccess::store_8_bind_compat_78289(uint8_t p_dest) { + store_8(p_dest); } -#endif // DISABLE_DEPRECATED +void FileAccess::store_16_bind_compat_78289(uint16_t p_dest) { + store_16(p_dest); +} + +void FileAccess::store_32_bind_compat_78289(uint32_t p_dest) { + store_32(p_dest); +} + +void FileAccess::store_64_bind_compat_78289(uint64_t p_dest) { + store_64(p_dest); +} + +void FileAccess::store_buffer_bind_compat_78289(const Vector &p_buffer) { + store_buffer(p_buffer); +} + +void FileAccess::store_var_bind_compat_78289(const Variant &p_var, bool p_full_objects) { + store_var(p_var, p_full_objects); +} + +void FileAccess::store_half_bind_compat_78289(float p_dest) { + store_half(p_dest); +} + +void FileAccess::store_float_bind_compat_78289(float p_dest) { + store_float(p_dest); +} + +void FileAccess::store_double_bind_compat_78289(double p_dest) { + store_double(p_dest); +} + +void FileAccess::store_real_bind_compat_78289(real_t p_real) { + store_real(p_real); +} + +void FileAccess::store_string_bind_compat_78289(const String &p_string) { + store_string(p_string); +} + +void FileAccess::store_line_bind_compat_78289(const String &p_line) { + store_line(p_line); +} + +void FileAccess::store_csv_line_bind_compat_78289(const Vector &p_values, const String &p_delim) { + store_csv_line(p_values, p_delim); +} + +void FileAccess::store_pascal_string_bind_compat_78289(const String &p_string) { + store_pascal_string(p_string); +} + +void FileAccess::_bind_compatibility_methods() { + ClassDB::bind_compatibility_static_method("FileAccess", D_METHOD("open_encrypted", "path", "mode_flags", "key"), &FileAccess::_open_encrypted_bind_compat_98918); + + ClassDB::bind_compatibility_method(D_METHOD("store_8", "value"), &FileAccess::store_8_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_16", "value"), &FileAccess::store_16_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_32", "value"), &FileAccess::store_32_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_64", "value"), &FileAccess::store_64_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_half", "value"), &FileAccess::store_half_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_float", "value"), &FileAccess::store_float_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_double", "value"), &FileAccess::store_double_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_real", "value"), &FileAccess::store_real_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_buffer", "buffer"), &FileAccess::store_buffer_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_line", "line"), &FileAccess::store_line_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line_bind_compat_78289, DEFVAL(",")); + ClassDB::bind_compatibility_method(D_METHOD("store_string", "string"), &FileAccess::store_string_bind_compat_78289); + ClassDB::bind_compatibility_method(D_METHOD("store_var", "value", "full_objects"), &FileAccess::store_var_bind_compat_78289, DEFVAL(false)); + ClassDB::bind_compatibility_method(D_METHOD("store_pascal_string", "string"), &FileAccess::store_pascal_string_bind_compat_78289); +} + +#endif diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp index 29027cade1..aedd9e20f9 100644 --- a/core/io/file_access.cpp +++ b/core/io/file_access.cpp @@ -495,56 +495,56 @@ String FileAccess::get_as_utf8_string(bool p_skip_cr) const { return s; } -void FileAccess::store_8(uint8_t p_dest) { - store_buffer(&p_dest, sizeof(uint8_t)); +bool FileAccess::store_8(uint8_t p_dest) { + return store_buffer(&p_dest, sizeof(uint8_t)); } -void FileAccess::store_16(uint16_t p_dest) { +bool FileAccess::store_16(uint16_t p_dest) { if (big_endian) { p_dest = BSWAP16(p_dest); } - store_buffer(reinterpret_cast(&p_dest), sizeof(uint16_t)); + return store_buffer(reinterpret_cast(&p_dest), sizeof(uint16_t)); } -void FileAccess::store_32(uint32_t p_dest) { +bool FileAccess::store_32(uint32_t p_dest) { if (big_endian) { p_dest = BSWAP32(p_dest); } - store_buffer(reinterpret_cast(&p_dest), sizeof(uint32_t)); + return store_buffer(reinterpret_cast(&p_dest), sizeof(uint32_t)); } -void FileAccess::store_64(uint64_t p_dest) { +bool FileAccess::store_64(uint64_t p_dest) { if (big_endian) { p_dest = BSWAP64(p_dest); } - store_buffer(reinterpret_cast(&p_dest), sizeof(uint64_t)); + return store_buffer(reinterpret_cast(&p_dest), sizeof(uint64_t)); } -void FileAccess::store_real(real_t p_real) { +bool FileAccess::store_real(real_t p_real) { if constexpr (sizeof(real_t) == 4) { - store_float(p_real); + return store_float(p_real); } else { - store_double(p_real); + return store_double(p_real); } } -void FileAccess::store_half(float p_dest) { - store_16(Math::make_half_float(p_dest)); +bool FileAccess::store_half(float p_dest) { + return store_16(Math::make_half_float(p_dest)); } -void FileAccess::store_float(float p_dest) { +bool FileAccess::store_float(float p_dest) { MarshallFloat m; m.f = p_dest; - store_32(m.i); + return store_32(m.i); } -void FileAccess::store_double(double p_dest) { +bool FileAccess::store_double(double p_dest) { MarshallDouble m; m.d = p_dest; - store_64(m.l); + return store_64(m.l); } uint64_t FileAccess::get_modified_time(const String &p_file) { @@ -628,19 +628,18 @@ Error FileAccess::set_read_only_attribute(const String &p_file, bool p_ro) { return err; } -void FileAccess::store_string(const String &p_string) { +bool FileAccess::store_string(const String &p_string) { if (p_string.length() == 0) { - return; + return true; } CharString cs = p_string.utf8(); - store_buffer((uint8_t *)&cs[0], cs.length()); + return store_buffer((uint8_t *)&cs[0], cs.length()); } -void FileAccess::store_pascal_string(const String &p_string) { +bool FileAccess::store_pascal_string(const String &p_string) { CharString cs = p_string.utf8(); - store_32(cs.length()); - store_buffer((uint8_t *)&cs[0], cs.length()); + return store_32(cs.length()) && store_buffer((uint8_t *)&cs[0], cs.length()); } String FileAccess::get_pascal_string() { @@ -655,13 +654,12 @@ String FileAccess::get_pascal_string() { return ret; } -void FileAccess::store_line(const String &p_line) { - store_string(p_line); - store_8('\n'); +bool FileAccess::store_line(const String &p_line) { + return store_string(p_line) && store_8('\n'); } -void FileAccess::store_csv_line(const Vector &p_values, const String &p_delim) { - ERR_FAIL_COND(p_delim.length() != 1); +bool FileAccess::store_csv_line(const Vector &p_values, const String &p_delim) { + ERR_FAIL_COND_V(p_delim.length() != 1, false); String line = ""; int size = p_values.size(); @@ -678,30 +676,43 @@ void FileAccess::store_csv_line(const Vector &p_values, const String &p_ line += value; } - store_line(line); + return store_line(line); } -void FileAccess::store_buffer(const Vector &p_buffer) { +bool FileAccess::store_buffer(const Vector &p_buffer) { uint64_t len = p_buffer.size(); + if (len == 0) { + return true; + } + const uint8_t *r = p_buffer.ptr(); - store_buffer(r, len); + return store_buffer(r, len); } -void FileAccess::store_var(const Variant &p_var, bool p_full_objects) { +bool FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_V(!p_src && p_length > 0, false); + for (uint64_t i = 0; i < p_length; i++) { + if (unlikely(!store_8(p_src[i]))) { + return false; + } + } + return true; +} + +bool FileAccess::store_var(const Variant &p_var, bool p_full_objects) { int len; Error err = encode_variant(p_var, nullptr, len, p_full_objects); - ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); + ERR_FAIL_COND_V_MSG(err != OK, false, "Error when trying to encode Variant."); Vector buff; buff.resize(len); uint8_t *w = buff.ptrw(); err = encode_variant(p_var, &w[0], len, p_full_objects); - ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant."); + ERR_FAIL_COND_V_MSG(err != OK, false, "Error when trying to encode Variant."); - store_32(len); - store_buffer(buff); + return store_32(len) && store_buffer(buff); } Vector FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) { @@ -864,7 +875,7 @@ void FileAccess::_bind_methods() { ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float); ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double); ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real); - ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (void(FileAccess::*)(const Vector &)) & FileAccess::store_buffer); + ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool(FileAccess::*)(const Vector &)) & FileAccess::store_buffer); ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line); ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(",")); ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string); diff --git a/core/io/file_access.h b/core/io/file_access.h index 48984c6c1b..5541975bc1 100644 --- a/core/io/file_access.h +++ b/core/io/file_access.h @@ -112,6 +112,21 @@ protected: #ifndef DISABLE_DEPRECATED static Ref _open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector &p_key); + void store_8_bind_compat_78289(uint8_t p_dest); + void store_16_bind_compat_78289(uint16_t p_dest); + void store_32_bind_compat_78289(uint32_t p_dest); + void store_64_bind_compat_78289(uint64_t p_dest); + void store_buffer_bind_compat_78289(const Vector &p_buffer); + void store_var_bind_compat_78289(const Variant &p_var, bool p_full_objects = false); + void store_half_bind_compat_78289(float p_dest); + void store_float_bind_compat_78289(float p_dest); + void store_double_bind_compat_78289(double p_dest); + void store_real_bind_compat_78289(real_t p_real); + void store_string_bind_compat_78289(const String &p_string); + void store_line_bind_compat_78289(const String &p_line); + void store_csv_line_bind_compat_78289(const Vector &p_values, const String &p_delim = ","); + void store_pascal_string_bind_compat_78289(const String &p_string); + static void _bind_compatibility_methods(); #endif @@ -164,6 +179,7 @@ public: virtual String get_as_utf8_string(bool p_skip_cr = false) const; /** + * Use this for files WRITTEN in _big_ endian machines (ie, amiga/mac) * It's not about the current CPU type but file formats. * This flag gets reset to `false` (little endian) on each open. @@ -175,27 +191,27 @@ public: virtual Error resize(int64_t p_length) = 0; virtual void flush() = 0; - virtual void store_8(uint8_t p_dest); ///< store a byte - virtual void store_16(uint16_t p_dest); ///< store 16 bits uint - virtual void store_32(uint32_t p_dest); ///< store 32 bits uint - virtual void store_64(uint64_t p_dest); ///< store 64 bits uint + virtual bool store_8(uint8_t p_dest); ///< store a byte + virtual bool store_16(uint16_t p_dest); ///< store 16 bits uint + virtual bool store_32(uint32_t p_dest); ///< store 32 bits uint + virtual bool store_64(uint64_t p_dest); ///< store 64 bits uint - virtual void store_half(float p_dest); - virtual void store_float(float p_dest); - virtual void store_double(double p_dest); - virtual void store_real(real_t p_real); + virtual bool store_half(float p_dest); + virtual bool store_float(float p_dest); + virtual bool store_double(double p_dest); + virtual bool store_real(real_t p_real); - virtual void store_string(const String &p_string); - virtual void store_line(const String &p_line); - virtual void store_csv_line(const Vector &p_values, const String &p_delim = ","); + virtual bool store_string(const String &p_string); + virtual bool store_line(const String &p_line); + virtual bool store_csv_line(const Vector &p_values, const String &p_delim = ","); - virtual void store_pascal_string(const String &p_string); + virtual bool store_pascal_string(const String &p_string); virtual String get_pascal_string(); - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) = 0; ///< store an array of bytes, needs to be overwritten by children. - void store_buffer(const Vector &p_buffer); + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) = 0; ///< store an array of bytes, needs to be overwritten by children. + bool store_buffer(const Vector &p_buffer); - void store_var(const Variant &p_var, bool p_full_objects = false); + bool store_var(const Variant &p_var, bool p_full_objects = false); virtual void close() = 0; diff --git a/core/io/file_access_compressed.cpp b/core/io/file_access_compressed.cpp index f7f2852e0a..53ef93d09b 100644 --- a/core/io/file_access_compressed.cpp +++ b/core/io/file_access_compressed.cpp @@ -40,18 +40,6 @@ void FileAccessCompressed::configure(const String &p_magic, Compression::Mode p_ block_size = p_block_size; } -#define WRITE_FIT(m_bytes) \ - { \ - if (write_pos + (m_bytes) > write_max) { \ - write_max = write_pos + (m_bytes); \ - } \ - if (write_max > write_buffer_size) { \ - write_buffer_size = next_power_of_2(write_max); \ - buffer.resize(write_buffer_size); \ - write_ptr = buffer.ptrw(); \ - } \ - } - Error FileAccessCompressed::open_after_magic(Ref p_base) { f = p_base; cmode = (Compression::Mode)f->get_32(); @@ -309,13 +297,23 @@ void FileAccessCompressed::flush() { // compressed files keep data in memory till close() } -void FileAccessCompressed::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_COND_MSG(f.is_null(), "File must be opened before use."); - ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); +bool FileAccessCompressed::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_V_MSG(f.is_null(), false, "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!writing, false, "File has not been opened in write mode."); + + if (write_pos + (p_length) > write_max) { + write_max = write_pos + (p_length); + } + if (write_max > write_buffer_size) { + write_buffer_size = next_power_of_2(write_max); + ERR_FAIL_COND_V(buffer.resize(write_buffer_size) != OK, false); + write_ptr = buffer.ptrw(); + } - WRITE_FIT(p_length); memcpy(write_ptr + write_pos, p_src, p_length); + write_pos += p_length; + return true; } bool FileAccessCompressed::file_exists(const String &p_name) { diff --git a/core/io/file_access_compressed.h b/core/io/file_access_compressed.h index ea9837dd03..607a45fc0a 100644 --- a/core/io/file_access_compressed.h +++ b/core/io/file_access_compressed.h @@ -89,7 +89,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; virtual bool file_exists(const String &p_name) override; ///< return true if a file exists diff --git a/core/io/file_access_encrypted.cpp b/core/io/file_access_encrypted.cpp index ba26f2e07b..c899c860c6 100644 --- a/core/io/file_access_encrypted.cpp +++ b/core/io/file_access_encrypted.cpp @@ -228,16 +228,17 @@ Error FileAccessEncrypted::get_error() const { return eofed ? ERR_FILE_EOF : OK; } -void FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_COND_MSG(!writing, "File has not been opened in write mode."); - ERR_FAIL_COND(!p_src && p_length > 0); +bool FileAccessEncrypted::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_V_MSG(!writing, false, "File has not been opened in write mode."); + ERR_FAIL_COND_V(!p_src && p_length > 0, false); if (pos + p_length >= get_length()) { - data.resize(pos + p_length); + ERR_FAIL_COND_V(data.resize(pos + p_length) != OK, false); } memcpy(data.ptrw() + pos, p_src, p_length); pos += p_length; + return true; } void FileAccessEncrypted::flush() { diff --git a/core/io/file_access_encrypted.h b/core/io/file_access_encrypted.h index 63a8cab145..a373fc0cb5 100644 --- a/core/io/file_access_encrypted.h +++ b/core/io/file_access_encrypted.h @@ -82,7 +82,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_name) override; ///< return true if a file exists diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp index 8d74011632..b5ab18407b 100644 --- a/core/io/file_access_memory.cpp +++ b/core/io/file_access_memory.cpp @@ -147,16 +147,16 @@ void FileAccessMemory::flush() { ERR_FAIL_NULL(data); } -void FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_COND(!p_src && p_length > 0); +bool FileAccessMemory::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_V(!p_src && p_length > 0, false); uint64_t left = length - pos; uint64_t write = MIN(p_length, left); - if (write < p_length) { - WARN_PRINT("Writing less data than requested"); - } - memcpy(&data[pos], p_src, write); pos += write; + + ERR_FAIL_COND_V_MSG(write < p_length, false, "Writing less data than requested."); + + return true; } diff --git a/core/io/file_access_memory.h b/core/io/file_access_memory.h index 39e1528d97..6845cf7130 100644 --- a/core/io/file_access_memory.h +++ b/core/io/file_access_memory.h @@ -61,7 +61,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_name) override; ///< return true if a file exists diff --git a/core/io/file_access_pack.cpp b/core/io/file_access_pack.cpp index 8b6b445cea..742aa3858e 100644 --- a/core/io/file_access_pack.cpp +++ b/core/io/file_access_pack.cpp @@ -417,8 +417,8 @@ void FileAccessPack::flush() { ERR_FAIL(); } -void FileAccessPack::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL(); +bool FileAccessPack::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_V(false); } bool FileAccessPack::file_exists(const String &p_name) { diff --git a/core/io/file_access_pack.h b/core/io/file_access_pack.h index b957a43de2..7011971164 100644 --- a/core/io/file_access_pack.h +++ b/core/io/file_access_pack.h @@ -184,7 +184,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; virtual bool file_exists(const String &p_name) override; diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp index 41907d1a3f..047b27cf82 100644 --- a/core/io/file_access_zip.cpp +++ b/core/io/file_access_zip.cpp @@ -322,8 +322,8 @@ void FileAccessZip::flush() { ERR_FAIL(); } -void FileAccessZip::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL(); +bool FileAccessZip::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_V(false); } bool FileAccessZip::file_exists(const String &p_name) { diff --git a/core/io/file_access_zip.h b/core/io/file_access_zip.h index 1e11e050df..57f1d20358 100644 --- a/core/io/file_access_zip.h +++ b/core/io/file_access_zip.h @@ -101,7 +101,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; virtual bool file_exists(const String &p_name) override; ///< return true if a file exists diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml index 846897a463..f3cf749b54 100644 --- a/doc/classes/FileAccess.xml +++ b/doc/classes/FileAccess.xml @@ -381,20 +381,22 @@ - + Stores an integer as 8 bits in the file. [b]Note:[/b] The [param value] should lie in the interval [code][0, 255][/code]. Any other value will overflow and wrap around. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example). - + Stores an integer as 16 bits in the file. [b]Note:[/b] The [param value] should lie in the interval [code][0, 2^16 - 1][/code]. Any other value will overflow and wrap around. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. To store a signed integer, use [method store_64] or store a signed integer from the interval [code][-2^15, 2^15 - 1][/code] (i.e. keeping one bit for the signedness) and compute its sign manually when reading. For example: [codeblocks] [gdscript] @@ -431,97 +433,108 @@ - + Stores an integer as 32 bits in the file. [b]Note:[/b] The [param value] should lie in the interval [code][0, 2^32 - 1][/code]. Any other value will overflow and wrap around. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. To store a signed integer, use [method store_64], or convert it manually (see [method store_16] for an example). - + Stores an integer as 64 bits in the file. [b]Note:[/b] The [param value] must lie in the interval [code][-2^63, 2^63 - 1][/code] (i.e. be a valid [int] value). + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores the given array of bytes in the file. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Store the given [PackedStringArray] in the file as a line formatted in the CSV (Comma-Separated Values) format. You can pass a different delimiter [param delim] to use other than the default [code]","[/code] (comma). This delimiter must be one-character long. Text will be encoded as UTF-8. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores a floating-point number as 64 bits in the file. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores a floating-point number as 32 bits in the file. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores a half-precision floating-point number as 16 bits in the file. - + Stores [param line] in the file followed by a newline character ([code]\n[/code]), encoding the text as UTF-8. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores the given [String] as a line in the file in Pascal format (i.e. also store the length of the string). Text will be encoded as UTF-8. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores a floating-point number in the file. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores [param string] in the file without a newline character ([code]\n[/code]), encoding the text as UTF-8. [b]Note:[/b] This method is intended to be used to write text files. The string is stored as a UTF-8 encoded buffer without string length or terminating zero, which means that it can't be loaded back easily. If you want to store a retrievable string in a binary file, consider using [method store_pascal_string] instead. For retrieving strings from a text file, you can use [code]get_buffer(length).get_string_from_utf8()[/code] (if you know the length) or [method get_as_text]. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. - + Stores any Variant value in the file. If [param full_objects] is [code]true[/code], encoding objects is allowed (and can potentially include code). Internally, this uses the same encoding mechanism as the [method @GlobalScope.var_to_bytes] method. [b]Note:[/b] Not all properties are included. Only properties that are configured with the [constant PROPERTY_USAGE_STORAGE] flag set will be serialized. You can add a new usage flag to a property by overriding the [method Object._get_property_list] method in your class. You can also check how property usage is configured by calling [method Object._get_property_list]. See [enum PropertyUsageFlags] for the possible usage flags. + [b]Note:[/b] If an error occurs, the resulting value of the file position indicator is indeterminate. diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 4b92e5f8a1..b9b47725f8 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -295,10 +295,10 @@ void FileAccessUnix::flush() { fflush(f); } -void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_NULL_MSG(f, "File must be opened before use."); - ERR_FAIL_COND(!p_src && p_length > 0); - ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); +bool FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_NULL_V_MSG(f, false, "File must be opened before use."); + ERR_FAIL_COND_V(!p_src && p_length > 0, false); + return fwrite(p_src, 1, p_length, f) == p_length; } bool FileAccessUnix::file_exists(const String &p_path) { diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 7caf8a14d7..9711cb2aa4 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -77,7 +77,7 @@ public: virtual Error resize(int64_t p_length) override; virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_path) override; ///< return true if a file exists diff --git a/drivers/unix/file_access_unix_pipe.cpp b/drivers/unix/file_access_unix_pipe.cpp index fd60bec9d0..325cca0815 100644 --- a/drivers/unix/file_access_unix_pipe.cpp +++ b/drivers/unix/file_access_unix_pipe.cpp @@ -150,14 +150,16 @@ Error FileAccessUnixPipe::get_error() const { return last_error; } -void FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_COND_MSG(fd[1] < 0, "Pipe must be opened before use."); - ERR_FAIL_COND(!p_src && p_length > 0); +bool FileAccessUnixPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_V_MSG(fd[1] < 0, false, "Pipe must be opened before use."); + ERR_FAIL_COND_V(!p_src && p_length > 0, false); if (::write(fd[1], p_src, p_length) != (ssize_t)p_length) { last_error = ERR_FILE_CANT_WRITE; + return false; } else { last_error = OK; + return true; } } diff --git a/drivers/unix/file_access_unix_pipe.h b/drivers/unix/file_access_unix_pipe.h index 1a4199f239..a95cbc8e61 100644 --- a/drivers/unix/file_access_unix_pipe.h +++ b/drivers/unix/file_access_unix_pipe.h @@ -71,7 +71,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override {} - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_path) override { return false; } diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 4a0e5e5f49..f3ec73fda3 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -372,9 +372,9 @@ void FileAccessWindows::flush() { } } -void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_NULL(f); - ERR_FAIL_COND(!p_src && p_length > 0); +bool FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_NULL_V(f, false); + ERR_FAIL_COND_V(!p_src && p_length > 0, false); if (flags == READ_WRITE || flags == WRITE_READ) { if (prev_op == READ) { @@ -385,7 +385,7 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) { prev_op = WRITE; } - ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != (size_t)p_length); + return fwrite(p_src, 1, p_length, f) == (size_t)p_length; } bool FileAccessWindows::file_exists(const String &p_name) { diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index f458ff9c6c..92021e1912 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -75,7 +75,7 @@ public: virtual Error resize(int64_t p_length) override; virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_name) override; ///< return true if a file exists diff --git a/drivers/windows/file_access_windows_pipe.cpp b/drivers/windows/file_access_windows_pipe.cpp index 7348b29a92..88e76f67ef 100644 --- a/drivers/windows/file_access_windows_pipe.cpp +++ b/drivers/windows/file_access_windows_pipe.cpp @@ -119,16 +119,18 @@ Error FileAccessWindowsPipe::get_error() const { return last_error; } -void FileAccessWindowsPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL_COND_MSG(fd[1] == nullptr, "Pipe must be opened before use."); - ERR_FAIL_COND(!p_src && p_length > 0); +bool FileAccessWindowsPipe::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_COND_V_MSG(fd[1] == nullptr, false, "Pipe must be opened before use."); + ERR_FAIL_COND_V(!p_src && p_length > 0, false); DWORD read = -1; bool ok = WriteFile(fd[1], p_src, p_length, &read, nullptr); if (!ok || read != p_length) { last_error = ERR_FILE_CANT_WRITE; + return false; } else { last_error = OK; + return true; } } diff --git a/drivers/windows/file_access_windows_pipe.h b/drivers/windows/file_access_windows_pipe.h index 5edf0500a5..b01b48fe13 100644 --- a/drivers/windows/file_access_windows_pipe.h +++ b/drivers/windows/file_access_windows_pipe.h @@ -70,7 +70,7 @@ public: virtual Error resize(int64_t p_length) override { return ERR_UNAVAILABLE; } virtual void flush() override {} - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; ///< store an array of bytes virtual bool file_exists(const String &p_name) override { return false; } diff --git a/misc/extension_api_validation/4.3-stable.expected b/misc/extension_api_validation/4.3-stable.expected index 0c988b8913..4cbeebc3b4 100644 --- a/misc/extension_api_validation/4.3-stable.expected +++ b/misc/extension_api_validation/4.3-stable.expected @@ -178,3 +178,23 @@ Validate extension JSON: Error: Field 'classes/RenderingDevice/methods/draw_list Draw lists no longer require the initial and final action for color and depth attachments to be specified. Draw lists can now specify if a particular color, depth, or stencil attachment should be cleared. + + +GH-78289 +-------- +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_16': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_32': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_64': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_8': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_buffer': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_csv_line': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_double': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_half': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_float': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_line': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_pascal_string': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_real': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_string': return_value +Validate extension JSON: JSON file: Field was added in a way that breaks compatibility 'classes/FileAccess/methods/store_var': return_value + +Added return values. Compatibility method registered. diff --git a/platform/android/file_access_android.cpp b/platform/android/file_access_android.cpp index 59b669eabb..da49c3e7ad 100644 --- a/platform/android/file_access_android.cpp +++ b/platform/android/file_access_android.cpp @@ -140,8 +140,8 @@ void FileAccessAndroid::flush() { ERR_FAIL(); } -void FileAccessAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) { - ERR_FAIL(); +bool FileAccessAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) { + ERR_FAIL_V(false); } bool FileAccessAndroid::file_exists(const String &p_path) { diff --git a/platform/android/file_access_android.h b/platform/android/file_access_android.h index 3224ab50b9..b411f747ec 100644 --- a/platform/android/file_access_android.h +++ b/platform/android/file_access_android.h @@ -73,7 +73,7 @@ public: virtual Error get_error() const override; // get last error virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; virtual bool file_exists(const String &p_path) override; // return true if a file exists diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp index 8b52a00ed8..5a1d85a669 100644 --- a/platform/android/file_access_filesystem_jandroid.cpp +++ b/platform/android/file_access_filesystem_jandroid.cpp @@ -234,19 +234,23 @@ uint64_t FileAccessFilesystemJAndroid::get_buffer(uint8_t *p_dst, uint64_t p_len } } -void FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) { +bool FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p_length) { if (_file_write) { - ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use."); + ERR_FAIL_COND_V_MSG(!is_open(), false, "File must be opened before use."); + ERR_FAIL_COND_V(!p_src && p_length > 0, false); if (p_length == 0) { - return; + return true; } JNIEnv *env = get_jni_env(); - ERR_FAIL_NULL(env); + ERR_FAIL_NULL_V(env, false); jobject j_buffer = env->NewDirectByteBuffer((void *)p_src, p_length); - env->CallVoidMethod(file_access_handler, _file_write, id, j_buffer); + bool ok = env->CallBooleanMethod(file_access_handler, _file_write, id, j_buffer); env->DeleteLocalRef(j_buffer); + return ok; + } else { + return false; } } @@ -324,7 +328,7 @@ void FileAccessFilesystemJAndroid::setup(jobject p_file_access_handler) { _file_seek_end = env->GetMethodID(cls, "fileSeekFromEnd", "(IJ)V"); _file_read = env->GetMethodID(cls, "fileRead", "(ILjava/nio/ByteBuffer;)I"); _file_close = env->GetMethodID(cls, "fileClose", "(I)V"); - _file_write = env->GetMethodID(cls, "fileWrite", "(ILjava/nio/ByteBuffer;)V"); + _file_write = env->GetMethodID(cls, "fileWrite", "(ILjava/nio/ByteBuffer;)Z"); _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"); diff --git a/platform/android/file_access_filesystem_jandroid.h b/platform/android/file_access_filesystem_jandroid.h index 1345b72fa6..f54a8e9d9a 100644 --- a/platform/android/file_access_filesystem_jandroid.h +++ b/platform/android/file_access_filesystem_jandroid.h @@ -84,7 +84,7 @@ public: virtual Error get_error() const override; ///< get last error virtual void flush() override; - virtual void store_buffer(const uint8_t *p_src, uint64_t p_length) override; + virtual bool store_buffer(const uint8_t *p_src, uint64_t p_length) override; virtual bool file_exists(const String &p_path) override; ///< return true if a file exists diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/AssetData.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/AssetData.kt index 1ab739d90b..d6994eb349 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/io/file/AssetData.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/AssetData.kt @@ -145,7 +145,8 @@ internal class AssetData(context: Context, private val filePath: String, accessF } } - override fun write(buffer: ByteBuffer) { + override fun write(buffer: ByteBuffer): Boolean { Log.w(TAG, "write() is not supported.") + return false } } 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 73f020f249..319ec3ec48 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 @@ -169,7 +169,7 @@ internal abstract class DataAccess { abstract fun position(): Long abstract fun size(): Long abstract fun read(buffer: ByteBuffer): Int - abstract fun write(buffer: ByteBuffer) + abstract fun write(buffer: ByteBuffer): Boolean fun seekFromEnd(positionFromEnd: Long) { val positionFromBeginning = max(0, size() - positionFromEnd) @@ -254,14 +254,16 @@ internal abstract class DataAccess { } } - override fun write(buffer: ByteBuffer) { + override fun write(buffer: ByteBuffer): Boolean { try { val writtenBytes = fileChannel.write(buffer) if (writtenBytes > 0) { endOfFile = false } + return true } catch (e: IOException) { Log.w(TAG, "Exception while writing to file $filePath.", e) + return false } } } 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 dee7aebdc3..21aee3395e 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 @@ -191,12 +191,12 @@ class FileAccessHandler(val context: Context) { return files[fileId].read(byteBuffer) } - fun fileWrite(fileId: Int, byteBuffer: ByteBuffer?) { + fun fileWrite(fileId: Int, byteBuffer: ByteBuffer?): Boolean { if (!hasFileId(fileId) || byteBuffer == null) { - return + return false } - files[fileId].write(byteBuffer) + return files[fileId].write(byteBuffer) } fun fileFlush(fileId: Int) {