libretro: add savestate support
authornotaz <notasas@gmail.com>
Tue, 30 Jul 2013 23:18:34 +0000 (02:18 +0300)
committernotaz <notasas@gmail.com>
Tue, 30 Jul 2013 23:18:34 +0000 (02:18 +0300)
pico/state.c
pico/state.h [new file with mode: 0644]
platform/libretro.c

index 11eee6f..3969e18 100644 (file)
 \r
 #include "../cpu/sh2/sh2.h"\r
 #include "sound/ym2612.h"\r
+#include "state.h"\r
 \r
 // sn76496\r
 extern int *sn76496_regs;\r
 \r
-typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);\r
-typedef size_t (areaeof)(void *file);\r
-typedef int    (areaseek)(void *file, long offset, int whence);\r
-typedef int    (areaclose)(void *file);\r
-\r
 static arearw    *areaRead;\r
 static arearw    *areaWrite;\r
 static areaeof   *areaEof;\r
@@ -594,15 +590,10 @@ readend:
   return 0;\r
 }\r
 \r
-int PicoState(const char *fname, int is_save)\r
+static int pico_state_internal(void *afile, int is_save)\r
 {\r
-  void *afile = NULL;\r
   int ret;\r
 \r
-  afile = open_save_file(fname, is_save);\r
-  if (afile == NULL)\r
-    return -1;\r
-\r
   if (is_save)\r
     ret = state_save(afile);\r
   else {\r
@@ -617,10 +608,35 @@ int PicoState(const char *fname, int is_save)
     Pico.m.dirtyPal = 1;\r
   }\r
 \r
+  return ret;\r
+}\r
+\r
+int PicoState(const char *fname, int is_save)\r
+{\r
+  void *afile = NULL;\r
+  int ret;\r
+\r
+  afile = open_save_file(fname, is_save);\r
+  if (afile == NULL)\r
+    return -1;\r
+\r
+  ret = pico_state_internal(afile, is_save);\r
   areaClose(afile);\r
   return ret;\r
 }\r
 \r
+int PicoStateFP(void *afile, int is_save,\r
+  arearw *read, arearw *write, areaeof *eof, areaseek *seek)\r
+{\r
+  areaRead  = read;\r
+  areaWrite = write;\r
+  areaEof   = eof;\r
+  areaSeek  = seek;\r
+  areaClose = NULL;\r
+\r
+  return pico_state_internal(afile, is_save);\r
+}\r
+\r
 int PicoStateLoadGfx(const char *fname)\r
 {\r
   void *afile;\r
diff --git a/pico/state.h b/pico/state.h
new file mode 100644 (file)
index 0000000..1d38022
--- /dev/null
@@ -0,0 +1,9 @@
+#include <stdlib.h>
+
+typedef size_t (arearw)(void *p, size_t _size, size_t _n, void *file);
+typedef size_t (areaeof)(void *file);
+typedef int    (areaseek)(void *file, long offset, int whence);
+typedef int    (areaclose)(void *file);
+
+int PicoStateFP(void *afile, int is_save,
+  arearw *read, arearw *write, areaeof *eof, areaseek *seek);
index 15a83ba..d46cc4a 100644 (file)
@@ -17,6 +17,7 @@
 #endif
 
 #include <pico/pico_int.h>
+#include <pico/state.h>
 #include "common/input_pico.h"
 #include "common/version.h"
 #include "libretro.h"
@@ -226,20 +227,124 @@ void retro_get_system_av_info(struct retro_system_av_info *info)
        info->geometry.aspect_ratio = 4.0 / 3.0;
 }
 
-/* savestates - TODO */
+/* savestates */
+struct savestate_state {
+       const char *load_buf;
+       char *save_buf;
+       size_t size;
+       size_t pos;
+};
+
+size_t state_read(void *p, size_t size, size_t nmemb, void *file)
+{
+       struct savestate_state *state = file;
+       size_t bsize = size * nmemb;
+
+       if (state->pos + bsize > state->size) {
+               lprintf("savestate error: %u/%u\n",
+                       state->pos + bsize, state->size);
+               bsize = state->size - state->pos;
+               if ((int)bsize <= 0)
+                       return 0;
+       }
+
+       memcpy(p, state->load_buf + state->pos, bsize);
+       state->pos += bsize;
+       return bsize;
+}
+
+size_t state_write(void *p, size_t size, size_t nmemb, void *file)
+{
+       struct savestate_state *state = file;
+       size_t bsize = size * nmemb;
+
+       if (state->pos + bsize > state->size) {
+               lprintf("savestate error: %u/%u\n",
+                       state->pos + bsize, state->size);
+               bsize = state->size - state->pos;
+               if ((int)bsize <= 0)
+                       return 0;
+       }
+
+       memcpy(state->save_buf + state->pos, p, bsize);
+       state->pos += bsize;
+       return bsize;
+}
+
+size_t state_skip(void *p, size_t size, size_t nmemb, void *file)
+{
+       struct savestate_state *state = file;
+       size_t bsize = size * nmemb;
+
+       state->pos += bsize;
+       return bsize;
+}
+
+size_t state_eof(void *file)
+{
+       struct savestate_state *state = file;
+
+       return state->pos >= state->size;
+}
+
+int state_fseek(void *file, long offset, int whence)
+{
+       struct savestate_state *state = file;
+
+       switch (whence) {
+       case SEEK_SET:
+               state->pos = offset;
+               break;
+       case SEEK_CUR:
+               state->pos += offset;
+               break;
+       case SEEK_END:
+               state->pos = state->size + offset;
+               break;
+       }
+       return (int)state->pos;
+}
+
+/* savestate sizes vary wildly depending if cd/32x or
+ * carthw is active, so run the whole thing to get size */
 size_t retro_serialize_size(void) 
 { 
-       return 0;
+       struct savestate_state state = { 0, };
+       int ret;
+
+       ret = PicoStateFP(&state, 1, NULL, state_skip, NULL, state_fseek);
+       if (ret != 0)
+               return 0;
+
+       return state.pos;
 }
 
 bool retro_serialize(void *data, size_t size)
 { 
-       return false;
+       struct savestate_state state = { 0, };
+       int ret;
+
+       state.save_buf = data;
+       state.size = size;
+       state.pos = 0;
+
+       ret = PicoStateFP(&state, 1, NULL, state_write,
+               NULL, state_fseek);
+       return ret == 0;
 }
 
 bool retro_unserialize(const void *data, size_t size)
 {
-       return false;
+       struct savestate_state state = { 0, };
+       int ret;
+
+       state.load_buf = data;
+       state.size = size;
+       state.pos = 0;
+
+       ret = PicoStateFP(&state, 0, state_read, NULL,
+               state_eof, state_fseek);
+       return ret == 0;
 }
 
 /* cheats - TODO */