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); }
int MDFNSS_StateAction(void* st_p, int load, SFORMAT* sf, const char* name) { StateMem* st = (StateMem*)st_p; if (load) { char sname[32]; 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, name, 32)) { if (!ReadStateChunk(st, sf, tmp_size)) { printf("Error reading chunk: %s\n", 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) // Not found. We are sad! { printf("Section missing: %.32s\n", name); return (0); } } else { if (!WriteStateChunk(st, name, sf)) return (0); } return (1); }
/* This function is called by the game driver(NES, GB, GBA) to save a state. */ static int MDFNSS_StateAction_internal(void *st_p, int load, int data_only, SSDescriptor *section) { StateMem *st = (StateMem*)st_p; if(load) { char sname[32]; int found = 0; uint32_t tmp_size; uint32_t total = 0; while(smem_read(st, (uint8_t *)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 { if(!WriteStateChunk(st, section->name, section->sf)) return(0); } return(1); }
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); }
int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, uint32 *fb, MDFN_Rect *LineWidths) { static uint8 header[32]="MEDNAFENSVESTATE"; int neowidth, neoheight; neowidth = MDFNGameInfo->ss_preview_width; neoheight = MDFNGameInfo->DisplayRect.h; if(!data_only) { memset(header+16,0,16); MDFN_en32lsb(header + 12, currFrameCounter); MDFN_en32lsb(header + 16, pcejin.lagFrameCounter); // MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); } if(wantpreview) { uint8 *previewbuffer = (uint8 *)malloc(17 * neowidth * neoheight); // MakeStatePreview(previewbuffer, fb, LineWidths); smem_write(st, fb, 17 * neowidth * neoheight); free(previewbuffer); } // State rewinding code path hack, FIXME //if(data_only) //{ // if(!MDFN_RawInputStateAction(st, 0, data_only)) // return(0); //} if(!MDFNGameInfo->StateAction(st, 0, data_only)) return(0); if(!data_only) { uint32 sizy = smem_tell(st); smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); } return(1); }
static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size, int data_only) { SFORMAT *tmp; int temp; if(data_only) { DOReadChunk(st, sf); } else { temp = smem_tell(st); while(smem_tell(st) < temp + size) { uint32 tsize; char toa[32]; if(smem_read(st, toa, 32) <= 0) { puts("Unexpected EOF?"); return 0; } smem_read32le(st, &tsize); if((tmp=CheckS(sf,tsize,toa))) { int32 bytesize = tmp->s&(~(MDFNSTATE_RLSB32 | MDFNSTATE_RLSB16 | RLSB)); smem_read(st, (uint8 *)tmp->v, bytesize); if(tmp->s & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(tmp->v, bytesize / sizeof(uint32)); else if(tmp->s & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(tmp->v, bytesize / sizeof(uint16)); else if(tmp->s&RLSB) Endian_V_LE_to_NE(tmp->v, bytesize); } else if(smem_seek(st,tsize,SEEK_CUR) < 0) { puts("Seek error"); return(0); } } // while(...) } return 1; }
int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only) { uint8 header[32]; uint32 stateversion; if(data_only) { stateversion = MEDNAFEN_VERSION_NUMERIC; } else { smem_read(st, header, 32); // if(memcmp(header,"MEDNAFENSVESTATE",16)) // return(0); stateversion = MDFN_de32lsb(header + 16); if(stateversion < 0x0600) { // printf("State too old: %08x\n", stateversion); // return(0); } } currFrameCounter = MDFN_de32lsb(header + 12); pcejin.lagFrameCounter = MDFN_de32lsb(header + 16); if(haspreview) { uint32 width = MDFN_de32lsb(header + 24); uint32 height = MDFN_de32lsb(header + 28); uint32 psize; //PREVIEWIMAGE psize = width * height * 4; smem_seek(st, psize, SEEK_CUR); // Skip preview } // State rewinding code path hack, FIXME if(data_only) { // if(!MDFN_RawInputStateAction(st, stateversion, data_only)) return(0); } return(MDFNGameInfo->StateAction(st, stateversion, data_only)); }
int MDFNSS_LoadSM(StateMem *st, int haspreview, int data_only) { uint8 header[32]; uint32 stateversion; if(data_only) { stateversion = MEDNAFEN_VERSION_NUMERIC; } else { smem_read(st, header, 32); if(memcmp(header, "MEDNAFENSVESTATE", 16) && memcmp(header, "MDFNSVST", 8)) return(0); stateversion = MDFN_de32lsb(header + 16); } if(haspreview) { uint32 width = MDFN_de32lsb(header + 24); uint32 height = MDFN_de32lsb(header + 28); uint32 psize; psize = width * height * 3; smem_seek(st, psize, SEEK_CUR); // Skip preview } // State rewinding code path hack, FIXME if(data_only) { if(!MDFN_RawInputStateAction(st, stateversion, data_only)) return(0); } return(MDFNGameInfo->StateAction(st, stateversion, data_only)); }
int MDFNSS_SaveSM(void *st_p, int, int, const void*, const void*, const void*) { uint8_t header[32]; StateMem *st = (StateMem*)st_p; static const char *header_magic = "MDFNSVST"; int neowidth = 0, neoheight = 0; memset(header, 0, sizeof(header)); memcpy(header, header_magic, 8); MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); if(!StateAction(st, 0, 0)) return(0); uint32_t sizy = st->loc; smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); return(1); }
static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size) { int temp = st->loc; while (st->loc < (temp + size)) { uint32_t recorded_size; // In bytes uint8_t toa[1 + 256]; // Don't change to char unless cast toa[0] to unsigned to smem_read() and other places. if(smem_read(st, toa, 1) != 1) { puts("Unexpected EOF"); return(0); } if(smem_read(st, toa + 1, toa[0]) != toa[0]) { puts("Unexpected EOF?"); return 0; } toa[1 + toa[0]] = 0; smem_read32le(st, &recorded_size); SFORMAT *tmp = FindSF((char*)toa + 1, sf); if(tmp) { uint32_t expected_size = tmp->size; // In bytes if(recorded_size != expected_size) { printf("Variable in save state wrong size: %s. Need: %d, got: %d\n", toa + 1, expected_size, recorded_size); if(smem_seek(st, recorded_size, SEEK_CUR) < 0) { puts("Seek error"); return(0); } } else { smem_read(st, (uint8_t *)tmp->v, expected_size); if(tmp->flags & MDFNSTATE_BOOL) { // Converting downwards is necessary for the case of sizeof(bool) > 1 for(int32_t bool_monster = expected_size - 1; bool_monster >= 0; bool_monster--) { ((bool *)tmp->v)[bool_monster] = ((uint8_t *)tmp->v)[bool_monster]; } } #ifdef MSB_FIRST if(tmp->flags & MDFNSTATE_RLSB64) Endian_A64_LE_to_NE(tmp->v, expected_size / sizeof(uint64_t)); else if(tmp->flags & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(tmp->v, expected_size / sizeof(uint32_t)); else if(tmp->flags & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(tmp->v, expected_size / sizeof(uint16_t)); else if(tmp->flags & RLSB) Endian_V_LE_to_NE(tmp->v, expected_size); #endif } } else { printf("Unknown variable in save state: %s\n", toa + 1); if(smem_seek(st, recorded_size, SEEK_CUR) < 0) { puts("Seek error"); return(0); } } } // while(...) assert(st->loc == (temp + size)); return 1; }
/* 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); }
int MDFNSS_SaveSM(StateMem *st, int wantpreview, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths) { static uint8 header[32]="MEDNAFENSVESTATE"; int neowidth = 0, neoheight = 0; if(wantpreview) { bool is_multires = FALSE; // We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has // multiple horizontal resolutions. neowidth = MDFNGameInfo->nominal_width; neoheight = MDFNGameInfo->nominal_height; if(LineWidths[0].w != ~0) { uint32 first_w = LineWidths[DisplayRect->y].w; for(int y = 0; y < DisplayRect->h; y++) if(LineWidths[DisplayRect->y + y].w != first_w) { puts("Multires!"); is_multires = TRUE; } } if(!is_multires) { if(((double)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((double)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25) neowidth = DisplayRect->w; if(((double)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((double)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25) neoheight = DisplayRect->h; } } if(!data_only) { memset(header+16,0,16); MDFN_en32lsb(header + 12, currFrameCounter); MDFN_en32lsb(header + 16, pcejin.lagFrameCounter); // MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); } if(wantpreview) { /* uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight); MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format.colorspace, surface->format.Rshift, surface->format.Gshift, surface->format.Bshift, surface->format.Ashift); MDFN_Rect dest_rect; dest_rect.x = 0; dest_rect.y = 0; dest_rect.w = neowidth; dest_rect.h = neoheight; // MDFN_ResizeSurface(surface, DisplayRect, (LineWidths[0].w != ~0) ? LineWidths : NULL, dest_surface, &dest_rect); { uint32 a, b = 0; for(a = 0; a < neowidth * neoheight * 4; a+=4) { uint32 c = *(uint32 *)&previewbuffer[a]; int nr, ng, nb; surface->DecodeColor(c, nr, ng, nb); previewbuffer[b + 0] = nr; previewbuffer[b + 1] = ng; previewbuffer[b + 2] = nb; b += 3; } }*/ //PREVIEWIMAGE smem_write(st, surface->pixels, 4 * neowidth * neoheight); // free(previewbuffer); // delete dest_surface; } // State rewinding code path hack, FIXME if(data_only) { // if(!MDFN_RawInputStateAction(st, 0, data_only)) return(0); } if(!MDFNGameInfo->StateAction(st, 0, data_only)) return(0); if(!data_only) { uint32 sizy = smem_tell(st); smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); } return(1); }
static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size, int data_only) { int temp; if(data_only) { DOReadChunk(st, sf); } else { SFMap_t sfmap; SFMap_t sfmap_found; // Used for identify variables that are missing in the save state. MakeSFMap(sf, sfmap); temp = smem_tell(st); while(smem_tell(st) < (temp + size)) { uint32 tsize; char toa[1 + 256]; if(smem_read(st, toa, 1) != 1) { puts("Unexpected EOF"); return(0); } if(smem_read(st, toa + 1, toa[0]) != toa[0]) { puts("Unexpected EOF?"); return 0; } toa[1 + toa[0]] = 0; smem_read32le(st, &tsize); SFMap_t::iterator sfmit; sfmit = sfmap.find(toa + 1); if(sfmit != sfmap.end()) { SFORMAT *tmp = sfmit->second; int32 bytesize = tmp->size; sfmap_found[tmp->name] = tmp; smem_read(st, (uint8 *)tmp->v, bytesize); if(tmp->flags & MDFNSTATE_BOOL) { // Converting downwards is necessary for the case of sizeof(bool) > 1 for(int32 bool_monster = bytesize - 1; bool_monster >= 0; bool_monster--) { ((bool *)tmp->v)[bool_monster] = (bool)((uint8 *)tmp->v)[bool_monster]; } } if(tmp->flags & MDFNSTATE_RLSB64) Endian_A64_LE_to_NE(tmp->v, bytesize / sizeof(uint64)); else if(tmp->flags & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(tmp->v, bytesize / sizeof(uint32)); else if(tmp->flags & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(tmp->v, bytesize / sizeof(uint16)); else if(tmp->flags & RLSB) Endian_V_LE_to_NE(tmp->v, bytesize); } else { printf("Unknown variable in save state: %s\n", toa + 1); if(smem_seek(st, tsize, SEEK_CUR) < 0) { puts("Seek error"); return(0); } } } // while(...) for(SFMap_t::const_iterator it = sfmap.begin(); it != sfmap.end(); it++) { if(sfmap_found.find(it->second->name) == sfmap_found.end()) { printf("Variable missing from save state: %s\n", it->second->name); } } assert(smem_tell(st) == (temp + size)); } return 1; }
/* 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); }
static int ReadStateChunk(StateMem *st, SFORMAT *sf, int size) { int temp; { SFMap_t sfmap; SFMap_t sfmap_found; // Used for identifying variables that are missing in the save state. MakeSFMap(sf, sfmap); temp = smem_tell(st); while(smem_tell(st) < (temp + size)) { uint32 recorded_size; // In bytes uint8 toa[1 + 256]; // Don't change to char unless cast toa[0] to unsigned to smem_read() and other places. if(smem_read(st, toa, 1) != 1) { puts("Unexpected EOF"); return(0); } if(smem_read(st, toa + 1, toa[0]) != toa[0]) { puts("Unexpected EOF?"); return 0; } toa[1 + toa[0]] = 0; smem_read32le(st, &recorded_size); SFMap_t::iterator sfmit; sfmit = sfmap.find((char *)toa + 1); if(sfmit != sfmap.end()) { SFORMAT *tmp = sfmit->second; uint32 expected_size = tmp->size; // In bytes if(recorded_size != expected_size) { printf("Variable in save state wrong size: %s. Need: %d, got: %d\n", toa + 1, expected_size, recorded_size); if(smem_seek(st, recorded_size, SEEK_CUR) < 0) { puts("Seek error"); return(0); } } else { sfmap_found[tmp->name] = tmp; smem_read(st, (uint8 *)tmp->v, expected_size); if(tmp->flags & MDFNSTATE_BOOL) { // Converting downwards is necessary for the case of sizeof(bool) > 1 for(int32 bool_monster = expected_size - 1; bool_monster >= 0; bool_monster--) { ((bool *)tmp->v)[bool_monster] = ((uint8 *)tmp->v)[bool_monster]; } } if(tmp->flags & MDFNSTATE_RLSB64) Endian_A64_LE_to_NE(tmp->v, expected_size / sizeof(uint64)); else if(tmp->flags & MDFNSTATE_RLSB32) Endian_A32_LE_to_NE(tmp->v, expected_size / sizeof(uint32)); else if(tmp->flags & MDFNSTATE_RLSB16) Endian_A16_LE_to_NE(tmp->v, expected_size / sizeof(uint16)); else if(tmp->flags & RLSB) Endian_V_LE_to_NE(tmp->v, expected_size); } } else { printf("Unknown variable in save state: %s\n", toa + 1); if(smem_seek(st, recorded_size, SEEK_CUR) < 0) { puts("Seek error"); return(0); } } } // while(...) for(SFMap_t::const_iterator it = sfmap.begin(); it != sfmap.end(); it++) { if(sfmap_found.find(it->second->name) == sfmap_found.end()) { printf("Variable missing from save state: %s\n", it->second->name); } } assert(smem_tell(st) == (temp + size)); } return 1; }
int MDFNSS_SaveSM(StateMem *st, int wantpreview_and_ts, int data_only, const MDFN_Surface *surface, const MDFN_Rect *DisplayRect, const MDFN_Rect *LineWidths) { static const char *header_magic = "MDFNSVST"; uint8 header[32]; int neowidth = 0, neoheight = 0; memset(header, 0, sizeof(header)); if(wantpreview_and_ts) { bool is_multires = FALSE; // We'll want to use the nominal width if the source rectangle is > 25% off on either axis, or the source image has // multiple horizontal resolutions. neowidth = MDFNGameInfo->nominal_width; neoheight = MDFNGameInfo->nominal_height; if(LineWidths[0].w != ~0) { uint32 first_w = LineWidths[DisplayRect->y].w; for(int y = 0; y < DisplayRect->h; y++) if(LineWidths[DisplayRect->y + y].w != first_w) { MDFN_printf("Multires!"); is_multires = TRUE; } } if(!is_multires) { if(((SysDDec)DisplayRect->w / MDFNGameInfo->nominal_width) > 0.75 && ((SysDDec)DisplayRect->w / MDFNGameInfo->nominal_width) < 1.25) neowidth = DisplayRect->w; if(((SysDDec)DisplayRect->h / MDFNGameInfo->nominal_height) > 0.75 && ((SysDDec)DisplayRect->h / MDFNGameInfo->nominal_height) < 1.25) neoheight = DisplayRect->h; } } if(!data_only) { memcpy(header, header_magic, 8); if(wantpreview_and_ts) MDFN_en64lsb(header + 8, time(NULL)); MDFN_en32lsb(header + 16, MEDNAFEN_VERSION_NUMERIC); MDFN_en32lsb(header + 24, neowidth); MDFN_en32lsb(header + 28, neoheight); smem_write(st, header, 32); } if(wantpreview_and_ts) { uint8 *previewbuffer = (uint8 *)malloc(4 * neowidth * neoheight); MDFN_Surface *dest_surface = new MDFN_Surface((uint32 *)previewbuffer, neowidth, neoheight, neowidth, surface->format); MDFN_Rect dest_rect; dest_rect.x = 0; dest_rect.y = 0; dest_rect.w = neowidth; dest_rect.h = neoheight; MDFN_ResizeSurface(surface, DisplayRect, (LineWidths[0].w != ~0) ? LineWidths : NULL, dest_surface, &dest_rect); { uint32 a, b = 0; for(a = 0; a < neowidth * neoheight * 4; a+=4) { uint32 c = *(uint32 *)&previewbuffer[a]; int nr, ng, nb; surface->DecodeColor(c, nr, ng, nb); previewbuffer[b + 0] = nr; previewbuffer[b + 1] = ng; previewbuffer[b + 2] = nb; b += 3; } } smem_write(st, previewbuffer, 3 * neowidth * neoheight); free(previewbuffer); delete dest_surface; } // State rewinding code path hack, FIXME if(data_only) { if(!MDFN_RawInputStateAction(st, 0, data_only)) return(0); } if(!MDFNGameInfo->StateAction(st, 0, data_only)) return(0); if(!data_only) { uint32 sizy = smem_tell(st); smem_seek(st, 16 + 4, SEEK_SET); smem_write32le(st, sizy); } return(1); }