diff --git a/src/core/core.h b/src/core/core.h index b1e5563a0..728d70aab 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -121,6 +121,9 @@ struct mCore { void (*detachDebugger)(struct mCore*); struct mCheatDevice* (*cheatDevice)(struct mCore*); + + size_t (*savedataClone)(struct mCore*, void** sram); + bool (*savedataLoad)(struct mCore*, const void* sram, size_t size); }; #if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 diff --git a/src/core/serialize.c b/src/core/serialize.c index 5049f44a4..b64910e54 100644 --- a/src/core/serialize.c +++ b/src/core/serialize.c @@ -310,20 +310,16 @@ bool mCoreSaveStateNamed(struct mCore* core, struct VFile* vf, int flags) { mStateExtdataInit(&extdata); size_t stateSize = core->stateSize(core); if (flags & SAVESTATE_SAVEDATA) { - /* // TODO: A better way to do this would be nice - void* sram = malloc(SIZE_CART_FLASH1M); - struct VFile* svf = VFileFromMemory(sram, SIZE_CART_FLASH1M); - if (GBASavedataClone(&gba->memory.savedata, svf)) { + void* sram = NULL; + size_t size = core->savedataClone(core, &sram); + if (size) { struct mStateExtdataItem item = { - .size = svf->seek(svf, 0, SEEK_CUR), + .size = size, .data = sram, .clean = free }; mStateExtdataPut(&extdata, EXTDATA_SAVEDATA, &item); - } else { - free(sram); } - svf->close(svf);*/ } struct VFile* cheatVf = 0; struct mCheatDevice* device; @@ -419,11 +415,9 @@ bool mCoreLoadStateNamed(struct mCore* core, struct VFile* vf, int flags) { } } if (flags & SAVESTATE_SAVEDATA && mStateExtdataGet(&extdata, EXTDATA_SAVEDATA, &item)) { - /*struct VFile* svf = VFileFromMemory(item.data, item.size); - GBASavedataLoad(&gba->memory.savedata, svf); - if (svf) { - svf->close(svf); - }*/ + if (item.data) { + core->savedataLoad(core, item.data, item.size); + } } struct mCheatDevice* device; if (flags & SAVESTATE_CHEATS && (device = core->cheatDevice(core)) && mStateExtdataGet(&extdata, EXTDATA_CHEATS, &item)) { diff --git a/src/gb/core.c b/src/gb/core.c index 3fe2318d1..4ea53e673 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -409,6 +409,33 @@ static struct mCheatDevice* _GBCoreCheatDevice(struct mCore* core) { return gbcore->cheatDevice; } +static size_t _GBCoreSavedataClone(struct mCore* core, void** sram) { + struct GB* gb = core->board; + struct VFile* vf = gb->sramVf; + if (vf) { + *sram = malloc(vf->size(vf)); + vf->seek(vf, 0, SEEK_SET); + return vf->read(vf, *sram, vf->size(vf)); + } + *sram = malloc(0x20000); + memcpy(*sram, gb->memory.sram, 0x20000); + return 0x20000; +} + +static bool _GBCoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { + struct GB* gb = core->board; + struct VFile* vf = gb->sramVf; + if (vf) { + vf->seek(vf, 0, SEEK_SET); + return vf->write(vf, sram, size) > 0; + } + if (size > 0x20000) { + size = 0x20000; + } + memcpy(gb->memory.sram, sram, 0x20000); + return true; +} + struct mCore* GBCoreCreate(void) { struct GBCore* gbcore = malloc(sizeof(*gbcore)); struct mCore* core = &gbcore->d; @@ -470,5 +497,7 @@ struct mCore* GBCoreCreate(void) { core->attachDebugger = _GBCoreAttachDebugger; core->detachDebugger = _GBCoreDetachDebugger; core->cheatDevice = _GBCoreCheatDevice; + core->savedataClone = _GBCoreSavedataClone; + core->savedataLoad = _GBCoreSavedataLoad; return core; } diff --git a/src/gba/core.c b/src/gba/core.c index 8d9c7beb4..5667e5a24 100644 --- a/src/gba/core.c +++ b/src/gba/core.c @@ -13,6 +13,7 @@ #include "gba/extra/cli.h" #include "gba/overrides.h" #include "gba/renderers/video-software.h" +#include "gba/savedata.h" #include "gba/serialize.h" #include "util/memory.h" #include "util/patch.h" @@ -429,6 +430,41 @@ static struct mCheatDevice* _GBACoreCheatDevice(struct mCore* core) { return gbacore->cheatDevice; } +static size_t _GBACoreSavedataClone(struct mCore* core, void** sram) { + struct GBA* gba = core->board; + size_t size = GBASavedataSize(&gba->memory.savedata); + if (!size) { + *sram = NULL; + return 0; + } + *sram = malloc(size); + struct VFile* vf = VFileFromMemory(*sram, size); + if (!vf) { + free(*sram); + *sram = NULL; + return 0; + } + bool success = GBASavedataClone(&gba->memory.savedata, vf); + vf->close(vf); + if (!success) { + free(*sram); + *sram = NULL; + return 0; + } + return size; +} + +static bool _GBACoreSavedataLoad(struct mCore* core, const void* sram, size_t size) { + struct VFile* vf = VFileFromConstMemory(sram, size); + if (!vf) { + return false; + } + struct GBA* gba = core->board; + bool success = GBASavedataLoad(&gba->memory.savedata, vf); + vf->close(vf); + return success; +} + struct mCore* GBACoreCreate(void) { struct GBACore* gbacore = malloc(sizeof(*gbacore)); struct mCore* core = &gbacore->d; @@ -490,5 +526,7 @@ struct mCore* GBACoreCreate(void) { core->attachDebugger = _GBACoreAttachDebugger; core->detachDebugger = _GBACoreDetachDebugger; core->cheatDevice = _GBACoreCheatDevice; + core->savedataClone = _GBACoreSavedataClone; + core->savedataLoad = _GBACoreSavedataLoad; return core; } diff --git a/src/gba/savedata.c b/src/gba/savedata.c index 6a83ff1ce..091b13fb3 100644 --- a/src/gba/savedata.c +++ b/src/gba/savedata.c @@ -125,6 +125,27 @@ bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out) { return true; } +size_t GBASavedataSize(struct GBASavedata* savedata) { + switch (savedata->type) { + case SAVEDATA_SRAM: + return SIZE_CART_SRAM; + case SAVEDATA_FLASH512: + return SIZE_CART_FLASH512; + case SAVEDATA_FLASH1M: + return SIZE_CART_FLASH1M; + case SAVEDATA_EEPROM: + return SIZE_CART_EEPROM; + case SAVEDATA_FORCE_NONE: + return 0; + case SAVEDATA_AUTODETECT: + default: + if (savedata->vf) { + return savedata->vf->size(savedata->vf); + } + return 0; + } +} + bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in) { if (savedata->vf) { off_t read = 0; diff --git a/src/gba/savedata.h b/src/gba/savedata.h index fbc03f1c3..b248729ff 100644 --- a/src/gba/savedata.h +++ b/src/gba/savedata.h @@ -97,6 +97,7 @@ void GBASavedataDeinit(struct GBASavedata* savedata); void GBASavedataMask(struct GBASavedata* savedata, struct VFile* vf); void GBASavedataUnmask(struct GBASavedata* savedata); +size_t GBASavedataSize(struct GBASavedata* savedata); bool GBASavedataClone(struct GBASavedata* savedata, struct VFile* out); bool GBASavedataLoad(struct GBASavedata* savedata, struct VFile* in); void GBASavedataForceType(struct GBASavedata* savedata, enum SavedataType type, bool realisticTiming);