https://github.com/libsdl-org/SDL/commit/abcfb22b7d964e22149352856907ae60cf91c7ad
From abcfb22b7d964e22149352856907ae60cf91c7ad Mon Sep 17 00:00:00 2001
From: uyjulian <[EMAIL REDACTED]>
Date: Sun, 28 Feb 2021 13:49:01 -0600
Subject: [PATCH] Add support for Vita file API in SDL_rwops
---
include/SDL_rwops.h | 14 +++
src/file/SDL_rwops.c | 257 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 256 insertions(+), 15 deletions(-)
diff --git a/include/SDL_rwops.h b/include/SDL_rwops.h
index 923a836c3..e73080749 100644
--- a/include/SDL_rwops.h
+++ b/include/SDL_rwops.h
@@ -45,6 +45,9 @@ extern "C" {
#define SDL_RWOPS_JNIFILE 3U /**< Android asset */
#define SDL_RWOPS_MEMORY 4U /**< Memory stream */
#define SDL_RWOPS_MEMORY_RO 5U /**< Read-Only memory stream */
+#if defined(__VITA__)
+#define SDL_RWOPS_VITAFILE 6U /**< Vita file */
+#endif
/**
* This is the read/write operation structure -- very basic.
@@ -110,6 +113,17 @@ typedef struct SDL_RWops
size_t left;
} buffer;
} windowsio;
+#elif defined(__VITA__)
+ struct
+ {
+ int h;
+ struct
+ {
+ void *data;
+ size_t size;
+ size_t left;
+ } buffer;
+ } vitaio;
#endif
#ifdef HAVE_STDIO_H
diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c
index d2a7831d2..9552b3d03 100644
--- a/src/file/SDL_rwops.c
+++ b/src/file/SDL_rwops.c
@@ -62,6 +62,236 @@
#include "nacl_io/nacl_io.h"
#endif
+#ifdef __VITA__
+
+#include <psp2/io/fcntl.h>
+#include <psp2/io/stat.h>
+
+#define READAHEAD_BUFFER_SIZE 1024
+static int SDLCALL
+vita_file_open(SDL_RWops * context, const char *filename, const char *mode)
+{
+ int h;
+ int open_flags;
+ SDL_bool has_r;
+ SDL_bool has_w;
+ SDL_bool has_a;
+ SDL_bool has_plus;
+
+ if (!context)
+ return -1; /* failed (invalid call) */
+
+ context->hidden.vitaio.h = -1; /* mark this as unusable */
+ context->hidden.vitaio.buffer.data = NULL;
+ context->hidden.vitaio.buffer.size = 0;
+ context->hidden.vitaio.buffer.left = 0;
+
+ open_flags = 0;
+
+ /* "r" = reading, file must exist */
+ /* "w" = writing, truncate existing, file may not exist */
+ /* "r+"= reading or writing, file must exist */
+ /* "a" = writing, append file may not exist */
+ /* "a+"= append + read, file may not exist */
+ /* "w+" = read, write, truncate. file may not exist */
+
+ has_r = SDL_strchr(mode, 'r') != NULL;
+ has_w = SDL_strchr(mode, 'w') != NULL;
+ has_a = SDL_strchr(mode, 'a') != NULL;
+ has_plus = SDL_strchr(mode, '+') != NULL;
+
+ if (has_plus)
+ {
+ if (has_r || has_w || has_a)
+ {
+ open_flags |= SCE_O_RDWR;
+ }
+ }
+ else
+ {
+ if (has_r)
+ {
+ open_flags |= SCE_O_RDONLY;
+ }
+ if (has_w || has_a)
+ {
+ open_flags |= SCE_O_WRONLY;
+ }
+ }
+ if (has_w || has_a)
+ {
+ open_flags |= SCE_O_CREAT;
+ }
+ if (has_w)
+ {
+ open_flags |= SCE_O_TRUNC;
+ }
+ if (has_a)
+ {
+ open_flags |= SCE_O_APPEND;
+ }
+
+ context->hidden.vitaio.buffer.data =
+ (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
+ if (!context->hidden.vitaio.buffer.data) {
+ return SDL_OutOfMemory();
+ }
+
+ /* Try to open the file on the filesystem first */
+ h = sceIoOpen(filename, open_flags, 0777);
+
+ if (h < 0) {
+ /* Try opening it from app0:/ container if it's a relative path */
+ char path[4096];
+ SDL_snprintf(path, 4096, "app0:/%s", filename);
+ h = sceIoOpen(path, open_flags, 0777);
+ }
+
+ if (h < 0) {
+ SDL_free(context->hidden.vitaio.buffer.data);
+ context->hidden.vitaio.buffer.data = NULL;
+ SDL_SetError("Couldn't open %s", filename);
+ return -2; /* failed (sceIoOpen) */
+ }
+ context->hidden.vitaio.h = h;
+
+ return 0; /* ok */
+}
+
+static Sint64 SDLCALL
+vita_file_size(SDL_RWops * context)
+{
+ SceIoStat st;
+ if (!context || context->hidden.vitaio.h < 0) {
+ return SDL_SetError("vita_file_size: invalid context/file not opened");
+ }
+
+ if (sceIoGetstatByFd(context->hidden.vitaio.h, &st) < 0)
+ {
+ return SDL_SetError("vita_file_size: could not get file size");
+ }
+ return st.st_size;
+}
+
+static Sint64 SDLCALL
+vita_file_seek(SDL_RWops * context, Sint64 offset, int whence)
+{
+ int vitawhence;
+
+ if (!context || context->hidden.vitaio.h < 0) {
+ return SDL_SetError("vita_file_seek: invalid context/file not opened");
+ }
+
+ /* FIXME: We may be able to satisfy the seek within buffered data */
+ if (whence == RW_SEEK_CUR && context->hidden.vitaio.buffer.left) {
+ offset -= (long)context->hidden.vitaio.buffer.left;
+ }
+ context->hidden.vitaio.buffer.left = 0;
+
+ switch (whence) {
+ case RW_SEEK_SET:
+ vitawhence = SCE_SEEK_SET;
+ break;
+ case RW_SEEK_CUR:
+ vitawhence = SCE_SEEK_CUR;
+ break;
+ case RW_SEEK_END:
+ vitawhence = SCE_SEEK_END;
+ break;
+ default:
+ return SDL_SetError("vita_file_seek: Unknown value for 'whence'");
+ }
+
+ return sceIoLseek(context->hidden.vitaio.h, offset, vitawhence);
+}
+
+static size_t SDLCALL
+vita_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
+{
+ size_t total_need;
+ size_t total_read = 0;
+ size_t read_ahead;
+ size_t byte_read;
+
+ total_need = size * maxnum;
+
+ if (!context || context->hidden.vitaio.h < 0
+ || !total_need)
+ return 0;
+
+ if (context->hidden.vitaio.buffer.left > 0) {
+ void *data = (char *) context->hidden.vitaio.buffer.data +
+ context->hidden.vitaio.buffer.size -
+ context->hidden.vitaio.buffer.left;
+ read_ahead =
+ SDL_min(total_need, context->hidden.vitaio.buffer.left);
+ SDL_memcpy(ptr, data, read_ahead);
+ context->hidden.vitaio.buffer.left -= read_ahead;
+
+ if (read_ahead == total_need) {
+ return maxnum;
+ }
+ ptr = (char *) ptr + read_ahead;
+ total_need -= read_ahead;
+ total_read += read_ahead;
+ }
+
+ if (total_need < READAHEAD_BUFFER_SIZE) {
+ byte_read = sceIoRead(context->hidden.vitaio.h, context->hidden.vitaio.buffer.data, READAHEAD_BUFFER_SIZE);
+ read_ahead = SDL_min(total_need, (int) byte_read);
+ SDL_memcpy(ptr, context->hidden.vitaio.buffer.data, read_ahead);
+ context->hidden.vitaio.buffer.size = byte_read;
+ context->hidden.vitaio.buffer.left = byte_read - read_ahead;
+ total_read += read_ahead;
+ } else {
+ byte_read = sceIoRead(context->hidden.vitaio.h, ptr, total_need);
+ total_read += byte_read;
+ }
+ return (total_read / size);
+}
+
+static size_t SDLCALL
+vita_file_write(SDL_RWops * context, const void *ptr, size_t size,
+ size_t num)
+{
+
+ size_t total_bytes;
+ size_t byte_written;
+ size_t nwritten;
+
+ total_bytes = size * num;
+
+ if (!context || context->hidden.vitaio.h < 0
+ || total_bytes <= 0 || !size)
+ return 0;
+
+ if (context->hidden.vitaio.buffer.left) {
+ sceIoLseek(context->hidden.vitaio.h, -(SceOff)context->hidden.vitaio.buffer.left, SCE_SEEK_CUR);
+ context->hidden.vitaio.buffer.left = 0;
+ }
+
+ byte_written = sceIoWrite(context->hidden.vitaio.h, ptr, total_bytes);
+
+ nwritten = byte_written / size;
+ return nwritten;
+}
+
+static int SDLCALL
+vita_file_close(SDL_RWops * context)
+{
+ if (context) {
+ if (context->hidden.vitaio.h >= 0) {
+ sceIoClose(context->hidden.vitaio.h);
+ context->hidden.vitaio.h = -1; /* to be sure */
+ }
+ SDL_free(context->hidden.vitaio.buffer.data);
+ context->hidden.vitaio.buffer.data = NULL;
+ SDL_FreeRW(context);
+ }
+ return 0;
+}
+#endif
+
#ifdef __WIN32__
/* Functions to read/write Win32 API file pointers */
@@ -590,22 +820,19 @@ SDL_RWFromFile(const char *file, const char *mode)
rwops->close = windows_file_close;
rwops->type = SDL_RWOPS_WINFILE;
#elif defined(__VITA__)
- {
- /* Try to open the file on the filesystem first */
- FILE *fp = fopen(file, mode);
- if (fp) {
- return SDL_RWFromFP(fp, 1);
- } else {
- /* Try opening it from app0:/ container if it's a relative path */
- char path[4096];
- SDL_snprintf(path, 4096, "app0:/%s", file);
- fp = fopen(path, mode);
- if (fp) {
- return SDL_RWFromFP(fp, 1);
- }
- }
- SDL_SetError("Couldn't open %s", file);
+ rwops = SDL_AllocRW();
+ if (!rwops)
+ return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
+ if (vita_file_open(rwops, file, mode) < 0) {
+ SDL_FreeRW(rwops);
+ return NULL;
}
+ rwops->size = vita_file_size;
+ rwops->seek = vita_file_seek;
+ rwops->read = vita_file_read;
+ rwops->write = vita_file_write;
+ rwops->close = vita_file_close;
+ rwops->type = SDL_RWOPS_VITAFILE;
#elif HAVE_STDIO_H
{
#ifdef __APPLE__