static int WriteStateChunk(MEM_TYPE *st, int type, SFORMAT *sf) { int bsize; fputc(type, st); bsize = SubWrite(0, sf); write32le(bsize, st); if (!SubWrite(st, sf)) return(0); return(bsize + 5); }
static int savestate_WriteChunk(EMUFILE* os, int type, const SFORMAT *sf) { write32le(type,os); if(!sf) return 4; int bsize = SubWrite((EMUFILE*)0,sf); write32le(bsize,os); if(!SubWrite(os,sf)) { return 8; } return (bsize+8); }
static int WriteStateChunk(MEMFILE *st, int type, SFORMAT *sf) { int bsize; mem_fputc(type,st); bsize=SubWrite(0,sf); mem_write32le(bsize,st); if(!SubWrite(st,sf)) { return(0); } return (bsize+5); }
static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf) { int32_t data_start_pos; int32_t end_pos; uint8_t 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); smem_write(st, sname_tmp, 32); smem_write32le(st, 0); // We'll come back and write this later. data_start_pos = st->loc; if(!SubWrite(st, sf)) return(0); end_pos = st->loc; smem_seek(st, data_start_pos - 4, SEEK_SET); smem_write32le(st, end_pos - data_start_pos); smem_seek(st, end_pos, SEEK_SET); return(end_pos - data_start_pos); }
static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf, int data_only) { int bsize; if(!data_only) smem_write(st, (uint8 *)sname, 4); bsize=SubWrite(0,sf, data_only, NULL); if(!data_only) smem_write32le(st, bsize); if(!SubWrite(st,sf, data_only, NULL)) return(0); if(data_only) return(bsize); else return (bsize + 4 + 4); }
static void SubWrite(Stream *st, SFORMAT *sf) { while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct. { if(!sf->size || !sf->v) { sf++; continue; } if(sf->size == (uint32)~0) /* Link to another struct. */ { SubWrite(st, (SFORMAT *)sf->v); sf++; continue; } int32 bytesize = sf->size; char nameo[1 + 255]; const int slen = strlen(sf->name); if(slen > 255) throw MDFN_Error(0, _("State variable name \"%s\" is too long."), sf->name); memcpy(&nameo[1], sf->name, slen); nameo[0] = slen; st->write(nameo, 1 + nameo[0]); st->put_LE<uint32>(bytesize); // Special case for the evil bool type, to convert bool to 1-byte elements. if(sf->flags & MDFNSTATE_BOOL) { for(int32 bool_monster = 0; bool_monster < bytesize; bool_monster++) { uint8 tmp_bool = ((bool *)sf->v)[bool_monster]; //printf("Bool write: %.31s\n", sf->name); st->write(&tmp_bool, 1); } } else { st->write((uint8 *)sf->v, bytesize); } sf++; } }
static int SubWrite(FILE *st, SFORMAT *sf) { uint32 acc=0; while(sf->v) { if(sf->s==~0) /* Link to another struct. */ { uint32 tmp; if(!(tmp=SubWrite(st,(SFORMAT *)sf->v))) return(0); acc+=tmp; sf++; continue; } acc+=8; /* Description + size */ acc+=sf->s&(~RLSB); if(st) /* Are we writing or calculating the size of this block? */ { fwrite(sf->desc,1,4,st); write32le(sf->s&(~RLSB),st); #ifndef LSB_FIRST if(sf->s&RLSB) FlipByteOrder(sf->v,sf->s&(~RLSB)); #endif fwrite((uint8 *)sf->v,1,sf->s&(~RLSB),st); /* Now restore the original byte order. */ #ifndef LSB_FIRST if(sf->s&RLSB) FlipByteOrder(sf->v,sf->s&(~RLSB)); #endif } sf++; } return(acc); }
static int WriteStateChunk(StateMem *st, const char *sname, SFORMAT *sf, int data_only) { int32 data_start_pos; int32 end_pos; if(!data_only) { uint8 sname_tmp[32]; memset(sname_tmp, 0, sizeof(sname_tmp)); strncpy((char *)sname_tmp, sname, 32); if(strlen(sname) > 32) MDFN_printf("Warning: section name is too long: %s\n", sname); smem_write(st, sname_tmp, 32); smem_write32le(st, 0); // We'll come back and write this later. } data_start_pos = smem_tell(st); if(!SubWrite(st, sf, data_only)) return(0); end_pos = smem_tell(st); if(!data_only) { smem_seek(st, data_start_pos - 4, SEEK_SET); smem_write32le(st, end_pos - data_start_pos); smem_seek(st, end_pos, SEEK_SET); } return(end_pos - data_start_pos); }
static bool SubWrite(StateMem *st, SFORMAT *sf, const char *name_prefix = NULL) { while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct. { if(!sf->size || !sf->v) { sf++; continue; } if(sf->size == (uint32_t)~0) /* Link to another struct. */ { if(!SubWrite(st, (SFORMAT *)sf->v, name_prefix)) return(0); sf++; continue; } int32_t bytesize = sf->size; char nameo[1 + 256]; int slen; slen = snprintf(nameo + 1, 256, "%s%s", name_prefix ? name_prefix : "", sf->name); nameo[0] = slen; if(slen >= 255) { printf("Warning: state variable name possibly too long: %s %s %s %d\n", sf->name, name_prefix, nameo, slen); slen = 255; } smem_write(st, nameo, 1 + nameo[0]); smem_write32le(st, bytesize); #ifdef MSB_FIRST /* Flip the byte order... */ if(sf->flags & MDFNSTATE_BOOL) { } else if(sf->flags & MDFNSTATE_RLSB64) Endian_A64_NE_to_LE(sf->v, bytesize / sizeof(uint64_t)); else if(sf->flags & MDFNSTATE_RLSB32) Endian_A32_NE_to_LE(sf->v, bytesize / sizeof(uint32_t)); else if(sf->flags & MDFNSTATE_RLSB16) Endian_A16_NE_to_LE(sf->v, bytesize / sizeof(uint16_t)); else if(sf->flags & RLSB) Endian_V_NE_to_LE(sf->v, bytesize); #endif // Special case for the evil bool type, to convert bool to 1-byte elements. // Don't do it if we're only saving the raw data. if(sf->flags & MDFNSTATE_BOOL) { for(int32_t bool_monster = 0; bool_monster < bytesize; bool_monster++) { uint8_t tmp_bool = ((bool *)sf->v)[bool_monster]; //printf("Bool write: %.31s\n", sf->name); smem_write(st, &tmp_bool, 1); } } else smem_write(st, (uint8_t *)sf->v, bytesize); #ifdef MSB_FIRST /* Now restore the original byte order. */ if(sf->flags & MDFNSTATE_BOOL) { } else if(sf->flags & MDFNSTATE_RLSB64) Endian_A64_LE_to_NE(sf->v, bytesize / sizeof(uint64_t)); else if(sf->flags & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(sf->v, bytesize / sizeof(uint32_t)); else if(sf->flags & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(sf->v, bytesize / sizeof(uint16_t)); else if(sf->flags & RLSB) Endian_V_LE_to_NE(sf->v, bytesize); #endif sf++; } return true; }
static int SubWrite(StateMem *st, SFORMAT *sf, int data_only, gzFile fp) { uint32 acc=0; // FIXME? It's kind of slow, and we definitely don't want it on with state rewinding... //ValidateSFStructure(sf); while(sf->s || sf->desc) // Size can sometimes be zero, so also check for the text description. These two should both be zero only at the end of a struct. { if(!sf->s || !sf->v) { sf++; continue; } if(sf->s == (uint32)~0) /* Link to another struct. */ { uint32 tmp; if(!(tmp=SubWrite(st,(SFORMAT *)sf->v, data_only, fp))) return(0); acc+=tmp; sf++; continue; } if(!data_only) acc+=32 + 4; /* Description + size */ int32 bytesize = sf->s&(~(MDFNSTATE_RLSB32 | MDFNSTATE_RLSB16 | RLSB)); acc += bytesize; //printf("%d %d %d\n", bytesize, data_only, fp); if(st || fp) /* Are we writing or calculating the size of this block? */ { if(!data_only) { char desco[32]; int slen = strlen(sf->desc); memset(desco, 0, 32); if(slen > 32) { printf("Warning: state variable name too long: %s %d\n", sf->desc, slen); slen = 32; } memcpy(desco, sf->desc, slen); smem_write(st, desco, 32); smem_write32le(st, bytesize); /* Flip the byte order... */ if(sf->s & MDFNSTATE_RLSB32) Endian_A32_NE_to_LE(sf->v, bytesize / sizeof(uint32)); else if(sf->s & MDFNSTATE_RLSB16) Endian_A16_NE_to_LE(sf->v, bytesize / sizeof(uint16)); else if(sf->s&RLSB) Endian_V_NE_to_LE(sf->v, bytesize); } if(fp) { //printf("Wrote: %d\n", bytesize); gzwrite(fp, sf->v, bytesize); } else { smem_write(st, (uint8 *)sf->v, bytesize); } if(!data_only) { /* Now restore the original byte order. */ if(sf->s & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(sf->v, bytesize / sizeof(uint32)); else if(sf->s & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(sf->v, bytesize / sizeof(uint16)); else if(sf->s&RLSB) Endian_V_LE_to_NE(sf->v, bytesize); } } sf++; } return(acc); }
static bool SubWrite(StateMem *st, SFORMAT *sf, int data_only, const char *name_prefix = NULL) { // FIXME? It's kind of slow, and we definitely don't want it on with state rewinding... //if(!data_only) // ValidateSFStructure(sf); while(sf->size || sf->name) // Size can sometimes be zero, so also check for the text name. These two should both be zero only at the end of a struct. { if(!sf->size || !sf->v) { sf++; continue; } if(sf->size == (uint32)~0) /* Link to another struct. */ { if(!SubWrite(st, (SFORMAT *)sf->v, data_only, name_prefix)) return(0); sf++; continue; } int32 bytesize = sf->size; // If we're only saving the raw data, and we come across a bool type, we save it as it is in memory, rather than converting it to // 1-byte. In the SFORMAT structure, the size member for bool entries is the number of bool elements, not the total in-memory size, // so we adjust it here. if(data_only && (sf->flags & MDFNSTATE_BOOL)) { bytesize *= sizeof(bool); } if(!data_only) { char nameo[1 + 256]; int slen; slen = snprintf(nameo + 1, 256, "%s%s", name_prefix ? name_prefix : "", sf->name); nameo[0] = slen; if(slen >= 255) { printf("Warning: state variable name possibly too long: %s %s %s %d\n", sf->name, name_prefix, nameo, slen); slen = 255; } smem_write(st, nameo, 1 + nameo[0]); smem_write32le(st, bytesize); /* Flip the byte order... */ if(sf->flags & MDFNSTATE_BOOL) { } else if(sf->flags & MDFNSTATE_RLSB64) Endian_A64_NE_to_LE(sf->v, bytesize / sizeof(uint64)); else if(sf->flags & MDFNSTATE_RLSB32) Endian_A32_NE_to_LE(sf->v, bytesize / sizeof(uint32)); else if(sf->flags & MDFNSTATE_RLSB16) Endian_A16_NE_to_LE(sf->v, bytesize / sizeof(uint16)); else if(sf->flags & RLSB) Endian_V_NE_to_LE(sf->v, bytesize); } // Special case for the evil bool type, to convert bool to 1-byte elements. // Don't do it if we're only saving the raw data. if((sf->flags & MDFNSTATE_BOOL) && !data_only) { for(int32 bool_monster = 0; bool_monster < bytesize; bool_monster++) { uint8 tmp_bool = ((bool *)sf->v)[bool_monster]; //printf("Bool write: %.31s\n", sf->name); smem_write(st, &tmp_bool, 1); } } else smem_write(st, (uint8 *)sf->v, bytesize); if(!data_only) { /* Now restore the original byte order. */ if(sf->flags & MDFNSTATE_BOOL) { } else if(sf->flags & MDFNSTATE_RLSB64) Endian_A64_LE_to_NE(sf->v, bytesize / sizeof(uint64)); else if(sf->flags & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(sf->v, bytesize / sizeof(uint32)); else if(sf->flags & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(sf->v, bytesize / sizeof(uint16)); else if(sf->flags & RLSB) Endian_V_LE_to_NE(sf->v, bytesize); } sf++; } return(TRUE); }
// // 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); }