198 lines
5.2 KiB
C
198 lines
5.2 KiB
C
/* gameplaySP
|
|
*
|
|
* Copyright (C) 2023 David Guillen Fandos <david@davidgf.net>
|
|
*
|
|
* This program 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 2 of
|
|
* the License, or (at your option) any later version.
|
|
*
|
|
* This program 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 this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
#include "common.h"
|
|
|
|
const u8 *state_mem_read_ptr;
|
|
u8 *state_mem_write_ptr;
|
|
|
|
bool bson_contains_key(const u8 *srcp, const char *key, u8 keytype)
|
|
{
|
|
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 tp == keytype; // Found it, check type
|
|
p += 1 + tlen;
|
|
if (tp == BSON_TYPE_DOC || tp == BSON_TYPE_ARR)
|
|
p += bson_read_u32(p);
|
|
else if (tp == BSON_TYPE_BIN)
|
|
p += bson_read_u32(p) + 1 + 4;
|
|
else if (tp == BSON_TYPE_INT32)
|
|
p += 4;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
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 == BSON_TYPE_DOC || tp == BSON_TYPE_ARR)
|
|
p += bson_read_u32(p);
|
|
else if (tp == BSON_TYPE_BIN)
|
|
p += bson_read_u32(p) + 1 + 4;
|
|
else if (tp == BSON_TYPE_INT32)
|
|
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;
|
|
|
|
// Validate that the state file makes sense before unconditionally reading it.
|
|
if (!cpu_check_savestate(srcptr) ||
|
|
!input_check_savestate(srcptr) ||
|
|
!main_check_savestate(srcptr) ||
|
|
!memory_check_savestate(srcptr) ||
|
|
!sound_check_savestate(srcptr))
|
|
return false;
|
|
|
|
if (!(cpu_read_savestate(srcptr) &&
|
|
input_read_savestate(srcptr) &&
|
|
main_read_savestate(srcptr) &&
|
|
memory_read_savestate(srcptr) &&
|
|
sound_read_savestate(srcptr)))
|
|
{
|
|
// TODO: this should not happen if the validation above is accurate.
|
|
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[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);
|
|
}
|
|
|
|
|