From aa59ee257e2c31db78cc2e2df3a6ca3857aa6ade Mon Sep 17 00:00:00 2001 From: StapleButter Date: Sat, 15 Sep 2018 02:04:21 +0200 Subject: [PATCH] base for savestate crapo. I'm not quite settled yet, so before I can get into the real meat, I figured I'd address some 'popular request' items. --- melonDS.cbp | 2 + src/Savestate.cpp | 262 ++++++++++++++++++++++++++++++++++++++++++++++ src/Savestate.h | 55 ++++++++++ 3 files changed, 319 insertions(+) create mode 100644 src/Savestate.cpp create mode 100644 src/Savestate.h diff --git a/melonDS.cbp b/melonDS.cbp index 44eb6a34..d53212bf 100644 --- a/melonDS.cbp +++ b/melonDS.cbp @@ -137,6 +137,8 @@ + + diff --git a/src/Savestate.cpp b/src/Savestate.cpp new file mode 100644 index 00000000..9e8a37a6 --- /dev/null +++ b/src/Savestate.cpp @@ -0,0 +1,262 @@ +/* + Copyright 2016-2017 StapleButter + + This file is part of melonDS. + + melonDS 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 Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#include "Savestate.h" + +/* + Savestate format + + header: + 00 - magic MELN + 04 - version major + 06 - version minor + 08 - length + 0C - reserved + + section header: + 00 - section magic + 04 - section length + 08 - reserved + 0C - reserved + + Implementation details + + version difference: + * different major means savestate file is incompatible + * different minor means adjustments may have to be made +*/ + +Savestate::Savestate(char* filename, bool save) +{ + char* magic = "MELN"; + + Error = false; + + if (save) + { + Saving = true; + file = fopen(filename, "wb"); + if (!file) + { + printf("savestate: file %s doesn't exist\n", filename); + Error = true; + return; + } + + VersionMajor = SAVESTATE_MAJOR; + VersionMinor = SAVESTATE_MINOR; + + fwrite(magic, 4, 1, file); + fwrite(&VersionMajor, 2, 1, file); + fwrite(&VersionMinor, 2, 1, file); + fseek(file, 8, SEEK_CUR); // length to be fixed later + } + else + { + Saving = false; + file = fopen(filename, "rb"); + if (!file) + { + printf("savestate: file %s doesn't exist\n", filename); + Error = true; + return; + } + + u32 len; + fseek(file, 0, SEEK_END); + len = (u32)ftell(file); + fseek(file, 0, SEEK_SET); + + u32 buf; + + fread(&buf, 4, 1, file); + if (buf != ((u32*)magic)[0]) + { + printf("savestate: invalid magic %08X\n", buf); + Error = true; + return; + } + + fread(&VersionMajor, 2, 1, file); + if (VersionMajor != SAVESTATE_MAJOR) + { + printf("savestate: bad version major %d, expecting %d\n", VersionMajor, SAVESTATE_MAJOR); + Error = true; + return; + } + + fread(&VersionMinor, 2, 1, file); + // TODO: handle it??? + + fread(&buf, 4, 1, file); + if (buf != len) + { + printf("savestate: bad length %d\n", buf); + Error = true; + return; + } + + fseek(file, 4, SEEK_CUR); + } + + CurSection = -1; +} + +Savestate::~Savestate() +{ + if (Error) return; + + if (Saving) + { + if (CurSection != -1) + { + u32 pos = (u32)ftell(file); + fseek(file, CurSection+4, SEEK_SET); + + u32 len = pos - CurSection; + fwrite(&len, 4, 1, file); + + fseek(file, pos, SEEK_SET); + } + + fseek(file, 0, SEEK_END); + u32 len = (u32)ftell(file); + fseek(file, 8, SEEK_SET); + fwrite(&len, 4, 1, file); + } + + if (file) fclose(file); +} + +void Savestate::Section(char* magic) +{ + if (Error) return; + + if (Saving) + { + if (CurSection != -1) + { + u32 pos = (u32)ftell(file); + fseek(file, CurSection+4, SEEK_SET); + + u32 len = pos - CurSection; + fwrite(&len, 4, 1, file); + + fseek(file, pos, SEEK_SET); + } + + fwrite(magic, 4, 1, file); + fseek(file, 12, SEEK_CUR); + } + else + { + fseek(file, 0x10, SEEK_SET); + + for (;;) + { + u32 buf; + + fread(&buf, 4, 1, file); + if (buf != ((u32*)magic)[0]) + { + if (buf == 0) + { + printf("savestate: section %s not found. blarg\n", magic); + return; + } + + fread(&buf, 4, 1, file); + fseek(file, buf-8, SEEK_CUR); + continue; + } + + fseek(file, 8, SEEK_CUR); + break; + } + } +} + +void Savestate::Var8(u8* var) +{ + if (Error) return; + + if (Saving) + { + fwrite(var, 1, 1, file); + } + else + { + fread(var, 1, 1, file); + } +} + +void Savestate::Var16(u16* var) +{ + if (Error) return; + + if (Saving) + { + fwrite(var, 2, 1, file); + } + else + { + fread(var, 2, 1, file); + } +} + +void Savestate::Var32(u32* var) +{ + if (Error) return; + + if (Saving) + { + fwrite(var, 4, 1, file); + } + else + { + fread(var, 4, 1, file); + } +} + +void Savestate::Var64(u64* var) +{ + if (Error) return; + + if (Saving) + { + fwrite(var, 8, 1, file); + } + else + { + fread(var, 8, 1, file); + } +} + +void Savestate::VarArray(void* data, u32 len) +{ + if (Error) return; + + if (Saving) + { + fwrite(data, len, 1, file); + } + else + { + fread(data, len, 1, file); + } +} diff --git a/src/Savestate.h b/src/Savestate.h new file mode 100644 index 00000000..3c067641 --- /dev/null +++ b/src/Savestate.h @@ -0,0 +1,55 @@ +/* + Copyright 2016-2017 StapleButter + + This file is part of melonDS. + + melonDS 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 Foundation, either version 3 of the License, or (at your option) + any later version. + + melonDS 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 melonDS. If not, see http://www.gnu.org/licenses/. +*/ + +#ifndef SAVESTATE_H +#define SAVESTATE_H + +#include +#include "types.h" + +#define SAVESTATE_MAJOR 1 +#define SAVESTATE_MINOR 0 + +class Savestate +{ +public: + Savestate(char* filename, bool save); + ~Savestate(); + + bool Error; + + bool Saving; + u32 VersionMajor; + u32 VersionMinor; + + u32 CurSection; + + void Section(char* magic); + + void Var8(u8* var); + void Var16(u16* var); + void Var32(u32* var); + void Var64(u64* var); + + void VarArray(void* data, u32 len); + +private: + FILE* file; +}; + +#endif // SAVESTATE_H