bool SaveBatteryOrState(char * filepath, int action, bool silent) { bool result = false; int offset = 0; int datasize = 0; // we need the actual size of the data written int device; if(!FindDevice(filepath, &device)) return 0; if(action == FILE_SNAPSHOT && gameScreenPngSize > 0) { char screenpath[1024]; strncpy(screenpath, filepath, 1024); screenpath[strlen(screenpath)-4] = 0; sprintf(screenpath, "%s.png", screenpath); SaveFile((char *)gameScreenPng, screenpath, gameScreenPngSize, silent); } AllocSaveBuffer(); // put VBA memory into savebuffer, sets datasize to size of memory written if(action == FILE_SRAM) { if(cartridgeType == 1) datasize = MemgbWriteBatteryFile((char *)savebuffer); else datasize = MemCPUWriteBatteryFile((char *)savebuffer); if (cartridgeType == 1) { const char* generic_goomba_error = "Cannot save SRAM in Goomba format (did not load correctly.)"; // check for goomba sram format char* old_sram = (char*)malloc(GOOMBA_COLOR_SRAM_SIZE); size_t br = LoadFile(old_sram, filepath, GOOMBA_COLOR_SRAM_SIZE, true); if (br >= GOOMBA_COLOR_SRAM_SIZE && goomba_is_sram(old_sram)) { void* cleaned = goomba_cleanup(old_sram); if (cleaned == NULL) { ErrorPrompt(generic_goomba_error); datasize = 0; } else { if (cleaned != old_sram) { free(old_sram); old_sram = (char*)cleaned; } stateheader* sh = stateheader_for(old_sram, RomTitle); if (sh == NULL) { // Game probably doesn't use SRAM datasize = 0; } else { void* new_sram = goomba_new_sav(old_sram, sh, savebuffer, datasize); if (new_sram == NULL) { ErrorPrompt(goomba_last_error()); datasize = 0; } else { memcpy(savebuffer, new_sram, GOOMBA_COLOR_SRAM_SIZE); datasize = GOOMBA_COLOR_SRAM_SIZE; free(new_sram); } } } } free(old_sram); } } else { if(emulator.emuWriteMemState((char *)savebuffer, SAVEBUFFERSIZE)) datasize = *((int *)(savebuffer+4)) + 8; } // write savebuffer into file if(datasize > 0) { offset = SaveFile(filepath, datasize, silent); if(offset > 0) { if(!silent) InfoPrompt ("Save successful"); result = true; } } else { if(!silent) InfoPrompt("No data to save!"); } FreeSaveBuffer(); return result; }
bool LoadBatteryOrState(char * filepath, int action, bool silent) { bool result = false; int offset = 0; int device; if(!FindDevice(filepath, &device)) return 0; AllocSaveBuffer(); // load the file into savebuffer offset = LoadFile(filepath, silent); if (cartridgeType == 1 && goomba_is_sram(savebuffer)) { void* cleaned = goomba_cleanup(savebuffer); if (savebuffer == NULL) { ErrorPrompt(goomba_last_error()); offset = 0; } else { if (cleaned != savebuffer) { memcpy(savebuffer, cleaned, GOOMBA_COLOR_SRAM_SIZE); free(cleaned); } stateheader* sh = stateheader_for(savebuffer, RomTitle); if (sh == NULL) { ErrorPrompt(goomba_last_error()); offset = 0; } else { goomba_size_t outsize; void* gbc_sram = goomba_extract(savebuffer, sh, &outsize); if (gbc_sram == NULL) { ErrorPrompt(goomba_last_error()); offset = 0; } else { memcpy(savebuffer, gbc_sram, outsize); offset = outsize; free(gbc_sram); } } } } // load savebuffer into VBA memory if (offset > 0) { if(action == FILE_SRAM) { if(cartridgeType == 1) result = MemgbReadBatteryFile((char *)savebuffer, offset); else result = MemCPUReadBatteryFile((char *)savebuffer, offset); } else { result = emulator.emuReadMemState((char *)savebuffer, offset); } } FreeSaveBuffer(); if(!silent && !result) { if(offset == 0) { if(action == FILE_SRAM) ErrorPrompt ("Save file not found"); else ErrorPrompt ("State file not found"); } else { if(action == FILE_SRAM) ErrorPrompt ("Invalid save file"); else ErrorPrompt ("Invalid state file"); } } return result; }
bool LoadRAM (char * filepath, bool silent) { int offset = 0; bool retval = false; int device; if(!FindDevice(filepath, &device)) return 0; if(GameInfo->type == GIT_FDS) // RAM saves don't exist for FDS games return false; AllocSaveBuffer (); offset = LoadFile(filepath, silent); // Check to see if this is a PocketNES save file if (goomba_is_sram(savebuffer)) { void* cleaned = goomba_cleanup(savebuffer); if (!cleaned) { ErrorPrompt(goomba_last_error()); } else if (cleaned != savebuffer) { memcpy(savebuffer, cleaned, GOOMBA_COLOR_SRAM_SIZE); free(cleaned); } // Look for just one save file. If there aren't any, or there is more than one, don't read any data. const stateheader* sh1 = NULL; const stateheader* sh2 = NULL; const stateheader* sh = stateheader_first(savebuffer); while (sh && stateheader_plausible(sh)) { if (little_endian_conv_16(sh->type) != GOOMBA_SRAMSAVE) { } else if (sh1 == NULL) { sh1 = sh; } else { sh2 = sh; break; } sh = stateheader_advance(sh); } if (sh1 == NULL) { ErrorPrompt("PocketNES save file has no SRAM."); offset = 0; } else if (sh2 != NULL) { ErrorPrompt("PocketNES save file has more than one SRAM."); offset = 0; } else { goomba_size_t len; void* extracted = goomba_extract(savebuffer, sh1, &len); if (!extracted) ErrorPrompt(goomba_last_error()); else { memcpy(savebuffer, extracted, len); offset = len; free(extracted); } } } if (offset > 0) { if(GameInfo->type == GIT_CART) WiiFCEU_GameSave(&iNESCart, 1); else if(GameInfo->type == GIT_VSUNI) WiiFCEU_GameSave(&UNIFCart, 1); ResetNES(); retval = true; } else { // if we reached here, nothing was done! if(!silent) InfoPrompt ("Save file not found"); } FreeSaveBuffer (); return retval; }
bool SaveRAM (char * filepath, bool silent) { bool retval = false; int datasize = 0; int offset = 0; int device; if(!FindDevice(filepath, &device)) return 0; if(GameInfo->type == GIT_FDS) { if(!silent) InfoPrompt("RAM saving is not available for FDS games!"); return false; } AllocSaveBuffer (); // save game save to savebuffer if(GameInfo->type == GIT_CART) datasize = WiiFCEU_GameSave(&iNESCart, 0); else if(GameInfo->type == GIT_VSUNI) datasize = WiiFCEU_GameSave(&UNIFCart, 0); if (datasize) { // Check to see if this is a PocketNES save file FILE* file = fopen(filepath, "rb"); if (file) { uint32 tag; fread(&tag, sizeof(uint32), 1, file); fclose(file); if (goomba_is_sram(&tag)) { void* gba_data = malloc(GOOMBA_COLOR_SRAM_SIZE); file = fopen(filepath, "rb"); fread(gba_data, 1, GOOMBA_COLOR_SRAM_SIZE, file); fclose(file); void* cleaned = goomba_cleanup(gba_data); if (!cleaned) { ErrorPrompt(goomba_last_error()); } else if (cleaned != gba_data) { memcpy(gba_data, cleaned, GOOMBA_COLOR_SRAM_SIZE); free(cleaned); } // Look for just one save file. If there aren't any, or there is more than one, don't read any data. const stateheader* sh1 = NULL; const stateheader* sh2 = NULL; const stateheader* sh = stateheader_first(gba_data); while (sh && stateheader_plausible(sh)) { if (little_endian_conv_16(sh->type) != GOOMBA_SRAMSAVE) {} else if (sh1 == NULL) { sh1 = sh; } else { sh2 = sh; break; } sh = stateheader_advance(sh); } if (sh1 == NULL) { ErrorPrompt("PocketNES save file has no SRAM."); datasize = 0; } else if (sh2 != NULL) { ErrorPrompt("PocketNES save file has more than one SRAM."); datasize = 0; } else { char* newdata = goomba_new_sav(gba_data, sh1, savebuffer, datasize); if (!newdata) { ErrorPrompt(goomba_last_error()); datasize = 0; } else { memcpy(savebuffer, newdata, GOOMBA_COLOR_SRAM_SIZE); datasize = GOOMBA_COLOR_SRAM_SIZE; free(newdata); } } } } } if (datasize) { offset = SaveFile(filepath, datasize, silent); if (offset > 0) { if (!silent) InfoPrompt("Save successful"); retval = true; } } else { if (!silent) InfoPrompt("No data to save!"); } FreeSaveBuffer (); return retval; }
static void load(const char* path) { FILE* f = fopen(path, "rb"); if (f == NULL) { error_msg("Could not open file %s", path); return; } fseek(f, 0, SEEK_END); size_t filesize = ftell(f); // If the file is smaller than 64 KiB, pad the rest with zeroes. Some goombasav code expects a 64 KiB file. if (filesize < GOOMBA_COLOR_SRAM_SIZE) filesize = GOOMBA_COLOR_SRAM_SIZE; if (loaded_file != NULL) { free(loaded_file); } loaded_file = (char*)malloc(filesize); loaded_file_size = filesize; fseek(f, 0, SEEK_SET); size_t total_bytes_read = 0; while (total_bytes_read < filesize) { size_t bytes_read = fread(loaded_file, 1, filesize - total_bytes_read, f); if (bytes_read <= 0) { fprintf(stderr, "Could only read %lu bytes from %s\n", (unsigned long)total_bytes_read, path); memset((char*)loaded_file + total_bytes_read, 0, filesize - total_bytes_read); total_bytes_read = filesize; } else { total_bytes_read += bytes_read; } } fclose(f); char* cleaned = goomba_cleanup(loaded_file); if (cleaned == NULL) { // this should not happen error_msg("%s", goomba_last_error()); return; } else if (cleaned != loaded_file) { GtkWidget* dialog = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_INFO, GTK_BUTTONS_NONE, "Uncompressed SRAM found at 0xE000. Would you like to move and compress it to the proper location? (Doing this is required to extract or replace the save data.)"); gtk_dialog_add_button(GTK_DIALOG(dialog), "Cancel", GTK_RESPONSE_CANCEL); gtk_dialog_add_button(GTK_DIALOG(dialog), "Skip", GTK_RESPONSE_NO); gtk_dialog_add_button(GTK_DIALOG(dialog), "Clean", GTK_RESPONSE_YES); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES); gint res = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); if (res == GTK_RESPONSE_YES) { memcpy(loaded_file, cleaned, GOOMBA_COLOR_SRAM_SIZE); dirty = true; } free(cleaned); if (res == GTK_RESPONSE_CANCEL) { return; } } else { dirty = false; } if (_filePath != NULL) free(_filePath); _filePath = (char*)malloc(strlen(path) + 1); strcpy(_filePath, path); update_titlebar(GTK_WINDOW(window)); header_scan(); }