gpsp/savestate.c

152 lines
3.5 KiB
C

#include "common.h"
const u8 *state_mem_read_ptr;
u8 *state_mem_write_ptr;
const u8* bson_find_key(const u8 *srcp, const char *key)
{
unsigned keyl = strlen(key) + 1;
unsigned doclen = bson_read_u32(srcp);
const u8* p = &srcp[4];
while (*p != 0 && (p - srcp) < doclen) {
u8 tp = *p;
unsigned tlen = strlen((char*)&p[1]) + 1;
if (keyl == tlen && !memcmp(key, &p[1], tlen))
return &p[tlen + 1];
p += 1 + tlen;
if (tp == 3 || tp == 4)
p += bson_read_u32(p);
else if (tp == 5)
p += bson_read_u32(p) + 1 + 4;
else if (tp == 0x10)
p += 4;
}
return NULL;
}
bool bson_read_int32(const u8 *srcp, const char *key, u32* value)
{
const u8* p = srcp ? bson_find_key(srcp, key) : NULL;
if (!p)
return false;
*value = bson_read_u32(p);
return true;
}
bool bson_read_int32_array(const u8 *srcp, const char *key, u32* value, unsigned cnt)
{
const u8* p = srcp ? bson_find_key(srcp, key) : NULL;
if (p) {
unsigned arrsz = bson_read_u32(p);
p += 4;
if (arrsz < 5)
return false;
arrsz = (arrsz - 5) >> 3;
while (arrsz--) {
p += 4; // type and name
*value++ = bson_read_u32(p);
p += 4; // value
}
return true;
}
*value = bson_read_u32(p);
return false;
}
bool bson_read_bytes(const u8 *srcp, const char *key, void* buffer, unsigned cnt)
{
const u8* p = srcp ? bson_find_key(srcp, key) : NULL;
if (p) {
unsigned bufsz = bson_read_u32(p);
if (bufsz != cnt)
return false;
// Skip byte array type and size
memcpy(buffer, &p[5], cnt);
return true;
}
return false;
}
bool gba_load_state(const void* src)
{
u32 i, tmp;
u8* srcptr = (u8*)src;
u32 docsize = bson_read_u32(srcptr);
if (docsize != GBA_STATE_MEM_SIZE)
return false;
if (!bson_read_int32(srcptr, "info-magic", &tmp) || tmp != GBA_STATE_MAGIC)
return false;
if (!bson_read_int32(srcptr, "info-version", &tmp) || tmp != GBA_STATE_VERSION)
return false;
if (!(cpu_read_savestate(srcptr) &&
input_read_savestate(srcptr) &&
main_read_savestate(srcptr) &&
memory_read_savestate(srcptr) &&
sound_read_savestate(srcptr)))
{
// TODO: reset state instead! Should revert instead??
return false;
}
// Generate converted palette (since it is not saved)
for(i = 0; i < 512; i++)
{
palette_ram_converted[i] = convert_palette(eswap16(palette_ram[i]));
}
video_reload_counters();
// Reset most of the frame state and dynarec state
#ifdef HAVE_DYNAREC
if (dynarec_enable)
flush_dynarec_caches();
#endif
instruction_count = 0;
reg[COMPLETED_FRAME] = 0;
reg[OAM_UPDATED] = 1;
return true;
}
void gba_save_state(void* dst)
{
u8 *stptr = (u8*)dst;
u8 *wrptr = (u8*)dst;
// Initial bson size
bson_write_u32(wrptr, 0);
// Add some info fields
bson_write_int32(wrptr, "info-magic", GBA_STATE_MAGIC);
bson_write_int32(wrptr, "info-version", GBA_STATE_VERSION);
wrptr += cpu_write_savestate(wrptr);
wrptr += input_write_savestate(wrptr);
wrptr += main_write_savestate(wrptr);
wrptr += memory_write_savestate(wrptr);
wrptr += sound_write_savestate(wrptr);
// The padding space is pushed into a padding field for easy parsing
{
unsigned padsize = GBA_STATE_MEM_SIZE - (wrptr - stptr);
padsize -= 1 + 9 + 4 + 1 + 1;
*wrptr++ = 0x05; // Byte array
bson_write_cstring(wrptr, "zpadding");
bson_write_u32(wrptr, padsize);
*wrptr++ = 0;
wrptr += padsize;
}
*wrptr++ = 0;
// Update the doc size
bson_write_u32(stptr, wrptr - stptr);
}