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 +#include + +#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__