static int ReadStateChunks(FILE *st, int32 totalsize) { int t; uint32 size; int ret=1; while(totalsize > 0) { t=fgetc(st); if(t==EOF) break; if(!read32le(&size,st)) break; totalsize -= size + 5; switch(t) { case 1:if(!ReadStateChunk(st,SFCPU,size)) ret=0;break; case 2:if(!ReadStateChunk(st,SFCPUC,size)) ret=0; else { X.mooPI=X.P; // Quick and dirty hack. } break; case 3:if(!ReadStateChunk(st,FCEUPPU_STATEINFO,size)) ret=0;break; case 4:if(!ReadStateChunk(st,FCEUCTRL_STATEINFO,size)) ret=0;break; case 5:if(!ReadStateChunk(st,FCEUSND_STATEINFO,size)) ret=0;break; case 0x10:if(!ReadStateChunk(st,SFMDATA,size)) ret=0; break; default: if(fseek(st,size,SEEK_CUR)<0) goto endo;break; } } endo: return ret; }
static int ReadStateChunks(MEMFILE *st) { int t; uint32 size; int ret=1; for(;;) { t=mem_fgetc(st); if(t==EOF) break; if(!mem_read32(&size,st)) break; // printf("ReadStateChunks: chunk %i\n", t); switch(t) { case 1:if(!ReadStateChunk(st,SFCPU,size)) ret=0; #ifdef ASM_6502 asmcpu_unpack(); #endif break; case 2:if(!ReadStateChunk(st,SFCPUC,size)) ret=0; else { X.mooPI=X.P; // Quick and dirty hack. } break; case 3:if(!ReadStateChunk(st,FCEUPPU_STATEINFO,size)) ret=0;break; case 4:if(!ReadStateChunk(st,FCEUCTRL_STATEINFO,size)) ret=0;break; case 5:if(!ReadStateChunk(st,SFSND,size)) ret=0;break; case 0x10:if(!ReadStateChunk(st,SFMDATA,size)) ret=0;break; default:printf("ReadStateChunks: unknown chunk: %i\n", t); if(mem_fseek(st,size,SEEK_CUR)<0) goto endo;break; } } endo: return ret; }
/* This function is called by the game driver(NES, GB, GBA) to save a state. */ int MDFNSS_StateAction(StateMem *st, int load, int data_only, std::vector <SSDescriptor> §ions) { std::vector<SSDescriptor>::iterator section; if(load) { char sname[4]; for(section = sections.begin(); section != sections.end(); section++) { if(data_only) { ReadStateChunk(st, section->sf, ~0, 1); } else { int found = 0; uint32 tmp_size; uint32 total = 0; while(smem_read(st, (uint8 *)sname, 4) == 4) { if(!smem_read32le(st, &tmp_size)) return(0); total += tmp_size + 8; // Yay, we found the section if(!memcmp(sname, section->name, 4)) { if(!ReadStateChunk(st, section->sf, tmp_size, 0)) { printf("Error reading chunk: %.4s\n", section->name); return(0); } found = 1; break; } else { //puts("SEEK"); if(smem_seek(st, tmp_size, SEEK_CUR) < 0) { puts("Chunk seek failure"); return(0); } } } if(smem_seek(st, -(int)total, SEEK_CUR) < 0) { puts("Reverse seek error"); return(0); } if(!found && !section->optional) // Not found. We are sad! { printf("Chunk missing: %.4s\n", section->name); return(0); } } } } else for(section = sections.begin(); section != sections.end(); section++) { if(!WriteStateChunk(st, section->name, section->sf, data_only)) return(0); } return(1); }
static bool ReadStateChunks(EMUFILE* is, s32 totalsize) { bool ret = true; bool haveInfo = false; s64 save_time = 0; u32 romsize = 0; u8 version_major = 0; u8 version_minor = 0; u8 version_build = 0; NDS_header header; SFORMAT SF_INFO[]={ { "GINF", 1, sizeof(header), &header}, { "GRSZ", 1, 4, &romsize}, { "DVMJ", 1, 1, &version_major}, { "DVMI", 1, 1, &version_minor}, { "DSBD", 1, 1, &version_build}, { "GREV", 1, 4, &svn_rev}, { "GTIM", 1, 8, &save_time}, { 0 } }; memset(&header, 0, sizeof(header)); while(totalsize > 0) { u32 size = 0; u32 t = 0; if(!read32le(&t,is)) { ret=false; break; } if(t == 0xFFFFFFFF) break; if(!read32le(&size,is)) { ret=false; break; } switch(t) { case 1: if(!ReadStateChunk(is,SF_ARM9,size)) ret=false; break; case 2: if(!ReadStateChunk(is,SF_ARM7,size)) ret=false; break; case 3: if(!cp15_loadstate(is,size)) ret=false; break; case 4: if(!ReadStateChunk(is,SF_MEM,size)) ret=false; break; case 5: if(!ReadStateChunk(is,SF_NDS,size)) ret=false; break; case 51: if(!nds_loadstate(is,size)) ret=false; break; case 60: if(!ReadStateChunk(is,SF_MMU,size)) ret=false; break; case 61: if(!mmu_loadstate(is,size)) ret=false; break; case 7: if(!gpu_loadstate(is,size)) ret=false; break; case 8: if(!spu_loadstate(is,size)) ret=false; break; case 81: if(!mic_loadstate(is,size)) ret=false; break; case 90: if(!ReadStateChunk(is,SF_GFX3D,size)) ret=false; break; case 91: if(!gfx3d_loadstate(is,size)) ret=false; break; case 100: if(!ReadStateChunk(is,SF_MOVIE, size)) ret=false; break; case 101: break; case 110: if(!ReadStateChunk(is,SF_WIFI,size)) ret=false; break; case 120: if(!ReadStateChunk(is,SF_RTC,size)) ret=false; break; case 130: if(!ReadStateChunk(is,SF_INFO,size)) ret=false; break; case 140: if(!s_slot1_loadstate(is, size)) ret=false; break; case 150: if(!s_slot2_loadstate(is, size)) ret=false; break; // reserved for future versions case 160: case 170: case 180: if(!ReadStateChunk(is,reserveChunks,size)) ret=false; break; // ============================ default: return false; } if(!ret) return false; } return ret; }
/* This function is called by the game driver(NES, GB, GBA) to save a state. */ int MDFNSS_StateAction(void *st_p, int load, int data_only, std::vector <SSDescriptor> §ions) { StateMem *st = (StateMem*)st_p; std::vector<SSDescriptor>::iterator section; if(load) { { char sname[32]; for(section = sections.begin(); section != sections.end(); section++) { int found = 0; uint32 tmp_size; uint32 total = 0; while(smem_read(st, (uint8 *)sname, 32) == 32) { if(smem_read32le(st, &tmp_size) != 4) return(0); total += tmp_size + 32 + 4; // Yay, we found the section if(!strncmp(sname, section->name, 32)) { if(!ReadStateChunk(st, section->sf, tmp_size)) { printf("Error reading chunk: %s\n", section->name); return(0); } found = 1; break; } else { if(smem_seek(st, tmp_size, SEEK_CUR) < 0) { puts("Chunk seek failure"); return(0); } } } if(smem_seek(st, -total, SEEK_CUR) < 0) { puts("Reverse seek error"); return(0); } if(!found && !section->optional) // Not found. We are sad! { printf("Section missing: %.32s\n", section->name); return(0); } } } } else { for(section = sections.begin(); section != sections.end(); section++) { if(!WriteStateChunk(st, section->name, section->sf)) return(0); } } return(1); }
// // When updating this function make sure to adhere to the guarantees in state.h. // bool MDFNSS_StateAction(StateMem *sm, const unsigned load, const bool data_only, SFORMAT *sf, const char *sname, const bool optional) noexcept { //printf("Section: %s %zu\n", sname, strlen(sname)); if(MDFN_UNLIKELY(sm->deferred_error)) { return(load ? false : true); } try { Stream* st = sm->st; if(MDFN_LIKELY(data_only)) // Not particularly likely, but it's more important to optimize for this code path... { static const uint8 SSFastCanary[8] = { 0x42, 0xA3, 0x10, 0x87, 0xBC, 0x6D, 0xF2, 0x79 }; char sname_canary[32 + 8]; if(load) { st->read(sname_canary, 32 + 8); if(strncmp(sname_canary, sname, 32)) throw MDFN_Error(0, _("Section name mismatch in state loading fast path.")); if(memcmp(sname_canary + 32, SSFastCanary, 8)) throw MDFN_Error(0, _("Section canary is a zombie AAAAAAAAAAGH!")); FastRWChunk<true>(st, sf); } else { memset(sname_canary, 0, sizeof(sname_canary)); strncpy(sname_canary, sname, 32); memcpy(sname_canary + 32, SSFastCanary, 8); st->write(sname_canary, 32 + 8); FastRWChunk<false>(st, sf); } } else { if(load) { char sname_tmp[32]; bool found = false; uint32 tmp_size; uint32 total = 0; while(st->tell() < sm->sss_bound) { st->read(sname_tmp, 32); tmp_size = st->get_LE<uint32>(); total += tmp_size + 32 + 4; // Yay, we found the section if(!strncmp(sname_tmp, sname, 32)) { ReadStateChunk(st, sf, tmp_size, sm->svbe); found = true; break; } else { st->seek(tmp_size, SEEK_CUR); } } st->seek(-(int64)total, SEEK_CUR); if(!found) { if(optional) { printf("Missing optional section: %.32s\n", sname); return(false); } else throw MDFN_Error(0, _("Section missing: %.32s"), sname); } } else { int64 data_start_pos; int64 end_pos; uint8 sname_tmp[32]; memset(sname_tmp, 0, sizeof(sname_tmp)); strncpy((char *)sname_tmp, sname, 32); if(strlen(sname) > 32) printf("Warning: section name is too long: %s\n", sname); st->write(sname_tmp, 32); st->put_LE<uint32>(0); // We'll come back and write this later. data_start_pos = st->tell(); SubWrite(st, sf); end_pos = st->tell(); st->seek(data_start_pos - 4, SEEK_SET); st->put_LE<uint32>(end_pos - data_start_pos); st->seek(end_pos, SEEK_SET); } } } catch(...) { sm->deferred_error = std::current_exception(); return(load ? false : true); } return(true); }