Переглянути джерело

[FileAccess] Return error codes from `store_*` methods.

bruvzg 2 роки тому
батько
коміт
a4b17e7852
30 змінених файлів з 277 додано та 136 видалено
  1. 72 1
      core/io/file_access.compat.inc
  2. 48 37
      core/io/file_access.cpp
  3. 31 15
      core/io/file_access.h
  4. 14 16
      core/io/file_access_compressed.cpp
  5. 1 1
      core/io/file_access_compressed.h
  6. 5 4
      core/io/file_access_encrypted.cpp
  7. 1 1
      core/io/file_access_encrypted.h
  8. 6 6
      core/io/file_access_memory.cpp
  9. 1 1
      core/io/file_access_memory.h
  10. 2 2
      core/io/file_access_pack.cpp
  11. 1 1
      core/io/file_access_pack.h
  12. 2 2
      core/io/file_access_zip.cpp
  13. 1 1
      core/io/file_access_zip.h
  14. 27 14
      doc/classes/FileAccess.xml
  15. 4 4
      drivers/unix/file_access_unix.cpp
  16. 1 1
      drivers/unix/file_access_unix.h
  17. 5 3
      drivers/unix/file_access_unix_pipe.cpp
  18. 1 1
      drivers/unix/file_access_unix_pipe.h
  19. 4 4
      drivers/windows/file_access_windows.cpp
  20. 1 1
      drivers/windows/file_access_windows.h
  21. 5 3
      drivers/windows/file_access_windows_pipe.cpp
  22. 1 1
      drivers/windows/file_access_windows_pipe.h
  23. 20 0
      misc/extension_api_validation/4.3-stable.expected
  24. 2 2
      platform/android/file_access_android.cpp
  25. 1 1
      platform/android/file_access_android.h
  26. 10 6
      platform/android/file_access_filesystem_jandroid.cpp
  27. 1 1
      platform/android/file_access_filesystem_jandroid.h
  28. 2 1
      platform/android/java/lib/src/org/godotengine/godot/io/file/AssetData.kt
  29. 4 2
      platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
  30. 3 3
      platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt

+ 72 - 1
core/io/file_access.compat.inc

@@ -34,8 +34,79 @@ Ref<FileAccess> FileAccess::_open_encrypted_bind_compat_98918(const String &p_pa
 	return open_encrypted(p_path, p_mode_flags, p_key, Vector<uint8_t>());
 }
 
+void FileAccess::store_8_bind_compat_78289(uint8_t p_dest) {
+	store_8(p_dest);
+}
+
+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<uint8_t> &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<String> &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 // DISABLE_DEPRECATED
+#endif

+ 48 - 37
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<uint8_t *>(&p_dest), sizeof(uint16_t));
+	return store_buffer(reinterpret_cast<uint8_t *>(&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<uint8_t *>(&p_dest), sizeof(uint32_t));
+	return store_buffer(reinterpret_cast<uint8_t *>(&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<uint8_t *>(&p_dest), sizeof(uint64_t));
+	return store_buffer(reinterpret_cast<uint8_t *>(&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<String> &p_values, const String &p_delim) {
-	ERR_FAIL_COND(p_delim.length() != 1);
+bool FileAccess::store_csv_line(const Vector<String> &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<String> &p_values, const String &p_
 		line += value;
 	}
 
-	store_line(line);
+	return store_line(line);
 }
 
-void FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) {
+bool FileAccess::store_buffer(const Vector<uint8_t> &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);
+}
+
+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;
 }
 
-void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
+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<uint8_t> 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<uint8_t> 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<uint8_t> &)) & FileAccess::store_buffer);
+	ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (bool(FileAccess::*)(const Vector<uint8_t> &)) & 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);

+ 31 - 15
core/io/file_access.h

@@ -112,6 +112,21 @@ protected:
 #ifndef DISABLE_DEPRECATED
 	static Ref<FileAccess> _open_encrypted_bind_compat_98918(const String &p_path, ModeFlags p_mode_flags, const Vector<uint8_t> &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<uint8_t> &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<String> &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<String> &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<String> &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<uint8_t> &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<uint8_t> &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;
 

+ 14 - 16
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<FileAccess> 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) {

+ 1 - 1
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
 

+ 5 - 4
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() {

+ 1 - 1
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
 

+ 6 - 6
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;
 }

+ 1 - 1
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
 

+ 2 - 2
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) {

+ 1 - 1
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;
 

+ 2 - 2
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) {

+ 1 - 1
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
 

+ 27 - 14
doc/classes/FileAccess.xml

@@ -381,20 +381,22 @@
 			</description>
 		</method>
 		<method name="store_8">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="int" />
 			<description>
 				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).
 			</description>
 		</method>
 		<method name="store_16">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="int" />
 			<description>
 				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 @@
 			</description>
 		</method>
 		<method name="store_32">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="int" />
 			<description>
 				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).
 			</description>
 		</method>
 		<method name="store_64">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="int" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_buffer">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="buffer" type="PackedByteArray" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_csv_line">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="values" type="PackedStringArray" />
 			<param index="1" name="delim" type="String" default="&quot;,&quot;" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_double">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="float" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_float">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="float" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_half">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="float" />
 			<description>
 				Stores a half-precision floating-point number as 16 bits in the file.
 			</description>
 		</method>
 		<method name="store_line">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="line" type="String" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_pascal_string">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="string" type="String" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_real">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="float" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_string">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="string" type="String" />
 			<description>
 				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.
 			</description>
 		</method>
 		<method name="store_var">
-			<return type="void" />
+			<return type="bool" />
 			<param index="0" name="value" type="Variant" />
 			<param index="1" name="full_objects" type="bool" default="false" />
 			<description>
 				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.
 			</description>
 		</method>
 	</methods>

+ 4 - 4
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) {

+ 1 - 1
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
 

+ 5 - 3
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;
 	}
 }
 

+ 1 - 1
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; }
 

+ 4 - 4
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) {

+ 1 - 1
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
 

+ 5 - 3
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;
 	}
 }
 

+ 1 - 1
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; }
 

+ 20 - 0
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.

+ 2 - 2
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) {

+ 1 - 1
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
 

+ 10 - 6
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");

+ 1 - 1
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
 

+ 2 - 1
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
 	}
 }

+ 4 - 2
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
 			}
 		}
 	}

+ 3 - 3
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) {