From 6622cb081006c927218e092451f2b50d7ac1a3b6 Mon Sep 17 00:00:00 2001
From: twinaphex <libretro@gmail.com>
Date: Sat, 16 Dec 2017 14:12:38 +0100
Subject: [PATCH] Update libretro API

---
 libretro-common/include/libretro.h            | 24 ++++++++++-
 libretro-common/include/streams/file_stream.h |  2 +-
 .../include/vfs/vfs_implementation.h          |  2 +-
 libretro-common/streams/chd_stream.c          | 22 +++++-----
 libretro-common/streams/file_stream.c         |  8 ++--
 .../streams/file_stream_transforms.c          | 16 ++++++-
 libretro-common/streams/interface_stream.c    | 18 +++++++-
 libretro-common/vfs/vfs_implementation.c      | 19 ++++++++-
 libretro-db/libretrodb.c                      | 42 ++++++++++++-------
 9 files changed, 115 insertions(+), 38 deletions(-)

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 <stdlib.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/types.h>
 
 #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;