diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 7362725ae2..315123c913 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -967,6 +967,23 @@ enum retro_mod * core supports VFS before it starts handing out paths. * It is recomended to do so in retro_set_environment */ +/* VFS functionality */ + +/* File paths: + * File paths passed as parameters when using this api shall be well formed unix-style, + * using "/" (unquoted forward slash) as directory separator regardless of the platform's native separator. + * Paths shall also include at least one forward slash ("game.bin" is an invalid path, use "./game.bin" instead). + * Other than the directory separator, cores shall not make assumptions about path format: + * "C:/path/game.bin", "http://example.com/game.bin", "#game/game.bin", "./game.bin" (without quotes) are all valid paths. + * Cores may replace the basename or remove path components from the end, and/or add new components; + * however, cores shall not append "./", "../" or multiple consecutive forward slashes ("//") to paths they request to front end. + * The frontend is encouraged to make such paths work as well as it can, but is allowed to give up if the core alters paths too much. + * Frontends are encouraged, but not required, to support native file system paths (modulo replacing the directory separator, if applicable). + * Cores are allowed to try using them, but must remain functional if the front rejects such requests. + * Cores are encouraged to use the libretro-common filestream functions for file I/O, + * as they seamlessly integrate with VFS, deal with directory separator replacement as appropriate + * and provide platform-specific fallbacks in cases where front ends do not support VFS. */ + /* Opaque file handle * Introduced in VFS API v1 */ struct retro_vfs_file_handle; @@ -985,6 +1002,11 @@ struct retro_vfs_file_handle; /* Indicate that the file will be accessed many times. The frontend should aggressively cache everything. */ #define RETRO_VFS_FILE_ACCESS_HINT_FREQUENT_ACCESS (1 << 0) +/* Seek positions */ +#define RETRO_VFS_SEEK_POSITION_START 0 +#define RETRO_VFS_SEEK_POSITION_CURRENT 1 +#define RETRO_VFS_SEEK_POSITION_END 2 + /* Get path from opaque handle. Returns the exact same path passed to file_open when getting the handle * Introduced in VFS API v1 */ typedef const char *(RETRO_CALLCONV *retro_vfs_get_path_t)(struct retro_vfs_file_handle *stream); @@ -1009,7 +1031,7 @@ typedef int64_t (RETRO_CALLCONV *retro_vfs_tell_t)(struct retro_vfs_file_handle /* Set the current read/write position for the file. Returns the new position, -1 for error. * Introduced in VFS API v1 */ -typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int whence); +typedef int64_t (RETRO_CALLCONV *retro_vfs_seek_t)(struct retro_vfs_file_handle *stream, int64_t offset, int seek_position); /* Read data from a file. Returns the number of bytes read, or -1 for error. * Introduced in VFS API v1 */ diff --git a/libretro-common/include/streams/file_stream.h b/libretro-common/include/streams/file_stream.h index c2b319e85f..fba803cdbe 100644 --- a/libretro-common/include/streams/file_stream.h +++ b/libretro-common/include/streams/file_stream.h @@ -60,7 +60,7 @@ int64_t filestream_get_size(RFILE *stream); **/ RFILE *filestream_open(const char *path, unsigned mode, unsigned hints); -ssize_t filestream_seek(RFILE *stream, ssize_t offset, int whence); +ssize_t filestream_seek(RFILE *stream, ssize_t offset, int seek_position); ssize_t filestream_read(RFILE *stream, void *data, int64_t len); diff --git a/libretro-common/include/vfs/vfs_implementation.h b/libretro-common/include/vfs/vfs_implementation.h index 2b3f34e4bc..5ceae39b6f 100644 --- a/libretro-common/include/vfs/vfs_implementation.h +++ b/libretro-common/include/vfs/vfs_implementation.h @@ -48,7 +48,7 @@ int64_t retro_vfs_file_size_impl(libretro_vfs_implementation_file *stream); int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream); -int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int whence); +int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position); int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len); diff --git a/libretro-common/streams/chd_stream.c b/libretro-common/streams/chd_stream.c index a2b5247733..1449b91dc9 100644 --- a/libretro-common/streams/chd_stream.c +++ b/libretro-common/streams/chd_stream.c @@ -401,17 +401,17 @@ int chdstream_seek(chdstream_t *stream, ssize_t offset, int whence) switch (whence) { - case SEEK_SET: - new_offset = offset; - break; - case SEEK_CUR: - new_offset = stream->offset + offset; - break; - case SEEK_END: - new_offset = stream->track_end + offset; - break; - default: - return -1; + case SEEK_SET: + new_offset = offset; + break; + case SEEK_CUR: + new_offset = stream->offset + offset; + break; + case SEEK_END: + new_offset = stream->track_end + offset; + break; + default: + return -1; } if (new_offset < 0) diff --git a/libretro-common/streams/file_stream.c b/libretro-common/streams/file_stream.c index 0d3d8142fb..b19397470c 100644 --- a/libretro-common/streams/file_stream.c +++ b/libretro-common/streams/file_stream.c @@ -188,14 +188,14 @@ int filestream_getc(RFILE *stream) return EOF; } -ssize_t filestream_seek(RFILE *stream, ssize_t offset, int whence) +ssize_t filestream_seek(RFILE *stream, ssize_t offset, int seek_position) { int64_t output; if (filestream_seek_cb != NULL) - output = filestream_seek_cb(stream->hfile, offset, whence); + output = filestream_seek_cb(stream->hfile, offset, seek_position); else - output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, whence); + output = retro_vfs_file_seek_impl((libretro_vfs_implementation_file*)stream->hfile, offset, seek_position); if (output == vfs_error_return_value) stream->error_flag = true; @@ -233,7 +233,7 @@ void filestream_rewind(RFILE *stream) { if (!stream) return; - filestream_seek(stream, 0L, SEEK_SET); + filestream_seek(stream, 0L, RETRO_VFS_SEEK_POSITION_START); stream->error_flag = false; } diff --git a/libretro-common/streams/file_stream_transforms.c b/libretro-common/streams/file_stream_transforms.c index ff11a32e34..b784cfccae 100644 --- a/libretro-common/streams/file_stream_transforms.c +++ b/libretro-common/streams/file_stream_transforms.c @@ -53,7 +53,21 @@ long rftell(RFILE* stream) int rfseek(RFILE* stream, long offset, int origin) { - return filestream_seek(stream, offset, origin); + int seek_position = -1; + switch (origin) + { + case SEEK_SET: + seek_position = RETRO_VFS_SEEK_POSITION_START; + break; + case SEEK_CUR: + seek_position = RETRO_VFS_SEEK_POSITION_CURRENT; + break; + case SEEK_END: + seek_position = RETRO_VFS_SEEK_POSITION_END; + break; + } + + return filestream_seek(stream, offset, seek_position); } size_t rfread(void* buffer, diff --git a/libretro-common/streams/interface_stream.c b/libretro-common/streams/interface_stream.c index 619555a4b1..44177aa7d7 100644 --- a/libretro-common/streams/interface_stream.c +++ b/libretro-common/streams/interface_stream.c @@ -223,7 +223,23 @@ int intfstream_seek(intfstream_internal_t *intf, int offset, int whence) switch (intf->type) { case INTFSTREAM_FILE: - return (int)filestream_seek(intf->file.fp, (int)offset, whence); + { + int seek_position = 0; + switch (whence) + { + case SEEK_SET: + seek_position = RETRO_VFS_SEEK_POSITION_START; + break; + case SEEK_CUR: + seek_position = RETRO_VFS_SEEK_POSITION_CURRENT; + break; + case SEEK_END: + seek_position = RETRO_VFS_SEEK_POSITION_END; + break; + } + return (int)filestream_seek(intf->file.fp, (int)offset, + seek_position); + } case INTFSTREAM_MEMORY: return (int)memstream_seek(intf->memory.fp, offset, whence); case INTFSTREAM_CHD: diff --git a/libretro-common/vfs/vfs_implementation.c b/libretro-common/vfs/vfs_implementation.c index acf46fbad4..9f7b216589 100644 --- a/libretro-common/vfs/vfs_implementation.c +++ b/libretro-common/vfs/vfs_implementation.c @@ -24,6 +24,7 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include "config.h" @@ -376,9 +377,23 @@ int64_t retro_vfs_file_tell_impl(libretro_vfs_implementation_file *stream) return 0; } -int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int whence) +int64_t retro_vfs_file_seek_impl(libretro_vfs_implementation_file *stream, int64_t offset, int seek_position) { - return retro_vfs_file_seek_internal(stream, offset, whence); + int whence = -1; + switch (seek_position) + { + case RETRO_VFS_SEEK_POSITION_START: + whence = SEEK_SET; + break; + case RETRO_VFS_SEEK_POSITION_CURRENT: + whence = SEEK_CUR; + break; + case RETRO_VFS_SEEK_POSITION_END: + whence = SEEK_END; + break; + } + + return retro_vfs_file_seek_internal(stream, offset, whence); } int64_t retro_vfs_file_read_impl(libretro_vfs_implementation_file *stream, void *s, uint64_t len) diff --git a/libretro-db/libretrodb.c b/libretro-db/libretrodb.c index 468a8fbbae..e9c21ba04a 100644 --- a/libretro-db/libretrodb.c +++ b/libretro-db/libretrodb.c @@ -143,14 +143,15 @@ int libretrodb_create(RFILE *fd, libretrodb_value_provider value_provider, struct rmsgpack_dom_value item; uint64_t item_count = 0; libretrodb_header_t header = {{0}}; - ssize_t root = filestream_seek(fd, 0, SEEK_CUR); + ssize_t root = filestream_seek(fd, 0, RETRO_VFS_SEEK_POSITION_CURRENT); memcpy(header.magic_number, MAGIC_NUMBER, sizeof(MAGIC_NUMBER)-1); /* We write the header in the end because we need to know the size of * the db first */ - filestream_seek(fd, sizeof(libretrodb_header_t), SEEK_CUR); + filestream_seek(fd, sizeof(libretrodb_header_t), + RETRO_VFS_SEEK_POSITION_CURRENT); item.type = RDT_NULL; while ((rv = value_provider(ctx, &item)) == 0) @@ -172,10 +173,11 @@ int libretrodb_create(RFILE *fd, libretrodb_value_provider value_provider, if ((rv = rmsgpack_dom_write(fd, &sentinal)) < 0) goto clean; - header.metadata_offset = swap_if_little64(filestream_seek(fd, 0, SEEK_CUR)); + header.metadata_offset = swap_if_little64(filestream_seek( + fd, 0, RETRO_VFS_SEEK_POSITION_CURRENT)); md.count = item_count; libretrodb_write_metadata(fd, &md); - filestream_seek(fd, root, SEEK_SET); + filestream_seek(fd, root, RETRO_VFS_SEEK_POSITION_START); filestream_write(fd, &header, sizeof(header)); clean: rmsgpack_dom_value_free(&item); @@ -228,7 +230,7 @@ int libretrodb_open(const char *path, libretrodb_t *db) free(db->path); db->path = strdup(path); - db->root = filestream_seek(fd, 0, SEEK_CUR); + db->root = filestream_seek(fd, 0, RETRO_VFS_SEEK_POSITION_CURRENT); if ((rv = (int)filestream_read(fd, &header, sizeof(header))) == -1) { @@ -243,7 +245,8 @@ int libretrodb_open(const char *path, libretrodb_t *db) } header.metadata_offset = swap_if_little64(header.metadata_offset); - filestream_seek(fd, (ssize_t)header.metadata_offset, SEEK_SET); + filestream_seek(fd, (ssize_t)header.metadata_offset, + RETRO_VFS_SEEK_POSITION_START); if (libretrodb_read_metadata(fd, &md) < 0) { @@ -251,9 +254,10 @@ int libretrodb_open(const char *path, libretrodb_t *db) goto error; } - db->count = md.count; - db->first_index_offset = filestream_seek(fd, 0, SEEK_CUR); - db->fd = fd; + db->count = md.count; + db->first_index_offset = filestream_seek(fd, 0, + RETRO_VFS_SEEK_POSITION_CURRENT); + db->fd = fd; return 0; error: @@ -265,9 +269,11 @@ error: static int libretrodb_find_index(libretrodb_t *db, const char *index_name, libretrodb_index_t *idx) { - ssize_t eof = filestream_seek(db->fd, 0, SEEK_END); + ssize_t eof = filestream_seek(db->fd, 0, + RETRO_VFS_SEEK_POSITION_END); ssize_t offset = filestream_seek(db->fd, - (ssize_t)db->first_index_offset, SEEK_SET); + (ssize_t)db->first_index_offset, + RETRO_VFS_SEEK_POSITION_START); while (offset < eof) { @@ -276,7 +282,8 @@ static int libretrodb_find_index(libretrodb_t *db, const char *index_name, if (strncmp(index_name, idx->name, strlen(idx->name)) == 0) return 0; - offset = filestream_seek(db->fd, (ssize_t)idx->next, SEEK_CUR); + offset = filestream_seek(db->fd, (ssize_t)idx->next, + RETRO_VFS_SEEK_POSITION_CURRENT); } return -1; @@ -341,7 +348,8 @@ int libretrodb_find_entry(libretrodb_t *db, const char *index_name, free(buff); if (rv == 0) - filestream_seek(db->fd, (ssize_t)offset, SEEK_SET); + filestream_seek(db->fd, (ssize_t)offset, + RETRO_VFS_SEEK_POSITION_START); return rmsgpack_dom_read(db->fd, out); } @@ -359,7 +367,7 @@ int libretrodb_cursor_reset(libretrodb_cursor_t *cursor) cursor->eof = 0; return (int)filestream_seek(cursor->fd, (ssize_t)(cursor->db->root + sizeof(libretrodb_header_t)), - SEEK_SET); + RETRO_VFS_SEEK_POSITION_START); } int libretrodb_cursor_read_item(libretrodb_cursor_t *cursor, @@ -466,7 +474,8 @@ static int node_iter(void *value, void *ctx) static uint64_t libretrodb_tell(libretrodb_t *db) { - return filestream_seek(db->fd, 0, SEEK_CUR); + return filestream_seek(db->fd, 0, + RETRO_VFS_SEEK_POSITION_CURRENT); } static int node_compare(const void *a, const void *b, void *ctx) @@ -557,7 +566,8 @@ int libretrodb_create_index(libretrodb_t *db, item_loc = libretrodb_tell(db); } - idx_header_offset = filestream_seek(db->fd, 0, SEEK_END); + idx_header_offset = filestream_seek(db->fd, 0, + RETRO_VFS_SEEK_POSITION_END); (void)idx_header_offset;