diff --git a/Makefile.common b/Makefile.common index 5ea6f35f23..83cf8a1f55 100644 --- a/Makefile.common +++ b/Makefile.common @@ -128,6 +128,7 @@ OBJ += frontend/frontend.o \ tasks/tasks_internal.o \ tasks/task_content.o \ tasks/task_save_ram.o \ + tasks/task_save_state.o \ tasks/task_file_transfer.o \ tasks/task_image.o \ libretro-common/encodings/encoding_utf.o \ diff --git a/griffin/griffin.c b/griffin/griffin.c index 1817ee4adb..9a083112c5 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -814,6 +814,7 @@ DATA RUNLOOP ============================================================ */ #include "../tasks/task_content.c" #include "../tasks/task_save_ram.c" +#include "../tasks/task_save_state.c" #include "../tasks/task_image.c" #include "../tasks/task_file_transfer.c" #ifdef HAVE_ZLIB diff --git a/tasks/task_content.c b/tasks/task_content.c index 89314e0f0d..7c1653b755 100644 --- a/tasks/task_content.c +++ b/tasks/task_content.c @@ -104,13 +104,6 @@ #define MAX_ARGS 32 -struct sram_block -{ - unsigned type; - void *data; - size_t size; -}; - typedef struct content_stream { uint32_t a; @@ -1038,179 +1031,6 @@ bool dump_to_file_desperate(const void *data, return true; } - -/** - * save_state: - * @path : path of saved state that shall be written to. - * - * Save a state from memory to disk. - * - * Returns: true if successful, false otherwise. - **/ -bool content_save_state(const char *path) -{ - retro_ctx_serialize_info_t serial_info; - retro_ctx_size_info_t info; - bool ret = false; - void *data = NULL; - - core_serialize_size(&info); - - RARCH_LOG("%s: \"%s\".\n", - msg_hash_to_str(MSG_SAVING_STATE), - path); - - if (info.size == 0) - return false; - - data = malloc(info.size); - - if (!data) - return false; - - RARCH_LOG("%s: %d %s.\n", - msg_hash_to_str(MSG_STATE_SIZE), - (int)info.size, - msg_hash_to_str(MSG_BYTES)); - - serial_info.data = data; - serial_info.size = info.size; - ret = core_serialize(&serial_info); - - if (ret) - ret = filestream_write_file(path, data, info.size); - else - { - RARCH_ERR("%s \"%s\".\n", - msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), - path); - } - - free(data); - - return ret; -} - -/** - * content_load_state: - * @path : path that state will be loaded from. - * - * Load a state from disk to memory. - * - * Returns: true if successful, false otherwise. - **/ -bool content_load_state(const char *path) -{ - unsigned i; - ssize_t size; - retro_ctx_serialize_info_t serial_info; - unsigned num_blocks = 0; - void *buf = NULL; - struct sram_block *blocks = NULL; - settings_t *settings = config_get_ptr(); - global_t *global = global_get_ptr(); - bool ret = filestream_read_file(path, &buf, &size); - - RARCH_LOG("%s: \"%s\".\n", - msg_hash_to_str(MSG_LOADING_STATE), - path); - - if (!ret || size < 0) - goto error; - - RARCH_LOG("%s: %u %s.\n", - msg_hash_to_str(MSG_STATE_SIZE), - (unsigned)size, - msg_hash_to_str(MSG_BYTES)); - - if (settings->block_sram_overwrite && global->savefiles - && global->savefiles->size) - { - RARCH_LOG("%s.\n", - msg_hash_to_str(MSG_BLOCKING_SRAM_OVERWRITE)); - blocks = (struct sram_block*) - calloc(global->savefiles->size, sizeof(*blocks)); - - if (blocks) - { - num_blocks = global->savefiles->size; - for (i = 0; i < num_blocks; i++) - blocks[i].type = global->savefiles->elems[i].attr.i; - } - } - - - for (i = 0; i < num_blocks; i++) - { - retro_ctx_memory_info_t mem_info; - - mem_info.id = blocks[i].type; - core_get_memory(&mem_info); - - blocks[i].size = mem_info.size; - } - - for (i = 0; i < num_blocks; i++) - if (blocks[i].size) - blocks[i].data = malloc(blocks[i].size); - - /* Backup current SRAM which is overwritten by unserialize. */ - for (i = 0; i < num_blocks; i++) - { - if (blocks[i].data) - { - retro_ctx_memory_info_t mem_info; - const void *ptr = NULL; - - mem_info.id = blocks[i].type; - - core_get_memory(&mem_info); - - ptr = mem_info.data; - if (ptr) - memcpy(blocks[i].data, ptr, blocks[i].size); - } - } - - serial_info.data_const = buf; - serial_info.size = size; - ret = core_unserialize(&serial_info); - - /* Flush back. */ - for (i = 0; i < num_blocks; i++) - { - if (blocks[i].data) - { - retro_ctx_memory_info_t mem_info; - void *ptr = NULL; - - mem_info.id = blocks[i].type; - - core_get_memory(&mem_info); - - ptr = mem_info.data; - if (ptr) - memcpy(ptr, blocks[i].data, blocks[i].size); - } - } - - for (i = 0; i < num_blocks; i++) - free(blocks[i].data); - free(blocks); - free(buf); - - if (!ret) - goto error; - - return true; - -error: - RARCH_ERR("%s \"%s\".\n", - msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE), - path); - return false; -} - /* Load the content into memory. */ static bool load_content_into_memory( struct retro_game_info *info, diff --git a/tasks/task_save_state.c b/tasks/task_save_state.c new file mode 100644 index 0000000000..f0b062771f --- /dev/null +++ b/tasks/task_save_state.c @@ -0,0 +1,210 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2011-2016 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../core.h" +#include "../msg_hash.h" +#include "../verbosity.h" +#include "tasks_internal.h" + +struct sram_block +{ + unsigned type; + void *data; + size_t size; +}; + +/* TODO/FIXME - turn this into actual task */ + +/** + * save_state: + * @path : path of saved state that shall be written to. + * + * Save a state from memory to disk. + * + * Returns: true if successful, false otherwise. + **/ +bool content_save_state(const char *path) +{ + retro_ctx_serialize_info_t serial_info; + retro_ctx_size_info_t info; + bool ret = false; + void *data = NULL; + + core_serialize_size(&info); + + RARCH_LOG("%s: \"%s\".\n", + msg_hash_to_str(MSG_SAVING_STATE), + path); + + if (info.size == 0) + return false; + + data = malloc(info.size); + + if (!data) + return false; + + RARCH_LOG("%s: %d %s.\n", + msg_hash_to_str(MSG_STATE_SIZE), + (int)info.size, + msg_hash_to_str(MSG_BYTES)); + + serial_info.data = data; + serial_info.size = info.size; + ret = core_serialize(&serial_info); + + if (ret) + ret = filestream_write_file(path, data, info.size); + else + { + RARCH_ERR("%s \"%s\".\n", + msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), + path); + } + + free(data); + + return ret; +} + +/** + * content_load_state: + * @path : path that state will be loaded from. + * + * Load a state from disk to memory. + * + * Returns: true if successful, false otherwise. + **/ +bool content_load_state(const char *path) +{ + unsigned i; + ssize_t size; + retro_ctx_serialize_info_t serial_info; + unsigned num_blocks = 0; + void *buf = NULL; + struct sram_block *blocks = NULL; + settings_t *settings = config_get_ptr(); + global_t *global = global_get_ptr(); + bool ret = filestream_read_file(path, &buf, &size); + + RARCH_LOG("%s: \"%s\".\n", + msg_hash_to_str(MSG_LOADING_STATE), + path); + + if (!ret || size < 0) + goto error; + + RARCH_LOG("%s: %u %s.\n", + msg_hash_to_str(MSG_STATE_SIZE), + (unsigned)size, + msg_hash_to_str(MSG_BYTES)); + + if (settings->block_sram_overwrite && global->savefiles + && global->savefiles->size) + { + RARCH_LOG("%s.\n", + msg_hash_to_str(MSG_BLOCKING_SRAM_OVERWRITE)); + blocks = (struct sram_block*) + calloc(global->savefiles->size, sizeof(*blocks)); + + if (blocks) + { + num_blocks = global->savefiles->size; + for (i = 0; i < num_blocks; i++) + blocks[i].type = global->savefiles->elems[i].attr.i; + } + } + + + for (i = 0; i < num_blocks; i++) + { + retro_ctx_memory_info_t mem_info; + + mem_info.id = blocks[i].type; + core_get_memory(&mem_info); + + blocks[i].size = mem_info.size; + } + + for (i = 0; i < num_blocks; i++) + if (blocks[i].size) + blocks[i].data = malloc(blocks[i].size); + + /* Backup current SRAM which is overwritten by unserialize. */ + for (i = 0; i < num_blocks; i++) + { + if (blocks[i].data) + { + retro_ctx_memory_info_t mem_info; + const void *ptr = NULL; + + mem_info.id = blocks[i].type; + + core_get_memory(&mem_info); + + ptr = mem_info.data; + if (ptr) + memcpy(blocks[i].data, ptr, blocks[i].size); + } + } + + serial_info.data_const = buf; + serial_info.size = size; + ret = core_unserialize(&serial_info); + + /* Flush back. */ + for (i = 0; i < num_blocks; i++) + { + if (blocks[i].data) + { + retro_ctx_memory_info_t mem_info; + void *ptr = NULL; + + mem_info.id = blocks[i].type; + + core_get_memory(&mem_info); + + ptr = mem_info.data; + if (ptr) + memcpy(ptr, blocks[i].data, blocks[i].size); + } + } + + for (i = 0; i < num_blocks; i++) + free(blocks[i].data); + free(blocks); + free(buf); + + if (!ret) + goto error; + + return true; + +error: + RARCH_ERR("%s \"%s\".\n", + msg_hash_to_str(MSG_FAILED_TO_LOAD_STATE), + path); + return false; +} diff --git a/tasks/tasks_internal.h b/tasks/tasks_internal.h index 02606b7cc3..b819e6011e 100644 --- a/tasks/tasks_internal.h +++ b/tasks/tasks_internal.h @@ -145,6 +145,8 @@ bool content_save_ram_file(ram_type_t *ram); bool content_load_ram_file(ram_type_t *ram); bool dump_to_file_desperate(const void *data, size_t size, unsigned type); +bool content_save_state(const char *path); +bool content_load_state(const char *path); #ifdef __cplusplus }