diff --git a/doc/classes/FileAccess.xml b/doc/classes/FileAccess.xml
index cdfdb36511..fac9d08604 100644
--- a/doc/classes/FileAccess.xml
+++ b/doc/classes/FileAccess.xml
@@ -425,7 +425,7 @@
Sets the file cursor to the specified position in bytes, from the end of the file. This changes the value returned by [method get_position].
- [b]Note:[/b] This is an offset, so you should use negative numbers otherwise the file cursor will be at the end of the file.
+ [b]Note:[/b] This is an offset, so you should use negative numbers otherwise the file cursor will move past the end of the file.
diff --git a/platform/android/java/lib/src/main/java/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/main/java/org/godotengine/godot/io/file/DataAccess.kt
index b426decf7a..5d20e645f0 100644
--- a/platform/android/java/lib/src/main/java/org/godotengine/godot/io/file/DataAccess.kt
+++ b/platform/android/java/lib/src/main/java/org/godotengine/godot/io/file/DataAccess.kt
@@ -203,8 +203,10 @@ internal abstract class DataAccess {
abstract fun write(buffer: ByteBuffer): Boolean
fun seekFromEnd(positionFromEnd: Long) {
- val positionFromBeginning = max(0, size() - positionFromEnd)
- seek(positionFromBeginning)
+ val positionFromBeginning = size() + positionFromEnd
+ if (positionFromBeginning >= 0) {
+ seek(positionFromBeginning)
+ }
}
abstract class FileChannelDataAccess(private val filePath: String) : DataAccess() {
diff --git a/tests/core/io/test_file_access.h b/tests/core/io/test_file_access.h
index 7c6a0ab3c4..24b1bc6c54 100644
--- a/tests/core/io/test_file_access.h
+++ b/tests/core/io/test_file_access.h
@@ -248,4 +248,51 @@ TEST_CASE("[FileAccess] Get/Store floating point half precision values") {
}
}
+TEST_CASE("[FileAccess] Cursor positioning") {
+ Ref f = FileAccess::open(TestUtils::get_data_path("line_endings_lf.test.txt"), FileAccess::READ);
+ REQUIRE(f.is_valid());
+
+ String full = f->get_as_utf8_string();
+ int64_t len = full.length();
+
+ SUBCASE("Initial position is zero") {
+ f->seek(0);
+ CHECK(f->get_position() == 0);
+ }
+
+ SUBCASE("seek() moves cursor to absolute position") {
+ f->seek(5);
+ CHECK(f->get_position() == 5);
+ }
+
+ SUBCASE("seek() moves cursor beyond file size") {
+ f->seek(len + 10);
+ CHECK(f->get_position() == len + 10);
+ }
+
+ SUBCASE("seek_end() moves cursor to end of file") {
+ f->seek_end(0);
+ CHECK(f->get_position() == len);
+ }
+
+ SUBCASE("seek_end() with positive offset") {
+ f->seek_end(1);
+ CHECK(f->get_position() == len + 1);
+ }
+
+ SUBCASE("seek_end() with negative offset") {
+ f->seek_end(-1);
+ CHECK(f->get_position() == len - 1);
+
+ char last_char = full[full.length() - 1];
+ CHECK(f->get_8() == last_char);
+ }
+
+ SUBCASE("seek_end() beyond file size") {
+ f->seek(5);
+ f->seek_end(-len - 10); // seeking to a position below 0; ignored.
+ CHECK(f->get_position() == 5);
+ }
+}
+
} // namespace TestFileAccess