int MDFNI_LoadState(const char *fname, const char *suffix) { if(!MDFNGameInfo->StateAction) return 0; MDFND_SetStateStatus(NULL); /* For network play and movies, be load the state locally, and then save the state to a temporary buffer, and send or record that. This ensures that if an older state is loaded that is missing some information expected in newer save states, desynchronization won't occur(at least not from this ;)). */ if(MDFNSS_Load(fname, suffix)) { if(MDFNnetplay) { NetplaySendState(); } if(MDFNMOV_IsRecording()) MDFNMOV_RecordState(); return 1; } return 0; }
static void RecvState(const uint32 clen) { StateMem sm; std::vector<uint8> cbuf; std::vector<uint8> buf; memset(&sm, 0, sizeof(StateMem)); if(clen < 4) { throw MDFN_Error(0, _("Compressed save state data is too small: %u"), clen); } if(clen > 8 * 1024 * 1024) // Compressed length sanity check - 8 MiB max. { throw MDFN_Error(0, _("Compressed save state data is too large: %u"), clen); } cbuf.resize(clen); MDFND_RecvData(&cbuf[0], clen); uLongf len = MDFN_de32lsb(&cbuf[0]); if(len > 12 * 1024 * 1024) // Uncompressed length sanity check - 12 MiB max. { throw MDFN_Error(0, _("Uncompressed save state data is too large: %llu"), (unsigned long long)len); } buf.resize(len); uncompress((Bytef *)&buf[0], &len, (Bytef *)&cbuf[0] + 4, clen - 4); sm.data = &buf[0]; sm.len = len; if(!MDFNSS_LoadSM(&sm, 0, 0)) { throw MDFN_Error(0, _("Error during save state loading.")); } if(MDFNMOV_IsRecording()) MDFNMOV_RecordState(); }
static void StopRecording(void) { MDFNMOV_RecordState(); if(MDFN_StateEvilIsRunning()) { MDFN_StateEvilFlushMovieLove(); } gzclose(slots[current-1]); MovieStatus[current - 1] = 1; RecentlySavedMovie = current - 1; current=0; MDFN_DispMessage(_("Movie recording stopped.")); if(RewindBuffer.data) { //puts("Oops"); free(RewindBuffer.data); RewindBuffer.data = NULL; } }
bool MDFNI_LoadState(const char *fname, const char *suffix) noexcept { bool ret = true; try { if(!MDFNGameInfo->StateAction) { throw MDFN_Error(0, _("Module \"%s\" doesn't support save states."), MDFNGameInfo->shortname); } /* For network play and movies, be load the state locally, and then save the state to a temporary buffer, and send or record that. This ensures that if an older state is loaded that is missing some information expected in newer save states, desynchronization won't occur(at least not from this ;)). */ { GZFileStream st(fname ? std::string(fname) : MDFN_MakeFName(MDFNMKF_STATE,CurrentState,suffix), GZFileStream::MODE::READ); uint8 header[32]; uint32 st_len; st.read(header, 32); st_len = MDFN_de32lsb(header + 16 + 4) & 0x7FFFFFFF; if(st_len < 32) throw MDFN_Error(0, _("Save state header length field is bad.")); MemoryStream sm(st_len, -1); memcpy(sm.map(), header, 32); st.read(sm.map() + 32, st_len - 32); MDFNSS_LoadSM(&sm, false); } if(MDFNnetplay) { NetplaySendState(); } if(MDFNMOV_IsRecording()) MDFNMOV_RecordState(); MDFND_SetStateStatus(NULL); if(!fname && !suffix) { SaveStateStatus[CurrentState] = true; MDFN_DispMessage(_("State %d loaded."), CurrentState); } } catch(std::exception &e) { if(!fname && !suffix) MDFN_DispMessage(_("State %d load error: %s"), CurrentState, e.what()); else MDFN_PrintError("%s", e.what()); if(MDFNnetplay) MDFND_NetplayText(e.what(), false); ret = false; } return(ret); }