static bool bsv_parse_header(const uint32_t *header, uint32_t magic) { uint32_t in_bsv = swap_if_little32(header[MAGIC_INDEX]); if (in_bsv != BSV_MAGIC) { RARCH_ERR("BSV magic mismatch, got 0x%x, expected 0x%x.\n", in_bsv, BSV_MAGIC); return false; } uint32_t in_magic = swap_if_big32(header[SERIALIZER_INDEX]); if (in_magic != magic) { RARCH_ERR("Magic mismatch, got 0x%x, expected 0x%x.\n", in_magic, magic); return false; } uint32_t in_crc = swap_if_big32(header[CRC_INDEX]); if (in_crc != g_extern.cart_crc) { RARCH_ERR("CRC32 mismatch, got 0x%x, expected 0x%x.\n", in_crc, g_extern.cart_crc); return false; } uint32_t in_state_size = swap_if_big32(header[STATE_SIZE_INDEX]); if (in_state_size != pretro_serialize_size()) { RARCH_ERR("Serialization size mismatch, got 0x%x, expected 0x%x.\n", (unsigned)in_state_size, (unsigned)pretro_serialize_size()); return false; } return true; }
static void event_main_state(unsigned cmd) { char path[PATH_MAX_LENGTH] = {0}; char msg[PATH_MAX_LENGTH] = {0}; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); if (settings->state_slot > 0) snprintf(path, sizeof(path), "%s%d", global->savestate_name, settings->state_slot); else if (settings->state_slot < 0) fill_pathname_join_delim(path, global->savestate_name, "auto", '.', sizeof(path)); else strlcpy(path, global->savestate_name, sizeof(path)); if (pretro_serialize_size()) { if (cmd == EVENT_CMD_SAVE_STATE) event_save_state(path, msg, sizeof(msg)); else if (cmd == EVENT_CMD_LOAD_STATE) event_load_state(path, msg, sizeof(msg)); } else strlcpy(msg, "Core does not support save states.", sizeof(msg)); rarch_main_msg_queue_push(msg, 2, 180, true); RARCH_LOG("%s\n", msg); }
bool save_state(const char *path) { RARCH_LOG("Saving state: \"%s\".\n", path); size_t size = pretro_serialize_size(); if (size == 0) return false; void *data = malloc(size); if (!data) { RARCH_ERR("Failed to allocate memory for save state buffer.\n"); return false; } RARCH_LOG("State size: %d bytes.\n", (int)size); bool ret = pretro_serialize(data, size); if (ret) ret = write_file(path, data, size); if (!ret) RARCH_ERR("Failed to save state to \"%s\".\n", path); free(data); return ret; }
static uint32_t *bsv_header_generate(size_t *size, uint32_t magic) { uint32_t bsv_header[4] = {0}; size_t serialize_size = pretro_serialize_size(); size_t header_size = sizeof(bsv_header) + serialize_size; *size = header_size; uint32_t *header = (uint32_t*)malloc(header_size); if (!header) return NULL; bsv_header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC); bsv_header[SERIALIZER_INDEX] = swap_if_big32(magic); bsv_header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc); bsv_header[STATE_SIZE_INDEX] = swap_if_big32(serialize_size); if (serialize_size && !pretro_serialize(header + 4, serialize_size)) { free(header); return NULL; } memcpy(header, bsv_header, sizeof(bsv_header)); return header; }
static void event_main_state(unsigned cmd) { char path[PATH_MAX_LENGTH] = {0}; char msg[PATH_MAX_LENGTH] = {0}; global_t *global = global_get_ptr(); settings_t *settings = config_get_ptr(); if (settings->state_slot > 0) snprintf(path, sizeof(path), "%s%d", global->name.savestate, settings->state_slot); else if (settings->state_slot < 0) fill_pathname_join_delim(path, global->name.savestate, "auto", '.', sizeof(path)); else strlcpy(path, global->name.savestate, sizeof(path)); if (pretro_serialize_size()) { switch (cmd) { case EVENT_CMD_SAVE_STATE: event_save_state(path, msg, sizeof(msg)); break; case EVENT_CMD_LOAD_STATE: event_load_state(path, msg, sizeof(msg)); break; } } else strlcpy(msg, msg_hash_to_str(MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES), sizeof(msg)); rarch_main_msg_queue_push(msg, 2, 180, true); RARCH_LOG("%s\n", msg); }
static void init_buffers(netplay_t *handle) { handle->buffer = (struct delta_frame*)calloc(handle->buffer_size, sizeof(*handle->buffer)); handle->state_size = pretro_serialize_size(); for (unsigned i = 0; i < handle->buffer_size; i++) { handle->buffer[i].state = malloc(handle->state_size); handle->buffer[i].is_simulated = true; } }
static bool get_info_spectate(netplay_t *handle) { if (!send_nickname(handle, handle->fd)) { RARCH_ERR("Failed to send nickname to host.\n"); return false; } if (!get_nickname(handle, handle->fd)) { RARCH_ERR("Failed to receive nickname from host.\n"); return false; } char msg[512]; snprintf(msg, sizeof(msg), "Connected to \"%s\"", handle->other_nick); msg_queue_push(g_extern.msg_queue, msg, 1, 180); RARCH_LOG("%s\n", msg); uint32_t header[4]; if (!recv_all(handle->fd, header, sizeof(header))) { RARCH_ERR("Cannot get header from host.\n"); return false; } size_t save_state_size = pretro_serialize_size(); if (!bsv_parse_header(header, implementation_magic_value())) { RARCH_ERR("Received invalid BSV header from host.\n"); return false; } void *buf = malloc(save_state_size); if (!buf) return false; size_t size = save_state_size; if (!recv_all(handle->fd, buf, size)) { RARCH_ERR("Failed to receive save state from host.\n"); free(buf); return false; } bool ret = true; if (save_state_size) ret = pretro_unserialize(buf, save_state_size); free(buf); return ret; }
static bool init_playback(bsv_movie_t *handle, const char *path) { handle->playback = true; handle->file = fopen(path, "rb"); if (!handle->file) { RARCH_ERR("Couldn't open BSV file \"%s\" for playback.\n", path); return false; } uint32_t header[4] = {0}; if (fread(header, sizeof(uint32_t), 4, handle->file) != 4) { RARCH_ERR("Couldn't read movie header.\n"); return false; } // Compatibility with old implementation that used incorrect documentation. if (swap_if_little32(header[MAGIC_INDEX]) != BSV_MAGIC && swap_if_big32(header[MAGIC_INDEX]) != BSV_MAGIC) { RARCH_ERR("Movie file is not a valid BSV1 file.\n"); return false; } if (swap_if_big32(header[CRC_INDEX]) != g_extern.cart_crc) RARCH_WARN("CRC32 checksum mismatch between ROM file and saved ROM checksum in replay file header; replay highly likely to desync on playback.\n"); uint32_t state_size = swap_if_big32(header[STATE_SIZE_INDEX]); if (state_size) { handle->state = (uint8_t*)malloc(state_size); handle->state_size = state_size; if (!handle->state) return false; if (fread(handle->state, 1, state_size, handle->file) != state_size) { RARCH_ERR("Couldn't read state from movie.\n"); return false; } if (pretro_serialize_size() == state_size) pretro_unserialize(handle->state, state_size); else RARCH_WARN("Movie format seems to have a different serializer version. Will most likely fail.\n"); } handle->min_file_pos = sizeof(header) + state_size; 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 save_state(const char *path) { bool ret = false; void *data = NULL; size_t size = pretro_serialize_size(); RARCH_LOG("%s: \"%s\".\n", msg_hash_to_str(MSG_SAVING_STATE), path); if (size == 0) return false; data = malloc(size); if (!data) return false; RARCH_LOG("%s: %d %s.\n", msg_hash_to_str(MSG_STATE_SIZE), (int)size, msg_hash_to_str(MSG_BYTES)); ret = pretro_serialize(data, size); if (ret) ret = retro_write_file(path, data, size); if (!ret) RARCH_ERR("%s \"%s\".\n", msg_hash_to_str(MSG_FAILED_TO_SAVE_STATE_TO), path); free(data); return ret; }
static bool init_record(bsv_movie_t *handle, const char *path) { handle->file = fopen(path, "wb"); if (!handle->file) { RARCH_ERR("Couldn't open BSV \"%s\" for recording.\n", path); return false; } uint32_t header[4] = {0}; // This value is supposed to show up as BSV1 in a HEX editor, big-endian. header[MAGIC_INDEX] = swap_if_little32(BSV_MAGIC); header[CRC_INDEX] = swap_if_big32(g_extern.cart_crc); uint32_t state_size = pretro_serialize_size(); header[STATE_SIZE_INDEX] = swap_if_big32(state_size); fwrite(header, 4, sizeof(uint32_t), handle->file); handle->min_file_pos = sizeof(header) + state_size; handle->state_size = state_size; if (state_size) { handle->state = (uint8_t*)malloc(state_size); if (!handle->state) return false; pretro_serialize(handle->state, state_size); fwrite(handle->state, 1, state_size, handle->file); } return true; }