// serialize.cpp : save states #include "serialize.h" #include "types.h" #include "hw/aica/aica_if.h" #include "hw/holly/sb.h" #include "hw/flashrom/nvmem.h" #include "hw/gdrom/gdrom_if.h" #include "hw/maple/maple_cfg.h" #include "hw/modem/modem.h" #include "hw/pvr/pvr.h" #include "hw/sh4/sh4_sched.h" #include "hw/sh4/sh4_mmr.h" #include "reios/reios.h" #include "hw/naomi/naomi.h" #include "hw/naomi/naomi_cart.h" #include "hw/bba/bba.h" #include "cfg/option.h" #include "imgread/common.h" #include "achievements/achievements.h" void dc_serialize(Serializer& ser) { aica::serialize(ser); sb_serialize(ser); nvmem::serialize(ser); gdrom::serialize(ser); mcfg_SerializeDevices(ser); pvr::serialize(ser); sh4::serialize(ser); ser << config::EmulateBBA.get(); if (config::EmulateBBA) bba_Serialize(ser); ModemSerialize(ser); sh4::serialize2(ser); libGDR_serialize(ser); naomi_Serialize(ser); ser << config::Broadcast.get(); ser << config::Cable.get(); ser << config::Region.get(); naomi_cart_serialize(ser); reios_serialize(ser); achievements::serialize(ser); DEBUG_LOG(SAVESTATE, "Saved %d bytes", (u32)ser.size()); } void dc_deserialize(Deserializer& deser) { DEBUG_LOG(SAVESTATE, "Loading state version %d", deser.version()); aica::deserialize(deser); sb_deserialize(deser); nvmem::deserialize(deser); gdrom::deserialize(deser); mcfg_DeserializeDevices(deser); pvr::deserialize(deser); sh4::deserialize(deser); deser >> config::EmulateBBA.get(); if (config::EmulateBBA) bba_Deserialize(deser); ModemDeserialize(deser); sh4::deserialize2(deser); libGDR_deserialize(deser); naomi_Deserialize(deser); deser >> config::Broadcast.get(); verify(config::Broadcast >= 0 && config::Broadcast <= 4); deser >> config::Cable.get(); verify(config::Cable >= 0 && config::Cable <= 3); deser >> config::Region.get(); verify(config::Region >= 0 && config::Region <= 3); naomi_cart_deserialize(deser); reios_deserialize(deser); achievements::deserialize(deser); sh4_sched_ffts(); DEBUG_LOG(SAVESTATE, "Loaded %d bytes", (u32)deser.size()); } Deserializer::Deserializer(const void *data, size_t limit, bool rollback) : SerializeBase(limit, rollback), data((const u8 *)data) { if (!memcmp(data, "RASTATE\001", 8)) { // RetroArch savestates now have several sections: MEM, ACHV, RPLY, etc. const u8 *p = this->data + 8; limit -= 8; while (limit > 8) { const u8 *section = p; u32 sectionSize = *(const u32 *)&p[4]; p += 8; limit -= 8; if (!memcmp(section, "MEM ", 4)) { // That's the part we're interested in this->data = p; this->limit = sectionSize; break; } sectionSize = (sectionSize + 7) & ~7; // align to 8 bytes if (limit < sectionSize) { limit = 0; break; } p += sectionSize; limit -= sectionSize; } if (limit <= 8) throw Exception("Can't find MEM section in RetroArch savestate"); } deserialize(_version); if (_version < V16) throw Exception("Unsupported version"); if (_version > Current) throw Exception("Version too recent"); if(_version >= V42 && settings.platform.isConsole()) { u32 ramSize; deserialize(ramSize); if (ramSize != settings.platform.ram_size) throw Exception("Selected RAM Size doesn't match Save State"); } } Serializer::Serializer(void *data, size_t limit, bool rollback) : SerializeBase(limit, rollback), data((u8 *)data) { Version v = Current; serialize(v); if (settings.platform.isConsole()) serialize(settings.platform.ram_size); }