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