[Scummvm-git-logs] scummvm master -> 414d2d6952b2248558b14570299aa7f938f09aa6
spleen1981
noreply at scummvm.org
Mon Aug 17 08:20:16 UTC 2026
This automated email contains information about 14 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .
Summary:
d11c1c1dbe LIBRETRO: fix index out of bound
935378548d LIBRETRO: fix RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE handling per API contract
08077889d5 LIBRETRO: add SAF support and use libretro VFS
f7519c9150 LIBRETRO: BUILD: sync with libretro-common
576d1cf084 LIBRETRO: BUILD: sync libretro-deps
46a14961b3 LIBRETRO: add getDefaultDir
702d2f628a LIBRETRO: reset last browsed path to default if is /
603dc6653e LIBRETRO: add use of RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS
75d9049057 LIBRETRO: add use of RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY
a5e2c0f387 LIBRETRO: BUILD: sync with libretro-common
3aefd831b9 LIBRETRO: add Browsing Mode core setting
d7fb0de22d LIBRETRO: add android storage information
940c6287c0 LIBRETRO: add consistency check for last browsed path
414d2d6952 LIBRETRO: add URI parser for authorized paths labels
Commit: d11c1c1dbe16123c95a842669332a3571bb48fd1
https://github.com/scummvm/scummvm/commit/d11c1c1dbe16123c95a842669332a3571bb48fd1
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:08:09+02:00
Commit Message:
LIBRETRO: fix index out of bound
Changed paths:
backends/platform/libretro/src/libretro-core.cpp
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index 9627e4870e7..e6c13f1350f 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -660,7 +660,7 @@ uint16 retro_setting_get_audio_samples_buffer_size(void) {
for (uint16 v : allowed) {
if (pow2 <= v) return v;
}
- return allowed[sizeof(allowed)/sizeof(allowed[0])];
+ return allowed[ARRAYSIZE(allowed) - 1];
}
void init_command_params(void) {
Commit: 935378548d03322c62d870e8890863c428f94c26
https://github.com/scummvm/scummvm/commit/935378548d03322c62d870e8890863c428f94c26
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:08:45+02:00
Commit Message:
LIBRETRO: fix RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE handling per API contract
Changed paths:
backends/platform/libretro/src/libretro-core.cpp
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index e6c13f1350f..97c9eaa79ab 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -1145,7 +1145,9 @@ void retro_run(void) {
/* Setting RA's video or audio driver to null will disable video/audio bits */
int audio_video_enable = 0;
- environ_cb(RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE, &audio_video_enable);
+ if (!environ_cb(RETRO_ENVIRONMENT_GET_AUDIO_VIDEO_ENABLE, &audio_video_enable))
+ /* If this flag is not supported, the core assumes that the frontend will not skip any steps, as per API contract */
+ audio_video_enable = RETRO_AV_ENABLE_VIDEO | RETRO_AV_ENABLE_AUDIO;
if (g_system) {
/* Switch to ScummVM thread */
Commit: 08077889d5f0feb6b6fa2e4e2bf5767548cc5a9e
https://github.com/scummvm/scummvm/commit/08077889d5f0feb6b6fa2e4e2bf5767548cc5a9e
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:09:28+02:00
Commit Message:
LIBRETRO: add SAF support and use libretro VFS
Changed paths:
backends/platform/libretro/dependencies.mk
backends/platform/libretro/include/libretro-fs.h
backends/platform/libretro/jni/Android.mk
backends/platform/libretro/src/libretro-core.cpp
backends/platform/libretro/src/libretro-fs.cpp
diff --git a/backends/platform/libretro/dependencies.mk b/backends/platform/libretro/dependencies.mk
index 715f8f333f8..ea62246d8b7 100644
--- a/backends/platform/libretro/dependencies.mk
+++ b/backends/platform/libretro/dependencies.mk
@@ -46,6 +46,10 @@ OBJS_DEPS += $(DEPS_PATH)/$(DEPS_FOLDER_libretro-common)/file/file_path_io.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-common)/streams/file_stream.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-common)/features/features_cpu.o
+ifeq ($(USE_LIBRETRO_SAF),1)
+OBJS_DEPS += $(DEPS_PATH)/$(DEPS_FOLDER_libretro-common)/vfs/vfs_implementation_saf.o
+endif
+
ifeq ($(USE_LIBCO), 1)
OBJS_DEPS += $(DEPS_PATH)/$(DEPS_FOLDER_libretro-common)/libco/libco.o
diff --git a/backends/platform/libretro/include/libretro-fs.h b/backends/platform/libretro/include/libretro-fs.h
index 7541d540ee8..65eed0a1849 100644
--- a/backends/platform/libretro/include/libretro-fs.h
+++ b/backends/platform/libretro/include/libretro-fs.h
@@ -61,7 +61,7 @@ public:
LibRetroFilesystemNode(const Common::String &path);
virtual bool exists() const {
- return access(_path.c_str(), F_OK) == 0;
+ return _isValid;
}
virtual Common::U32String getDisplayName() const {
return _displayName;
diff --git a/backends/platform/libretro/jni/Android.mk b/backends/platform/libretro/jni/Android.mk
index 5cb6ab7f035..0c2ef19d2d1 100644
--- a/backends/platform/libretro/jni/Android.mk
+++ b/backends/platform/libretro/jni/Android.mk
@@ -3,6 +3,7 @@ ROOT_PATH := $(LOCAL_PATH)/..
TARGET_NAME := scummvm
HAVE_OPENGLES2 := 1
USE_IMGUI := 0
+USE_LIBRETRO_SAF := 1
# Reset flags not reset to Makefile.common
DEFINES :=
@@ -38,6 +39,11 @@ LOCAL_SRC_FILES := $(DETECT_OBJS:%.o=$(SCUMMVM_PATH)/%.cpp) $(OBJS_DEPS:%
LOCAL_C_INCLUDES := $(subst -I,,$(INCLUDES))
LOCAL_CPPFLAGS := $(COREFLAGS) -std=c++11
LOCAL_CFLAGS := $(COREFLAGS)
+ifeq ($(USE_LIBRETRO_SAF),1)
+LOCAL_CFLAGS += -DANDROID -DHAVE_SAF -DLIBRETRO_FS_DEBUG
+LOCAL_CPPFLAGS += -DANDROID -DHAVE_SAF -DLIBRETRO_FS_DEBUG
+endif
+
LOCAL_LDFLAGS := -Wl,-version-script=$(ROOT_PATH)/link.T
LOCAL_LDLIBS := -lz -llog
LOCAL_CPP_FEATURES := rtti
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index 97c9eaa79ab..1367a8d91c3 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -24,6 +24,8 @@
#include "common/fs.h"
#include "common/error.h"
#include "streams/file_stream.h"
+#include <file/file_path.h>
+#include <retro_dirent.h>
#include "graphics/surface.h"
#ifdef _WIN32
#include <direct.h>
@@ -794,6 +796,7 @@ void retro_set_input_state(retro_input_state_t cb) {
void retro_set_environment(retro_environment_t cb) {
environ_cb = cb;
+
bool tmp = true;
bool has_categories;
environ_cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &tmp);
@@ -922,6 +925,18 @@ void retro_init(void) {
else
retro_log_cb = NULL;
+ struct retro_vfs_interface_info vfs_iface;
+ vfs_iface.required_interface_version = STAT64_REQUIRED_VFS_VERSION;
+ vfs_iface.iface = nullptr;
+
+ bool vfs_ok = environ_cb(RETRO_ENVIRONMENT_GET_VFS_INTERFACE, &vfs_iface);
+
+ if (vfs_ok) {
+ filestream_vfs_init(&vfs_iface);
+ path_vfs_init(&vfs_iface);
+ dirent_vfs_init(&vfs_iface);
+ }
+
if (retro_log_cb)
retro_log_cb(RETRO_LOG_DEBUG, "ScummVM core version: %s\n", __GIT_VERSION);
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index 1934c21995f..8a392c7e6d2 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -27,31 +27,271 @@
#define FORBIDDEN_SYMBOL_EXCEPTION_getenv
#define FORBIDDEN_SYMBOL_EXCEPTION_strcat
#define FORBIDDEN_SYMBOL_EXCEPTION_strcpy
+#define FORBIDDEN_SYMBOL_EXCEPTION_strstr
#define FORBIDDEN_SYMBOL_EXCEPTION_exit // Needed for IRIX's unistd.h
+#include <libretro.h>
#include <file/file_path.h>
#include <retro_dirent.h>
-#include <retro_stat.h>
+#include <streams/file_stream.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "backends/platform/libretro/include/libretro-fs.h"
-#include "backends/fs/stdiostream.h"
#include "common/algorithm.h"
+#include "common/stream.h"
+
+static bool libretroFsHasUriScheme(const Common::String &path) {
+ return strstr(path.c_str(), "://") != nullptr;
+}
+
+static Common::String libretroFsUriDisplayName(const Common::String &path) {
+ Common::String trimmed(path);
+
+ while (trimmed.size() > 1 && trimmed.lastChar() == '/')
+ trimmed.erase(trimmed.size() - 1);
+
+ Common::String name = Common::lastPathComponent(trimmed, '/');
+ return name.empty() ? trimmed : name;
+}
+
+static int libretroFsWhenceToVfs(int whence) {
+ switch (whence) {
+ case SEEK_SET:
+ return RETRO_VFS_SEEK_POSITION_START;
+ case SEEK_CUR:
+ return RETRO_VFS_SEEK_POSITION_CURRENT;
+ case SEEK_END:
+ return RETRO_VFS_SEEK_POSITION_END;
+ default:
+ return whence;
+ }
+}
+
+class LibRetroFileReadStream final : public Common::SeekableReadStream {
+public:
+ explicit LibRetroFileReadStream(RFILE *file)
+ : _file(file), _size(file ? filestream_get_size(file) : -1),
+ _eos(false), _err(false) {
+ }
+
+ ~LibRetroFileReadStream() override {
+ close();
+ }
+
+ uint32 read(void *dataPtr, uint32 dataSize) override {
+ if (!_file || !dataPtr) {
+ _err = true;
+ return 0;
+ }
+
+ if (dataSize == 0)
+ return 0;
+
+ int64_t ret = filestream_read(_file, dataPtr, dataSize);
+
+ if (ret < 0) {
+ _err = true;
+ return 0;
+ }
+
+ // Emulate fread()/feof() behaviour closely enough for ScummVM:
+ // EOF becomes observable after a read cannot satisfy the requested size.
+ if ((uint32)ret < dataSize)
+ _eos = true;
+
+ return (uint32)ret;
+ }
+
+ bool eos() const override {
+ return _eos;
+ }
+
+ bool err() const override {
+ return _err;
+ }
+
+ void clearErr() override {
+ _eos = false;
+ _err = false;
+ }
+
+ int64 pos() const override {
+ if (!_file)
+ return -1;
+
+ int64_t ret = filestream_tell(_file);
+ return ret < 0 ? -1 : ret;
+ }
+
+ int64 size() const override {
+ if (!_file)
+ return -1;
+
+ return _size >= 0 ? _size : filestream_get_size(_file);
+ }
+
+ bool seek(int64 offs, int whence = SEEK_SET) override {
+ if (!_file) {
+ _err = true;
+ return false;
+ }
+
+ int64_t ret = filestream_seek(_file, offs, libretroFsWhenceToVfs(whence));
+
+ if (ret < 0) {
+ _err = true;
+ return false;
+ }
+
+ // ScummVM's stream contract says a successful seek clears EOF.
+ _eos = false;
+ return true;
+ }
+
+private:
+ void close() {
+ if (_file) {
+ filestream_close(_file);
+ _file = nullptr;
+ }
+ }
+
+ RFILE *_file;
+ int64 _size;
+ bool _eos;
+ bool _err;
+};
+
+class LibRetroFileWriteStream final : public Common::SeekableWriteStream {
+public:
+ explicit LibRetroFileWriteStream(RFILE *file) : _file(file), _err(false) {
+ }
+
+ ~LibRetroFileWriteStream() override {
+ close();
+ }
+
+ uint32 write(const void *dataPtr, uint32 dataSize) override {
+ if (!_file || !dataPtr) {
+ _err = true;
+ return 0;
+ }
+
+ if (dataSize == 0)
+ return 0;
+
+ int64_t ret = filestream_write(_file, dataPtr, dataSize);
+
+ if (ret < 0) {
+ _err = true;
+ return 0;
+ }
+
+ if ((uint32)ret < dataSize)
+ _err = true;
+
+ return (uint32)ret;
+ }
+
+ bool flush() override {
+ if (!_file) {
+ _err = true;
+ return false;
+ }
+
+ if (filestream_flush(_file) != 0) {
+ _err = true;
+ return false;
+ }
+
+ return true;
+ }
+
+ bool err() const override {
+ return _err;
+ }
+
+ void clearErr() override {
+ _err = false;
+ }
+
+ void finalize() override {
+ flush();
+ }
+
+ int64 pos() const override {
+ if (!_file)
+ return -1;
+
+ int64_t ret = filestream_tell(_file);
+ return ret < 0 ? -1 : ret;
+ }
+
+ int64 size() const override {
+ if (!_file)
+ return -1;
+
+ return filestream_get_size(_file);
+ }
+
+ bool seek(int64 offs, int whence = SEEK_SET) override {
+ if (!_file) {
+ _err = true;
+ return false;
+ }
+
+ if (filestream_seek(_file, offs, libretroFsWhenceToVfs(whence)) < 0) {
+ _err = true;
+ return false;
+ }
+
+ return true;
+ }
+
+private:
+ void close() {
+ if (_file) {
+ flush();
+ filestream_close(_file);
+ _file = nullptr;
+ }
+ }
+
+ RFILE *_file;
+ bool _err;
+};
void LibRetroFilesystemNode::setFlags() {
const char *fspath = _path.c_str();
+ // Keep all filesystem state queries on libretro-common VFS.
+ // This is important on Android/SAF and also keeps POSIX paths consistent
+ // with the same VFS path used later by filestream_open().
_isValid = path_is_valid(fspath);
_isDirectory = path_is_directory(fspath);
- _isReadable = access(fspath, R_OK) == 0;
- _isWritable = access(_path.c_str(), W_OK) == 0;
+
+ // libretro-common exposes stat-style validity/directory queries here, but
+ // no portable readability/writability probes. Treat valid paths as readable
+ // for ScummVM's FSNode purposes and let createReadStream()/createWriteStream()
+ // be the definitive open check.
+ _isReadable = _isValid;
+ _isWritable = _isValid;
}
LibRetroFilesystemNode::LibRetroFilesystemNode(const Common::String &p) {
assert(p.size() > 0);
+ if (libretroFsHasUriScheme(p)) {
+ _path = p;
+ _displayName = libretroFsUriDisplayName(_path);
+ setFlags();
+ return;
+ }
+
// Expand "~/" to the value of the HOME env variable
if (p.hasPrefix("~/") || p.hasPrefix("~\\")) {
Common::String homeDir = getHomeDir();
@@ -72,7 +312,6 @@ LibRetroFilesystemNode::LibRetroFilesystemNode(const Common::String &p) {
// Normalize the path (that is, remove unneeded slashes etc.)
_path = Common::normalizePath(Common::String(portable_path), '/');
_displayName = Common::lastPathComponent(_path, '/');
-
setFlags();
}
@@ -123,7 +362,6 @@ bool LibRetroFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode,
entry._isValid = true;
entry._isDirectory = retro_dirent_is_dir(dirp, entry._path.c_str());
-
// Skip files that are invalid for some reason (e.g. because we couldn't
// properly stat them).
if (!entry._isValid)
@@ -144,6 +382,50 @@ AbstractFSNode *LibRetroFilesystemNode::getParent() const {
if (_path == "/")
return 0; // The filesystem root has no parent
+ Common::String parentPath(_path);
+
+ if (libretroFsHasUriScheme(parentPath)) {
+ const char *pathStr = parentPath.c_str();
+ const char *scheme = strstr(pathStr, "://");
+ const uint schemeRootLen = scheme ? (uint)(scheme - pathStr) + 3 : 0;
+
+ // For hierarchical URI paths, keep the authority root intact.
+ // Example:
+ // smb://server/share/game -> smb://server/share/
+ // smb://server/share/ -> smb://server/
+ // smb://server/ -> /
+ uint uriRootLen = schemeRootLen;
+ if (schemeRootLen > 0) {
+ const char *authorityEnd = strchr(pathStr + schemeRootLen, '/');
+ if (authorityEnd)
+ uriRootLen = (uint)(authorityEnd - pathStr) + 1;
+ else
+ uriRootLen = parentPath.size();
+ }
+
+ while (parentPath.size() > uriRootLen && parentPath.lastChar() == '/')
+ parentPath.erase(parentPath.size() - 1);
+
+ if (parentPath.size() <= uriRootLen) {
+ return makeNode("/");
+ }
+
+ size_t pos = parentPath.findLastOf('/');
+ if (pos == Common::String::npos || pos + 1 <= uriRootLen)
+ parentPath = parentPath.substr(0, uriRootLen);
+ else
+ parentPath = parentPath.substr(0, pos + 1);
+
+ AbstractFSNode *parent = makeNode(parentPath);
+
+ if (parent && parent->isDirectory() == false) {
+ delete parent;
+ return 0;
+ }
+
+ return parent;
+ }
+
const char *start = _path.c_str();
const char *end = start + _path.size();
@@ -156,20 +438,34 @@ AbstractFSNode *LibRetroFilesystemNode::getParent() const {
return 0;
}
- AbstractFSNode *parent = makeNode(Common::String(start, end));
+ Common::String posixParentPath(start, end);
- if (parent->isDirectory() == false)
+ AbstractFSNode *parent = makeNode(posixParentPath);
+
+ if (parent->isDirectory() == false) {
+ delete parent;
return 0;
+ }
return parent;
}
Common::SeekableReadStream *LibRetroFilesystemNode::createReadStream() {
- return StdioStream::makeFromPath(getPath(), StdioStream::WriteMode_Read);
+ RFILE *file = filestream_open(getPath().c_str(), RETRO_VFS_FILE_ACCESS_READ, RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+ if (!file)
+ return nullptr;
+ return new LibRetroFileReadStream(file);
}
Common::SeekableWriteStream *LibRetroFilesystemNode::createWriteStream(bool atomic) {
- return StdioStream::makeFromPath(getPath(), atomic ? StdioStream::WriteMode_WriteAtomic : StdioStream::WriteMode_Write);
+ (void)atomic;
+ RFILE *file = filestream_open(getPath().c_str(), RETRO_VFS_FILE_ACCESS_WRITE, RETRO_VFS_FILE_ACCESS_HINT_NONE);
+
+ if (!file)
+ return nullptr;
+
+ return new LibRetroFileWriteStream(file);
}
bool LibRetroFilesystemNode::createDirectory() {
Commit: f7519c91508f4d401b085c9ecb6f32898efaf58c
https://github.com/scummvm/scummvm/commit/f7519c91508f4d401b085c9ecb6f32898efaf58c
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:09:57+02:00
Commit Message:
LIBRETRO: BUILD: sync with libretro-common
Changed paths:
backends/platform/libretro/dependencies.mk
diff --git a/backends/platform/libretro/dependencies.mk b/backends/platform/libretro/dependencies.mk
index ea62246d8b7..1f90b7cbb39 100644
--- a/backends/platform/libretro/dependencies.mk
+++ b/backends/platform/libretro/dependencies.mk
@@ -11,7 +11,7 @@ DEPS_COMMIT_libretro-deps := 7e6e34f0319f4c7448d72f0e949e76265ccf55a1
DEPS_FOLDER_libretro-common := libretro-common
DEPS_URL_libretro-common := https://github.com/libretro/libretro-common
-DEPS_COMMIT_libretro-common := 70ed90c42ddea828f53dd1b984c6443ddb39dbd6
+DEPS_COMMIT_libretro-common := 692124dbd8a0b2f5526b48f3bc2026421754e3c5
submodule_test = $(if $(shell result=$$($(SCRIPTS_PATH)/configure_submodules.sh $(DEPS_URL_$(1)) $(DEPS_COMMIT_$(1)) $(DEPS_PATH) $(DEBUG_ALLOW_DIRTY_SUBMODULES) $(DEPS_FOLDER_$(1))) ; { [ -z $$result ] || [ ! $$result = 0 ] ; } && printf error),$(1))
$(info Configuring submodules...)
Commit: 576d1cf08474f8d01493debed3121e20e9d8abf2
https://github.com/scummvm/scummvm/commit/576d1cf08474f8d01493debed3121e20e9d8abf2
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:10:24+02:00
Commit Message:
LIBRETRO: BUILD: sync libretro-deps
Changed paths:
backends/platform/libretro/dependencies.mk
diff --git a/backends/platform/libretro/dependencies.mk b/backends/platform/libretro/dependencies.mk
index 1f90b7cbb39..4ac9f221e7d 100644
--- a/backends/platform/libretro/dependencies.mk
+++ b/backends/platform/libretro/dependencies.mk
@@ -7,7 +7,7 @@ DEPS_SUBMODULES := libretro-deps libretro-common
DEPS_FOLDER_libretro-deps := libretro-deps
DEPS_URL_libretro-deps := https://github.com/libretro/libretro-deps
-DEPS_COMMIT_libretro-deps := 7e6e34f0319f4c7448d72f0e949e76265ccf55a1
+DEPS_COMMIT_libretro-deps := bab7d258c451c0e7cba4b6a79f1b062c13efff38
DEPS_FOLDER_libretro-common := libretro-common
DEPS_URL_libretro-common := https://github.com/libretro/libretro-common
@@ -214,16 +214,16 @@ this_lib_header := zlib.h
this_lib_flags := -lz
include $(ROOT_PATH)/sharedlib_test.mk
ifneq ($(this_lib_available), yes)
+INCLUDES += -I$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz
OBJS_DEPS += $(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/deflate.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/gzlib.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/uncompr.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/zutil.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/inffast.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/gzread.o \
- $(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/crc32.o \
+ $(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/libz-crc32.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/gzwrite.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/inflate.o \
- $(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/infback.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/inftrees.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/trees.o \
$(DEPS_PATH)/$(DEPS_FOLDER_libretro-deps)/libz/gzclose.o \
Commit: 46a14961b3d4599d8795536fe9e630882983c3ca
https://github.com/scummvm/scummvm/commit/46a14961b3d4599d8795536fe9e630882983c3ca
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:10:48+02:00
Commit Message:
LIBRETRO: add getDefaultDir
Changed paths:
backends/platform/libretro/include/libretro-fs.h
backends/platform/libretro/src/libretro-fs-factory.cpp
backends/platform/libretro/src/libretro-fs.cpp
backends/platform/libretro/src/libretro-os-utils.cpp
diff --git a/backends/platform/libretro/include/libretro-fs.h b/backends/platform/libretro/include/libretro-fs.h
index 65eed0a1849..1dea0fd99af 100644
--- a/backends/platform/libretro/include/libretro-fs.h
+++ b/backends/platform/libretro/include/libretro-fs.h
@@ -91,6 +91,7 @@ public:
virtual bool createDirectory();
static Common::String getHomeDir(void);
+ static Common::String getDefaultDir(void);
private:
/**
* Tests and sets the _isValid and _isDirectory flags, using the stat() function.
diff --git a/backends/platform/libretro/src/libretro-fs-factory.cpp b/backends/platform/libretro/src/libretro-fs-factory.cpp
index 02ee0e7a80c..772b1c5e625 100644
--- a/backends/platform/libretro/src/libretro-fs-factory.cpp
+++ b/backends/platform/libretro/src/libretro-fs-factory.cpp
@@ -39,11 +39,7 @@ AbstractFSNode *LibRetroFilesystemFactory::makeCurrentDirectoryFileNode() const
#ifdef PLAYSTATION3
return new LibRetroFilesystemNode("/");
#else
- char *cwd = getcwd(NULL, 0);
- AbstractFSNode *node = cwd ? new LibRetroFilesystemNode(Common::String(cwd)) : NULL;
- if (cwd)
- free(cwd);
- return node;
+ return new LibRetroFilesystemNode(LibRetroFilesystemNode::getDefaultDir());
#endif
}
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index 8a392c7e6d2..08dd4ef86d8 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -41,6 +41,7 @@
#include <string.h>
#include "backends/platform/libretro/include/libretro-fs.h"
+#include "backends/platform/libretro/include/libretro-core.h"
#include "common/algorithm.h"
#include "common/stream.h"
@@ -557,3 +558,26 @@ Common::String LibRetroFilesystemNode::getHomeDir(void) {
return path;
}
+
+Common::String LibRetroFilesystemNode::getDefaultDir(void) {
+ Common::String homeDir(getHomeDir());
+
+ if (!homeDir.empty() && LibRetroFilesystemNode(homeDir).isDirectory())
+ return homeDir;
+
+ const char *systemDir = retro_get_system_dir();
+ if (systemDir && *systemDir) {
+ Common::String path(systemDir);
+ if (LibRetroFilesystemNode(path).isDirectory())
+ return path;
+ }
+
+ const char *saveDir = retro_get_save_dir();
+ if (saveDir && *saveDir) {
+ Common::String path(saveDir);
+ if (LibRetroFilesystemNode(path).isDirectory())
+ return path;
+ }
+
+ return Common::String("/");
+}
diff --git a/backends/platform/libretro/src/libretro-os-utils.cpp b/backends/platform/libretro/src/libretro-os-utils.cpp
index 4ff64a9d2c7..644df8cae20 100644
--- a/backends/platform/libretro/src/libretro-os-utils.cpp
+++ b/backends/platform/libretro/src/libretro-os-utils.cpp
@@ -190,7 +190,7 @@ void OSystem_libretro::setLibretroDir(const char *path, Common::String &var) {
void OSystem_libretro::applyBackendSettings() {
/* ScummVM paths checks at startup and on settings applied */
- Common::String s_homeDir(LibRetroFilesystemNode::getHomeDir());
+ Common::String s_homeDir(LibRetroFilesystemNode::getDefaultDir());
Common::String s_themeDir(s_systemDir + "/" + SCUMMVM_SYSTEM_SUBDIR + "/" + SCUMMVM_THEME_SUBDIR);
Common::String s_extraDir(s_systemDir + "/" + SCUMMVM_SYSTEM_SUBDIR + "/" + SCUMMVM_EXTRA_SUBDIR);
Common::String s_soundfontPath(s_extraDir + "/" + DEFAULT_SOUNDFONT_FILENAME);
@@ -201,8 +201,6 @@ void OSystem_libretro::applyBackendSettings() {
s_extraDir.clear();
if (! LibRetroFilesystemNode(s_soundfontPath).exists())
s_soundfontPath.clear();
- if (s_homeDir.empty() || ! LibRetroFilesystemNode(s_homeDir).isDirectory())
- s_homeDir = s_systemDir;
//Register default paths
if (! s_homeDir.empty()) {
Commit: 702d2f628a6cd08cede5797f4de1c8372ddc7612
https://github.com/scummvm/scummvm/commit/702d2f628a6cd08cede5797f4de1c8372ddc7612
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:11:09+02:00
Commit Message:
LIBRETRO: reset last browsed path to default if is /
Changed paths:
backends/platform/libretro/src/libretro-os-utils.cpp
diff --git a/backends/platform/libretro/src/libretro-os-utils.cpp b/backends/platform/libretro/src/libretro-os-utils.cpp
index 644df8cae20..e1e10381e99 100644
--- a/backends/platform/libretro/src/libretro-os-utils.cpp
+++ b/backends/platform/libretro/src/libretro-os-utils.cpp
@@ -170,8 +170,11 @@ bool OSystem_libretro::checkPathSetting(const char *setting, Common::String cons
Common::String setPath;
if (ConfMan.hasKey(setting))
setPath = Common::Path::fromConfig(ConfMan.get(setting)).toString();
- if (setPath.empty() || !(isDirectory ? LibRetroFilesystemNode(setPath).isDirectory() : LibRetroFilesystemNode(setPath).exists()))
+ if (!strcmp(setting, "browser_lastpath") && setPath == "/" && !defaultPath.empty() && defaultPath != "/")
ConfMan.removeKey(setting, Common::ConfigManager::kApplicationDomain);
+ else if (setPath.empty() || !(isDirectory ? LibRetroFilesystemNode(setPath).isDirectory() : LibRetroFilesystemNode(setPath).exists()))
+ ConfMan.removeKey(setting, Common::ConfigManager::kApplicationDomain);
+
if (! ConfMan.hasKey(setting))
if (defaultPath.empty())
return false;
Commit: 603dc6653e85ae566d8c6535b01b06e3b4f36d0c
https://github.com/scummvm/scummvm/commit/603dc6653e85ae566d8c6535b01b06e3b4f36d0c
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:11:26+02:00
Commit Message:
LIBRETRO: add use of RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS
Changed paths:
backends/platform/libretro/include/libretro-fs.h
backends/platform/libretro/src/libretro-core.cpp
backends/platform/libretro/src/libretro-fs-factory.cpp
backends/platform/libretro/src/libretro-fs.cpp
diff --git a/backends/platform/libretro/include/libretro-fs.h b/backends/platform/libretro/include/libretro-fs.h
index 1dea0fd99af..34fba406196 100644
--- a/backends/platform/libretro/include/libretro-fs.h
+++ b/backends/platform/libretro/include/libretro-fs.h
@@ -92,6 +92,10 @@ public:
static Common::String getHomeDir(void);
static Common::String getDefaultDir(void);
+ static Common::String getAuthorizedRootPath(void);
+ static void clearAuthorizedLocations(void);
+ static void addAuthorizedLocation(const Common::String &path, const Common::String &label);
+ static bool hasAuthorizedLocations(void);
private:
/**
* Tests and sets the _isValid and _isDirectory flags, using the stat() function.
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index 1367a8d91c3..f5c5d0bccdf 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -56,8 +56,25 @@
#include "backends/platform/libretro/include/libretro-threads.h"
#include "backends/platform/libretro/include/libretro-core-options.h"
#include "backends/platform/libretro/include/libretro-os.h"
+#include "backends/platform/libretro/include/libretro-fs.h"
#include "backends/platform/libretro/include/libretro-mapper.h"
+#ifndef RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS
+#define RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS (93 | RETRO_ENVIRONMENT_EXPERIMENTAL)
+
+struct retro_vfs_authorized_location {
+ const char *path;
+ const char *label;
+ unsigned flags;
+};
+
+struct retro_vfs_authorized_locations {
+ const struct retro_vfs_authorized_location *locations;
+ size_t count;
+};
+#endif
+
+
static struct retro_game_info game_buf;
static struct retro_game_info *game_buf_ptr;
@@ -937,6 +954,26 @@ void retro_init(void) {
dirent_vfs_init(&vfs_iface);
}
+ LibRetroFilesystemNode::clearAuthorizedLocations();
+
+ {
+ struct retro_vfs_authorized_locations locations;
+ memset(&locations, 0, sizeof(locations));
+
+ if (environ_cb && environ_cb(RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS, &locations) &&
+ locations.locations) {
+ for (size_t i = 0; i < locations.count; ++i) {
+ const char *path = locations.locations[i].path;
+ const char *label = locations.locations[i].label;
+
+ if (path && *path)
+ LibRetroFilesystemNode::addAuthorizedLocation(
+ Common::String(path),
+ label ? Common::String(label) : Common::String());
+ }
+ }
+ }
+
if (retro_log_cb)
retro_log_cb(RETRO_LOG_DEBUG, "ScummVM core version: %s\n", __GIT_VERSION);
diff --git a/backends/platform/libretro/src/libretro-fs-factory.cpp b/backends/platform/libretro/src/libretro-fs-factory.cpp
index 772b1c5e625..931d4f20f66 100644
--- a/backends/platform/libretro/src/libretro-fs-factory.cpp
+++ b/backends/platform/libretro/src/libretro-fs-factory.cpp
@@ -32,6 +32,9 @@
#include "backends/platform/libretro/include/libretro-fs.h"
AbstractFSNode *LibRetroFilesystemFactory::makeRootFileNode() const {
+ if (LibRetroFilesystemNode::hasAuthorizedLocations())
+ return new LibRetroFilesystemNode(LibRetroFilesystemNode::getAuthorizedRootPath());
+
return new LibRetroFilesystemNode("/");
}
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index 08dd4ef86d8..14ed814a53d 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -43,8 +43,57 @@
#include "backends/platform/libretro/include/libretro-fs.h"
#include "backends/platform/libretro/include/libretro-core.h"
#include "common/algorithm.h"
+#include "common/array.h"
#include "common/stream.h"
+static const char *kLibRetroAuthorizedRootPath = "libretro-authorized:///";
+static const char *kLibRetroAuthorizedRootLabel = "RetroArch authorized locations";
+
+struct LibRetroAuthorizedLocation {
+ Common::String path;
+ Common::String label;
+};
+
+static Common::Array<LibRetroAuthorizedLocation> s_libretroAuthorizedLocations;
+
+static Common::String libretroFsStripTrailingSlash(Common::String path) {
+ while (path.size() > 1 && path.lastChar() == '/')
+ path.erase(path.size() - 1);
+
+ return path;
+}
+
+static bool libretroFsSamePath(const Common::String &a, const Common::String &b) {
+ return libretroFsStripTrailingSlash(a).equals(libretroFsStripTrailingSlash(b));
+}
+
+static bool libretroFsIsAuthorizedRoot(const Common::String &path) {
+ Common::String normalizedPath = libretroFsStripTrailingSlash(path);
+
+ for (uint i = 0; i < s_libretroAuthorizedLocations.size(); ++i) {
+ if (normalizedPath.equals(libretroFsStripTrailingSlash(s_libretroAuthorizedLocations[i].path)))
+ return true;
+ }
+
+ return false;
+}
+
+static bool libretroFsIsInsideAuthorizedLocation(const Common::String &path) {
+ Common::String normalizedPath = libretroFsStripTrailingSlash(path);
+
+ for (uint i = 0; i < s_libretroAuthorizedLocations.size(); ++i) {
+ Common::String root = libretroFsStripTrailingSlash(s_libretroAuthorizedLocations[i].path);
+
+ if (normalizedPath.equals(root))
+ return true;
+
+ if (normalizedPath.hasPrefix(root) && normalizedPath.size() > root.size() && normalizedPath[root.size()] == '/')
+ return true;
+ }
+
+ return false;
+}
+
static bool libretroFsHasUriScheme(const Common::String &path) {
return strstr(path.c_str(), "://") != nullptr;
}
@@ -286,6 +335,16 @@ void LibRetroFilesystemNode::setFlags() {
LibRetroFilesystemNode::LibRetroFilesystemNode(const Common::String &p) {
assert(p.size() > 0);
+ if (p.equals(kLibRetroAuthorizedRootPath)) {
+ _path = p;
+ _displayName = kLibRetroAuthorizedRootLabel;
+ _isValid = true;
+ _isDirectory = true;
+ _isReadable = true;
+ _isWritable = false;
+ return;
+ }
+
if (libretroFsHasUriScheme(p)) {
_path = p;
_displayName = libretroFsUriDisplayName(_path);
@@ -336,6 +395,27 @@ AbstractFSNode *LibRetroFilesystemNode::getChild(const Common::String &n) const
bool LibRetroFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, bool hidden) const {
assert(_isDirectory);
+ if (_path.equals(kLibRetroAuthorizedRootPath)) {
+ if (mode == Common::FSNode::kListFilesOnly)
+ return true;
+
+ for (uint i = 0; i < s_libretroAuthorizedLocations.size(); ++i) {
+ LibRetroFilesystemNode *node = new LibRetroFilesystemNode(s_libretroAuthorizedLocations[i].path);
+
+ if (!node->isDirectory()) {
+ delete node;
+ continue;
+ }
+
+ if (!s_libretroAuthorizedLocations[i].label.empty())
+ node->_displayName = s_libretroAuthorizedLocations[i].label;
+
+ myList.push_back(node);
+ }
+
+ return true;
+ }
+
struct RDIR *dirp = retro_opendir(_path.c_str());
if (dirp == NULL)
@@ -380,9 +460,12 @@ bool LibRetroFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode,
}
AbstractFSNode *LibRetroFilesystemNode::getParent() const {
- if (_path == "/")
+ if (_path == "/" || _path.equals(kLibRetroAuthorizedRootPath))
return 0; // The filesystem root has no parent
+ if (hasAuthorizedLocations() && libretroFsIsAuthorizedRoot(_path))
+ return makeNode(kLibRetroAuthorizedRootPath);
+
Common::String parentPath(_path);
if (libretroFsHasUriScheme(parentPath)) {
@@ -408,6 +491,9 @@ AbstractFSNode *LibRetroFilesystemNode::getParent() const {
parentPath.erase(parentPath.size() - 1);
if (parentPath.size() <= uriRootLen) {
+ if (hasAuthorizedLocations() && (parentPath.hasPrefix("saf://") || libretroFsIsInsideAuthorizedLocation(_path)))
+ return makeNode(kLibRetroAuthorizedRootPath);
+
return makeNode("/");
}
@@ -559,7 +645,46 @@ Common::String LibRetroFilesystemNode::getHomeDir(void) {
return path;
}
+Common::String LibRetroFilesystemNode::getAuthorizedRootPath(void) {
+ return Common::String(kLibRetroAuthorizedRootPath);
+}
+
+void LibRetroFilesystemNode::clearAuthorizedLocations(void) {
+ s_libretroAuthorizedLocations.clear();
+}
+
+void LibRetroFilesystemNode::addAuthorizedLocation(const Common::String &path, const Common::String &label) {
+ if (path.empty())
+ return;
+
+ for (uint i = 0; i < s_libretroAuthorizedLocations.size(); ++i) {
+ if (libretroFsSamePath(s_libretroAuthorizedLocations[i].path, path))
+ return;
+ }
+
+ LibRetroFilesystemNode node(path);
+ if (!node.isDirectory())
+ return;
+
+ LibRetroAuthorizedLocation location;
+ location.path = path;
+
+ if (!label.empty())
+ location.label = label;
+ else
+ location.label = libretroFsUriDisplayName(path);
+
+ s_libretroAuthorizedLocations.push_back(location);
+}
+
+bool LibRetroFilesystemNode::hasAuthorizedLocations(void) {
+ return !s_libretroAuthorizedLocations.empty();
+}
+
Common::String LibRetroFilesystemNode::getDefaultDir(void) {
+ if (hasAuthorizedLocations())
+ return s_libretroAuthorizedLocations[0].path;
+
Common::String homeDir(getHomeDir());
if (!homeDir.empty() && LibRetroFilesystemNode(homeDir).isDirectory())
Commit: 75d9049057d9a9a99c581414f1f2dca833975e45
https://github.com/scummvm/scummvm/commit/75d9049057d9a9a99c581414f1f2dca833975e45
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:11:45+02:00
Commit Message:
LIBRETRO: add use of RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY
Changed paths:
backends/platform/libretro/include/libretro-core.h
backends/platform/libretro/src/libretro-core.cpp
backends/platform/libretro/src/libretro-fs.cpp
diff --git a/backends/platform/libretro/include/libretro-core.h b/backends/platform/libretro/include/libretro-core.h
index c1e8bbdc083..f5b8818b2f7 100644
--- a/backends/platform/libretro/include/libretro-core.h
+++ b/backends/platform/libretro/include/libretro-core.h
@@ -29,6 +29,7 @@ void retro_osd_notification(const char *msg);
int retro_get_input_device(void);
const char *retro_get_core_dir(void);
const char *retro_get_system_dir(void);
+const char *retro_get_file_browser_start_dir(void);
const char *retro_get_save_dir(void);
const char *retro_get_playlist_dir(void);
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index f5c5d0bccdf..93e2e48bdd3 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -884,6 +884,15 @@ const char *retro_get_system_dir(void) {
return sysdir;
}
+const char *retro_get_file_browser_start_dir(void) {
+ const char *startdir = NULL;
+
+ if (!environ_cb || !environ_cb(RETRO_ENVIRONMENT_GET_FILE_BROWSER_START_DIRECTORY, &startdir))
+ return NULL;
+
+ return startdir;
+}
+
const char *retro_get_save_dir(void) {
const char *savedir = NULL;
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index 14ed814a53d..9f7d91e5210 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -685,6 +685,13 @@ Common::String LibRetroFilesystemNode::getDefaultDir(void) {
if (hasAuthorizedLocations())
return s_libretroAuthorizedLocations[0].path;
+ const char *browserStartDir = retro_get_file_browser_start_dir();
+ if (browserStartDir && *browserStartDir) {
+ Common::String path(browserStartDir);
+ if (LibRetroFilesystemNode(path).isDirectory())
+ return path;
+ }
+
Common::String homeDir(getHomeDir());
if (!homeDir.empty() && LibRetroFilesystemNode(homeDir).isDirectory())
Commit: a5e2c0f38704c43edd69bebf9dd0a1556455091b
https://github.com/scummvm/scummvm/commit/a5e2c0f38704c43edd69bebf9dd0a1556455091b
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:12:08+02:00
Commit Message:
LIBRETRO: BUILD: sync with libretro-common
Changed paths:
backends/platform/libretro/dependencies.mk
backends/platform/libretro/src/libretro-core.cpp
diff --git a/backends/platform/libretro/dependencies.mk b/backends/platform/libretro/dependencies.mk
index 4ac9f221e7d..b518997300f 100644
--- a/backends/platform/libretro/dependencies.mk
+++ b/backends/platform/libretro/dependencies.mk
@@ -11,7 +11,7 @@ DEPS_COMMIT_libretro-deps := bab7d258c451c0e7cba4b6a79f1b062c13efff38
DEPS_FOLDER_libretro-common := libretro-common
DEPS_URL_libretro-common := https://github.com/libretro/libretro-common
-DEPS_COMMIT_libretro-common := 692124dbd8a0b2f5526b48f3bc2026421754e3c5
+DEPS_COMMIT_libretro-common := 879c8d507b0b52e77e27d759239c2b5df1e26dfd
submodule_test = $(if $(shell result=$$($(SCRIPTS_PATH)/configure_submodules.sh $(DEPS_URL_$(1)) $(DEPS_COMMIT_$(1)) $(DEPS_PATH) $(DEBUG_ALLOW_DIRTY_SUBMODULES) $(DEPS_FOLDER_$(1))) ; { [ -z $$result ] || [ ! $$result = 0 ] ; } && printf error),$(1))
$(info Configuring submodules...)
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index 93e2e48bdd3..d15e4d76114 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -59,22 +59,6 @@
#include "backends/platform/libretro/include/libretro-fs.h"
#include "backends/platform/libretro/include/libretro-mapper.h"
-#ifndef RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS
-#define RETRO_ENVIRONMENT_GET_VFS_AUTHORIZED_LOCATIONS (93 | RETRO_ENVIRONMENT_EXPERIMENTAL)
-
-struct retro_vfs_authorized_location {
- const char *path;
- const char *label;
- unsigned flags;
-};
-
-struct retro_vfs_authorized_locations {
- const struct retro_vfs_authorized_location *locations;
- size_t count;
-};
-#endif
-
-
static struct retro_game_info game_buf;
static struct retro_game_info *game_buf_ptr;
Commit: 3aefd831b94fa3ac51d316e2eaf399853bb3b418
https://github.com/scummvm/scummvm/commit/3aefd831b94fa3ac51d316e2eaf399853bb3b418
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:19:01+02:00
Commit Message:
LIBRETRO: add Browsing Mode core setting
Changed paths:
backends/platform/libretro/include/libretro-core-options-intl.h
backends/platform/libretro/include/libretro-core-options.h
backends/platform/libretro/include/libretro-core.h
backends/platform/libretro/include/libretro-fs.h
backends/platform/libretro/src/libretro-core.cpp
backends/platform/libretro/src/libretro-fs-factory.cpp
backends/platform/libretro/src/libretro-fs.cpp
backends/platform/libretro/src/libretro-os-utils.cpp
diff --git a/backends/platform/libretro/include/libretro-core-options-intl.h b/backends/platform/libretro/include/libretro-core-options-intl.h
index ac8bfeffe87..37362bb3c3d 100644
--- a/backends/platform/libretro/include/libretro-core-options-intl.h
+++ b/backends/platform/libretro/include/libretro-core-options-intl.h
@@ -90,6 +90,11 @@ struct retro_core_option_v2_category option_cats_it[] = {
"Mappatura RetroPad",
"Configura la mappatura del RetroPad"
},
+ {
+ "system",
+ "Sistema",
+ "Configura le impostazioni di sistema"
+ },
{ NULL, NULL, NULL },
};
@@ -534,6 +539,20 @@ struct retro_core_option_v2_definition option_defs_it[] = {
NULL,
},
#endif
+ {
+ "scummvm_browsing_mode",
+ "Sistema > Modalità di navigazione",
+ "Modalità di navigazione",
+ "Seleziona come il file browser di ScummVM elenca le posizioni. 'Archiviazione autorizzata' mostra le cartelle autorizzate tramite il frontend (es. tree SAF di Android). 'File system locale' naviga i percorsi locali standard.",
+ NULL,
+ NULL,
+ {
+ {"local", "File system locale"},
+ {"authorized", "Archiviazione autorizzata"},
+ {NULL, NULL},
+ },
+ NULL
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};
struct retro_core_options_v2 options_it = {
diff --git a/backends/platform/libretro/include/libretro-core-options.h b/backends/platform/libretro/include/libretro-core-options.h
index dfb9ee36448..cdc8635b688 100644
--- a/backends/platform/libretro/include/libretro-core-options.h
+++ b/backends/platform/libretro/include/libretro-core-options.h
@@ -92,6 +92,11 @@ struct retro_core_option_v2_category option_cats_us[] = {
"RetroPad mapping",
"Configure RetroPad mapping"
},
+ {
+ "system",
+ "System",
+ "Configure system settings"
+ },
{ NULL, NULL, NULL },
};
@@ -613,6 +618,24 @@ struct retro_core_option_v2_definition option_defs_us[] = {
"720"
},
#endif
+ {
+ "scummvm_browsing_mode",
+ "System > Browsing mode",
+ "Browsing mode",
+ "Select how the ScummVM file browser lists locations. 'Authorized storage' shows the folders authorized through the frontend (e.g. Android SAF trees). 'Local filesystem' browses the standard local paths.",
+ NULL,
+ "system",
+ {
+ {"local", "Local filesystem"},
+ {"authorized", "Authorized storage"},
+ {NULL, NULL},
+ },
+#ifdef ANDROID
+ "authorized"
+#else
+ "local"
+#endif
+ },
{ NULL, NULL, NULL, NULL, NULL, NULL, {{0}}, NULL },
};
diff --git a/backends/platform/libretro/include/libretro-core.h b/backends/platform/libretro/include/libretro-core.h
index f5b8818b2f7..85bf9f53457 100644
--- a/backends/platform/libretro/include/libretro-core.h
+++ b/backends/platform/libretro/include/libretro-core.h
@@ -35,6 +35,7 @@ const char *retro_get_playlist_dir(void);
float retro_setting_get_frame_rate(void);
uint16 retro_setting_get_sample_rate(void);
+bool retro_setting_get_browsing_mode_authorized(void);
uint16 retro_setting_get_audio_samples_buffer_size(void);
int retro_setting_get_analog_deadzone(void);
bool retro_setting_get_analog_response_is_quadratic(void);
diff --git a/backends/platform/libretro/include/libretro-fs.h b/backends/platform/libretro/include/libretro-fs.h
index 34fba406196..3d2ad414941 100644
--- a/backends/platform/libretro/include/libretro-fs.h
+++ b/backends/platform/libretro/include/libretro-fs.h
@@ -96,6 +96,7 @@ public:
static void clearAuthorizedLocations(void);
static void addAuthorizedLocation(const Common::String &path, const Common::String &label);
static bool hasAuthorizedLocations(void);
+ static bool useAuthorizedRoot(void);
private:
/**
* Tests and sets the _isValid and _isDirectory flags, using the stat() function.
diff --git a/backends/platform/libretro/src/libretro-core.cpp b/backends/platform/libretro/src/libretro-core.cpp
index d15e4d76114..56fc7048724 100644
--- a/backends/platform/libretro/src/libretro-core.cpp
+++ b/backends/platform/libretro/src/libretro-core.cpp
@@ -107,6 +107,7 @@ static retro_time_t audio_last_time_usec = 0; // timestamp of the previous audio
static int16 *audio_sample_buffer = NULL; // pointer to output buffer
static bool input_bitmask_supported = false;
+static bool browsing_mode_authorized = false;
static bool updating_variables = false;
#ifdef USE_OPENGL
@@ -366,6 +367,17 @@ static void update_variables(void) {
} else
sample_rate = DEFAULT_SAMPLE_RATE;
+ var.key = "scummvm_browsing_mode";
+ var.value = NULL;
+ if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value)
+ browsing_mode_authorized = (strcmp(var.value, "authorized") == 0);
+ else
+#ifdef ANDROID
+ browsing_mode_authorized = true;
+#else
+ browsing_mode_authorized = false;
+#endif
+
var.key = "scummvm_mapper_up";
var.value = NULL;
if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) {
@@ -645,6 +657,10 @@ uint16 retro_setting_get_sample_rate(void) {
return sample_rate;
}
+bool retro_setting_get_browsing_mode_authorized(void) {
+ return browsing_mode_authorized;
+}
+
static uint32 next_pow2(uint32 x) {
if (x <= 1) return 1;
@@ -971,6 +987,13 @@ void retro_init(void) {
retro_log_cb(RETRO_LOG_DEBUG, "ScummVM core version: %s\n", __GIT_VERSION);
update_variables();
+
+ if (retro_setting_get_browsing_mode_authorized() && !LibRetroFilesystemNode::hasAuthorizedLocations()) {
+ if (retro_log_cb)
+ retro_log_cb(RETRO_LOG_WARN, "[scummvm] Browsing mode set to 'Authorized storage' but no authorized locations are available; falling back to local filesystem. Authorize folders from the frontend and restart the core.\n");
+ retro_osd_notification("No authorized storage available, using local filesystem.");
+ }
+
max_width = gui_width > max_width ? gui_width : max_width;
max_height = gui_height > max_height ? gui_height : max_height;
diff --git a/backends/platform/libretro/src/libretro-fs-factory.cpp b/backends/platform/libretro/src/libretro-fs-factory.cpp
index 931d4f20f66..fc2e1749ff1 100644
--- a/backends/platform/libretro/src/libretro-fs-factory.cpp
+++ b/backends/platform/libretro/src/libretro-fs-factory.cpp
@@ -32,7 +32,7 @@
#include "backends/platform/libretro/include/libretro-fs.h"
AbstractFSNode *LibRetroFilesystemFactory::makeRootFileNode() const {
- if (LibRetroFilesystemNode::hasAuthorizedLocations())
+ if (LibRetroFilesystemNode::useAuthorizedRoot())
return new LibRetroFilesystemNode(LibRetroFilesystemNode::getAuthorizedRootPath());
return new LibRetroFilesystemNode("/");
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index 9f7d91e5210..107474c4546 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -45,9 +45,10 @@
#include "common/algorithm.h"
#include "common/array.h"
#include "common/stream.h"
+#include "common/config-manager.h"
static const char *kLibRetroAuthorizedRootPath = "libretro-authorized:///";
-static const char *kLibRetroAuthorizedRootLabel = "RetroArch authorized locations";
+static const char *kLibRetroAuthorizedRootLabel = "Authorized storage";
struct LibRetroAuthorizedLocation {
Common::String path;
@@ -94,6 +95,8 @@ static bool libretroFsIsInsideAuthorizedLocation(const Common::String &path) {
return false;
}
+static Common::String libretroFsPosixDefaultDir();
+
static bool libretroFsHasUriScheme(const Common::String &path) {
return strstr(path.c_str(), "://") != nullptr;
}
@@ -681,10 +684,7 @@ bool LibRetroFilesystemNode::hasAuthorizedLocations(void) {
return !s_libretroAuthorizedLocations.empty();
}
-Common::String LibRetroFilesystemNode::getDefaultDir(void) {
- if (hasAuthorizedLocations())
- return s_libretroAuthorizedLocations[0].path;
-
+static Common::String libretroFsPosixDefaultDir() {
const char *browserStartDir = retro_get_file_browser_start_dir();
if (browserStartDir && *browserStartDir) {
Common::String path(browserStartDir);
@@ -692,7 +692,7 @@ Common::String LibRetroFilesystemNode::getDefaultDir(void) {
return path;
}
- Common::String homeDir(getHomeDir());
+ Common::String homeDir(LibRetroFilesystemNode::getHomeDir());
if (!homeDir.empty() && LibRetroFilesystemNode(homeDir).isDirectory())
return homeDir;
@@ -713,3 +713,17 @@ Common::String LibRetroFilesystemNode::getDefaultDir(void) {
return Common::String("/");
}
+
+bool LibRetroFilesystemNode::useAuthorizedRoot(void) {
+ if (!hasAuthorizedLocations())
+ return false;
+
+ return retro_setting_get_browsing_mode_authorized();
+}
+
+Common::String LibRetroFilesystemNode::getDefaultDir(void) {
+ if (useAuthorizedRoot())
+ return getAuthorizedRootPath();
+
+ return libretroFsPosixDefaultDir();
+}
diff --git a/backends/platform/libretro/src/libretro-os-utils.cpp b/backends/platform/libretro/src/libretro-os-utils.cpp
index e1e10381e99..6ba7c1c0ffa 100644
--- a/backends/platform/libretro/src/libretro-os-utils.cpp
+++ b/backends/platform/libretro/src/libretro-os-utils.cpp
@@ -219,7 +219,7 @@ void OSystem_libretro::applyBackendSettings() {
//Check current path settings
if (!checkPathSetting("savepath", s_saveDir)) {
- ConfMan.setAndFlush("savepath", s_homeDir);
+ ConfMan.setAndFlush("savepath", s_systemDir);
retro_osd_notification("ScummVM save folder not found.");
}
if (!checkPathSetting("themepath", s_themeDir))
@@ -228,7 +228,7 @@ void OSystem_libretro::applyBackendSettings() {
retro_osd_notification("ScummVM extra folder not found. Some engines/features (e.g. Virtual Keyboard) will not work without relevant datafiles.");
checkPathSetting("soundfont", s_soundfontPath, false);
checkPathSetting("browser_lastpath", s_homeDir);
- checkPathSetting("libretro_playlist_path", s_playlistDir.empty() ? s_homeDir : s_playlistDir);
+ checkPathSetting("libretro_playlist_path", s_playlistDir.empty() ? s_systemDir : s_playlistDir);
checkPathSetting("iconspath", "");
}
Commit: d7fb0de22db85de22e1381c6a9085806c3bb42f9
https://github.com/scummvm/scummvm/commit/d7fb0de22db85de22e1381c6a9085806c3bb42f9
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:19:01+02:00
Commit Message:
LIBRETRO: add android storage information
Changed paths:
backends/platform/libretro/README.md
backends/platform/libretro/src/libretro-os-utils.cpp
diff --git a/backends/platform/libretro/README.md b/backends/platform/libretro/README.md
index 66c97187201..84933dcbd7f 100644
--- a/backends/platform/libretro/README.md
+++ b/backends/platform/libretro/README.md
@@ -75,3 +75,23 @@ Operation status will be shown in the same dialog, while details will be given i
- **Sample rate**: set core sample rate. Reducing the rate will slightly improve the performance on lower end devices. Changing this setting will reset the core.
### RetroPad mapping
Settings to map each RetroPad key to ScummVM controls.
+
+## Android storage access
+On modern Android versions apps can only access folders explicitly authorized by the user through the system file picker (Storage Access Framework, SAF).
+
+The core can browse both the standard local filesystem and the folders authorized through the frontend (e.g. RetroArch). The starting location of the ScummVM file browser is controlled by the **Browsing mode** core option.
+
+### Browsing mode
+Available under the frontend core options (e.g. RetroArch `Quick Menu > Core Options > System`):
+
+ - **Authorized storage**: the file browser starts from a virtual root listing only the folders authorized through the frontend. Default on Android.
+ - **Local filesystem**: the file browser starts from the standard local path.
+
+### Authorizing folders
+ - Open the frontend file browser (e.g. in RetroArch, "Load Content") and use the option to open/add a new folder; the system file picker will appear.
+ - Grant access to the folder(s) containing your games and exit the file browser (no need to actually select any content at this time). The authorization is persistent across reboots.
+ - Start the core; the authorized folders will be listed by the ScummVM file browser when **Browsing mode** is set to `Authorized storage`.
+
+### Notes
+ - The authorized folder list is read when the core starts. If you authorize new folders while the core is running, restart (reload) the core to make them available.
+ - If **Browsing mode** is `Authorized storage` but no folders have been authorized, the core falls back to the local filesystem and shows a notification.
diff --git a/backends/platform/libretro/src/libretro-os-utils.cpp b/backends/platform/libretro/src/libretro-os-utils.cpp
index 6ba7c1c0ffa..36116345aea 100644
--- a/backends/platform/libretro/src/libretro-os-utils.cpp
+++ b/backends/platform/libretro/src/libretro-os-utils.cpp
@@ -269,6 +269,36 @@ static const char *const helpTabs[] = {
"Operation status will be shown in the same dialog, while details will be given in frontend logs."
),
+#ifdef ANDROID
+ _s("Android storage"),
+ "",
+ _s(
+ "## Android storage access\n"
+ "On Android modern versions apps can only access folders that have been explicitly authorized by the user through the system file picker (Storage Access Framework, SAF).\n"
+ "\n"
+ "The core can browse both the standard local filesystem and the folders authorized through the frontend (e.g. RetroArch). The starting location of the file browser is controlled by the **Browsing mode** core option.\n"
+ "\n"
+ "## Browsing mode\n"
+ "This core option is available in the frontend core options (e.g. RetroArch 'Quick Menu > Core Options > System').\n"
+ "\n"
+ " - **Authorized storage**: the file browser starts from a virtual root listing only the folders authorized through the frontend. This is the default on Android.\n"
+ "\n"
+ " - **Local filesystem**: the file browser starts from the standard local path.\n"
+ "\n"
+ "## Authorizing folders\n"
+ " - Open the frontend file browser (e.g. in RetroArch, 'Load Content') and use the option to open/add a folder; the system file picker will appear.\n"
+ "\n"
+ " - Grant access to the folder(s) that contain your games and exit the file browser (no need to actually select any content at this time). The authorization is persistent across reboots.\n"
+ "\n"
+ " - Start the core; the authorized folders will be listed by the ScummVM file browser when **Browsing mode** is set to 'Authorized storage'.\n"
+ "\n"
+ "## Notes\n"
+ " - The authorized folder list is read when the core starts. If you authorize new folders while the core is running, restart (reload) the core to make them available.\n"
+ "\n"
+ " - If **Browsing mode** is set to 'Authorized storage' but no folders have been authorized, the core falls back to the local filesystem and shows a notification.\n"
+ ),
+#endif
+
0 // End of list
};
Commit: 940c6287c0ce6c3b91392ca1e34cb0c97ea2a911
https://github.com/scummvm/scummvm/commit/940c6287c0ce6c3b91392ca1e34cb0c97ea2a911
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:19:01+02:00
Commit Message:
LIBRETRO: add consistency check for last browsed path
Changed paths:
backends/platform/libretro/include/libretro-fs.h
backends/platform/libretro/src/libretro-fs.cpp
backends/platform/libretro/src/libretro-os-utils.cpp
diff --git a/backends/platform/libretro/include/libretro-fs.h b/backends/platform/libretro/include/libretro-fs.h
index 3d2ad414941..91bcc62b669 100644
--- a/backends/platform/libretro/include/libretro-fs.h
+++ b/backends/platform/libretro/include/libretro-fs.h
@@ -97,6 +97,7 @@ public:
static void addAuthorizedLocation(const Common::String &path, const Common::String &label);
static bool hasAuthorizedLocations(void);
static bool useAuthorizedRoot(void);
+ static bool isBrowserLastPathCompatible(const Common::String &path);
private:
/**
* Tests and sets the _isValid and _isDirectory flags, using the stat() function.
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index 107474c4546..c3fa0af24ee 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -721,6 +721,18 @@ bool LibRetroFilesystemNode::useAuthorizedRoot(void) {
return retro_setting_get_browsing_mode_authorized();
}
+bool LibRetroFilesystemNode::isBrowserLastPathCompatible(const Common::String &path) {
+ if (path.empty())
+ return false;
+
+ bool isAuthorizedPath = path.equals(kLibRetroAuthorizedRootPath) || libretroFsIsInsideAuthorizedLocation(path);
+
+ if (useAuthorizedRoot())
+ return isAuthorizedPath;
+
+ return !isAuthorizedPath;
+}
+
Common::String LibRetroFilesystemNode::getDefaultDir(void) {
if (useAuthorizedRoot())
return getAuthorizedRootPath();
diff --git a/backends/platform/libretro/src/libretro-os-utils.cpp b/backends/platform/libretro/src/libretro-os-utils.cpp
index 36116345aea..af046d2cf9b 100644
--- a/backends/platform/libretro/src/libretro-os-utils.cpp
+++ b/backends/platform/libretro/src/libretro-os-utils.cpp
@@ -227,7 +227,18 @@ void OSystem_libretro::applyBackendSettings() {
if (!checkPathSetting("extrapath", s_extraDir))
retro_osd_notification("ScummVM extra folder not found. Some engines/features (e.g. Virtual Keyboard) will not work without relevant datafiles.");
checkPathSetting("soundfont", s_soundfontPath, false);
- checkPathSetting("browser_lastpath", s_homeDir);
+ {
+ Common::String lastPath;
+ if (ConfMan.hasKey("browser_lastpath"))
+ lastPath = Common::Path::fromConfig(ConfMan.get("browser_lastpath")).toString();
+
+ if (lastPath.empty() || !LibRetroFilesystemNode::isBrowserLastPathCompatible(lastPath)) {
+ if (s_homeDir.empty())
+ ConfMan.removeKey("browser_lastpath", Common::ConfigManager::kApplicationDomain);
+ else
+ ConfMan.setPath("browser_lastpath", Common::Path::fromConfig(s_homeDir));
+ }
+ }
checkPathSetting("libretro_playlist_path", s_playlistDir.empty() ? s_systemDir : s_playlistDir);
checkPathSetting("iconspath", "");
}
Commit: 414d2d6952b2248558b14570299aa7f938f09aa6
https://github.com/scummvm/scummvm/commit/414d2d6952b2248558b14570299aa7f938f09aa6
Author: Giovanni Cascione (ing.cascione at gmail.com)
Date: 2026-08-17T10:19:01+02:00
Commit Message:
LIBRETRO: add URI parser for authorized paths labels
Changed paths:
backends/platform/libretro/src/libretro-fs.cpp
diff --git a/backends/platform/libretro/src/libretro-fs.cpp b/backends/platform/libretro/src/libretro-fs.cpp
index c3fa0af24ee..4cf79795282 100644
--- a/backends/platform/libretro/src/libretro-fs.cpp
+++ b/backends/platform/libretro/src/libretro-fs.cpp
@@ -101,6 +101,50 @@ static bool libretroFsHasUriScheme(const Common::String &path) {
return strstr(path.c_str(), "://") != nullptr;
}
+static Common::String libretroFsPercentDecode(const Common::String &s) {
+ Common::String out;
+ for (uint i = 0; i < s.size(); ++i) {
+ if (s[i] == '%' && i + 2 < s.size()) {
+ char h1 = s[i + 1], h2 = s[i + 2];
+ int v1 = (h1 >= '0' && h1 <= '9') ? h1 - '0' : (h1 >= 'A' && h1 <= 'F') ? h1 - 'A' + 10 : (h1 >= 'a' && h1 <= 'f') ? h1 - 'a' + 10 : -1;
+ int v2 = (h2 >= '0' && h2 <= '9') ? h2 - '0' : (h2 >= 'A' && h2 <= 'F') ? h2 - 'A' + 10 : (h2 >= 'a' && h2 <= 'f') ? h2 - 'a' + 10 : -1;
+ if (v1 >= 0 && v2 >= 0) {
+ out += (char)((v1 << 4) | v2);
+ i += 2;
+ continue;
+ }
+ }
+ out += s[i];
+ }
+ return out;
+}
+
+static Common::String libretroFsSafDisplayName(const Common::String &path) {
+ Common::String decoded(path);
+ // SAF paths are double-encoded (e.g. %252F). Decode up to twice to reveal real separators.
+ for (int pass = 0; pass < 2; ++pass) {
+ if (decoded.contains('%'))
+ decoded = libretroFsPercentDecode(decoded);
+ else
+ break;
+ }
+
+ while (decoded.size() > 1 && decoded.lastChar() == '/')
+ decoded.erase(decoded.size() - 1);
+
+ // Take the part after the last '/'.
+ size_t slash = decoded.findLastOf('/');
+ if (slash != Common::String::npos)
+ decoded = decoded.substr(slash + 1);
+
+ // Take the part after the last ':' (e.g. 'primary:Games' -> 'Games').
+ size_t colon = decoded.findLastOf(':');
+ if (colon != Common::String::npos)
+ decoded = decoded.substr(colon + 1);
+
+ return decoded.empty() ? path : decoded;
+}
+
static Common::String libretroFsUriDisplayName(const Common::String &path) {
Common::String trimmed(path);
@@ -672,10 +716,10 @@ void LibRetroFilesystemNode::addAuthorizedLocation(const Common::String &path, c
LibRetroAuthorizedLocation location;
location.path = path;
- if (!label.empty())
- location.label = label;
- else
- location.label = libretroFsUriDisplayName(path);
+ // The frontend may pass a generic label (e.g. "Removable storage") for all
+ // SAF trees; derive a readable name from the path instead.
+ (void)label;
+ location.label = libretroFsSafDisplayName(path);
s_libretroAuthorizedLocations.push_back(location);
}
More information about the Scummvm-git-logs
mailing list