Windows Port:

- Fix crashing bug where the app would crash if the SaveRam path is invalid or does not allow for read/write access. (Fixes bugs #1394 and #1426.)
- New behavior: If the SaveRam path is invalid or does not allow for read/write access, warn the user. After the warning, continue emulation as normal.

mc.cpp:
- Allow backup memory to operate inside RAM if read/write file access is unavailable.
This commit is contained in:
rogerman 2015-03-19 01:50:15 +00:00
parent bfe105a188
commit 3331fb1890
6 changed files with 78 additions and 40 deletions

View File

@ -1,7 +1,7 @@
/*
The MIT License
Copyright (C) 2009-2014 DeSmuME team
Copyright (C) 2009-2015 DeSmuME team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -141,13 +141,15 @@ void EMUFILE_FILE::EnablePositionCache()
mFilePosition = ::ftell(fp);
}
void EMUFILE_FILE::fwrite(const void *ptr, size_t bytes)
size_t EMUFILE_FILE::fwrite(const void *ptr, size_t bytes)
{
DemandCondition(eCondition_Write);
size_t ret = ::fwrite((void*)ptr, 1, bytes, fp);
mFilePosition += ret;
if(ret < bytes)
failbit = true;
return ret;
}

View File

@ -1,7 +1,7 @@
/*
The MIT License
Copyright (C) 2009-2014 DeSmuME team
Copyright (C) 2009-2015 DeSmuME team
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@ -84,11 +84,7 @@ public:
virtual int fputc(int c) = 0;
virtual size_t _fread(const void *ptr, size_t bytes) = 0;
//removing these return values for now so we can find any code that might be using them and make sure
//they handle the return values correctly
virtual void fwrite(const void *ptr, size_t bytes) = 0;
virtual size_t fwrite(const void *ptr, size_t bytes) = 0;
void write64le(u64* val);
void write64le(u64 val);
@ -221,15 +217,13 @@ public:
}
virtual size_t _fread(const void *ptr, size_t bytes);
//removing these return values for now so we can find any code that might be using them and make sure
//they handle the return values correctly
virtual void fwrite(const void *ptr, size_t bytes){
virtual size_t fwrite(const void *ptr, size_t bytes){
reserve(pos+(s32)bytes);
memcpy(buf()+pos,ptr,bytes);
pos += (s32)bytes;
len = std::max(pos,len);
return bytes;
}
virtual int fseek(int offset, int origin){
@ -333,10 +327,7 @@ public:
}
virtual size_t _fread(const void *ptr, size_t bytes);
//removing these return values for now so we can find any code that might be using them and make sure
//they handle the return values correctly
virtual void fwrite(const void *ptr, size_t bytes);
virtual size_t fwrite(const void *ptr, size_t bytes);
virtual int fseek(int offset, int origin);

View File

@ -2210,7 +2210,7 @@ public:
std::vector<std::string> differences;
virtual void fwrite(const void *ptr, size_t bytes)
virtual size_t fwrite(const void *ptr, size_t bytes)
{
if(!failbit)
{
@ -2243,6 +2243,8 @@ public:
}
pos += bytes;
return bytes;
}
};

View File

@ -123,7 +123,7 @@ bool BackupDevice::save_state(EMUFILE* os)
std::vector<u8> data(fsize);
fpMC->fseek(0, SEEK_SET);
if(data.size()!=0)
fread((char*)&data[0], 1, fsize, fpMC->get_fp());
fpMC->fwrite((char *)&data[0], fsize);
u32 version = 5;
//v0
@ -195,7 +195,7 @@ bool BackupDevice::load_state(EMUFILE* is)
#ifndef _DONT_SAVE_BACKUP
fpMC->fseek(0, SEEK_SET);
if(data.size()!=0)
fwrite((char*)&data[0], 1, fsize, fpMC->get_fp());
fpMC->fwrite((char *)&data[0], fsize);
ensure(data.size(), fpMC);
#endif
@ -249,19 +249,29 @@ BackupDevice::BackupDevice()
if (!out->fail())
{
u8 *data = new u8[sz];
fread(data, 1, sz, in->get_fp());
fwrite(data, 1, sz, out->get_fp());
in->fread(data, sz);
out->fwrite(data, sz);
delete [] data;
}
else
{
printf("BackupDevice: Could not create the backup save file.\n");
}
delete out;
}
}
else
{
printf("BackupDevice: Could not read the save file for creating a backup.\n");
}
delete in;
}
if (!fexists)
{
printf("DeSmuME .dsv save file not found. Trying to load an old raw .sav file.\n");
printf("BackupDevice: DeSmuME .dsv save file not found. Trying to load a .sav file.\n");
std::string tmp_fsav = std::string(buf) + ".sav";
EMUFILE_FILE *fpTmp = new EMUFILE_FILE(tmp_fsav, "rb");
@ -275,14 +285,19 @@ BackupDevice::BackupDevice()
if (!fpOut->fail())
{
u8 *buf = new u8[sz + 1];
if ((buf) && (fread(buf, 1, sz, fpTmp->get_fp()) == sz))
if ((buf) && (fpTmp->fread(buf, sz) == sz))
{
if (no_gba_unpack(buf, sz))
printf("Converted from no$gba save.\n");
{
printf("BackupDevice: Converting no$gba .sav file.\n");
}
else
{
printf("BackupDevice: Converting old raw .sav file.\n");
sz = trim(buf, sz);
}
if (fwrite(buf, 1, sz, fpOut->get_fp()) == sz)
if (fpOut->fwrite(buf, sz) == sz)
{
u8 res = searchFileSaveType(sz);
if (res != 0xFF)
@ -297,6 +312,10 @@ BackupDevice::BackupDevice()
info.type = 0;
fexists = true;
}
else
{
printf("BackupDevice: Error converting .sav file.\n");
}
}
delete [] buf;
}
@ -307,6 +326,14 @@ BackupDevice::BackupDevice()
}
fpMC = new EMUFILE_FILE(filename, fexists?"rb+":"wb+");
const bool fileCanReadWrite = (fpMC->get_fp() != NULL);
if (!fileCanReadWrite)
{
delete fpMC;
fpMC = new EMUFILE_MEMORY();
printf("BackupDevice: WARNING! Failed to get read/write access to the save file! Will operate in RAM instead.\n");
}
if (!fpMC->fail())
{
fsize = fpMC->size();
@ -372,7 +399,7 @@ BackupDevice::BackupDevice()
}
if (ss > 0)
printf("Backup size: %u %cbit\n", ss, _Mbit?'M':'K');
printf("BackupDevice: size = %u %cbit\n", ss, _Mbit?'M':'K');
}
state = (fsize > 0)?RUNNING:DETECTING;
@ -491,7 +518,7 @@ bool BackupDevice::write(u8 val)
//never use save files if we are in movie mode
if (isMovieMode) return true;
return fwrite(&val, 1, 1, fpMC->get_fp())?true:false;
return (fpMC->fwrite(&val, 1) == 1);
}
void BackupDevice::writeByte(u32 addr, u8 val)
@ -548,7 +575,7 @@ bool BackupDevice::saveBuffer(u8 *data, u32 size, bool _rewind, bool _truncate)
fpMC->truncate(0);
}
fsize = size;
fwrite(data, 1, size, fpMC->get_fp());
fpMC->fwrite(data, size);
ensure(size, fpMC);
return true;
}
@ -886,16 +913,16 @@ u8 BackupDevice::data_command(u8 val, u8 PROCNUM)
}
//guarantees that the data buffer has room enough for the specified number of bytes
void BackupDevice::ensure(u32 addr, EMUFILE_FILE *fpOut)
void BackupDevice::ensure(u32 addr, EMUFILE *fpOut)
{
ensure(addr, uninitializedValue, fpOut);
}
void BackupDevice::ensure(u32 addr, u8 val, EMUFILE_FILE *fpOut)
void BackupDevice::ensure(u32 addr, u8 val, EMUFILE *fpOut)
{
if (!fpOut && (addr < fsize)) return;
EMUFILE_FILE *fp = fpOut?fpOut:fpMC;
EMUFILE *fp = fpOut?fpOut:fpMC;
#ifndef _DONT_SAVE_BACKUP
fp->fseek(fsize, SEEK_SET);
@ -912,7 +939,7 @@ void BackupDevice::ensure(u32 addr, u8 val, EMUFILE_FILE *fpOut)
{
u8 *tmp = new u8[size];
memset(tmp, val, size);
fwrite(tmp, 1, size, fp->get_fp());
fp->fwrite(tmp, size);
delete [] tmp;
}
@ -1297,7 +1324,7 @@ bool BackupDevice::export_no_gba(const char* fname)
std::vector<u8> data(fsize);
u32 pos = fpMC->ftell();
fpMC->fseek(0, SEEK_SET);
fread((char*)&data[0], 1, fsize, fpMC->get_fp());
fpMC->fread((char *)&data[0], fsize);
fpMC->fseek(pos, SEEK_SET);
FILE* outf = fopen(fname,"wb");
@ -1326,7 +1353,7 @@ bool BackupDevice::export_raw(const char* filename)
std::vector<u8> data(fsize);
u32 pos = fpMC->ftell();
fpMC->fseek(0, SEEK_SET);
fread((char*)&data[0], 1, fsize, fpMC->get_fp());
fpMC->fread((char *)&data[0], fsize);
fpMC->fseek(pos, SEEK_SET);
FILE* outf = fopen(filename,"wb");
@ -1525,7 +1552,7 @@ bool BackupDevice::load_movie(EMUFILE* is) {
is->fread((char*)&info.mem_size,4);
is->fseek(0, SEEK_SET);
fpMC = (EMUFILE_FILE*)&is;
fpMC = (EMUFILE*)&is;
state = RUNNING;
addr_size = info.addr_size;

View File

@ -49,7 +49,6 @@
#define MC_SIZE_512MBITS 0x4000000
class EMUFILE;
class EMUFILE_FILE;
//This "backup device" represents a typical retail NDS save memory accessible via AUXSPI.
//It is managed as a core emulator service for historical reasons which are bad,
@ -104,8 +103,8 @@ public:
u32 addr_size;
} savedInfo;
void ensure(u32 addr, EMUFILE_FILE *fpOut = NULL);
void ensure(u32 addr, u8 val, EMUFILE_FILE *fpOut = NULL);
void ensure(u32 addr, EMUFILE *fpOut = NULL);
void ensure(u32 addr, u8 val, EMUFILE *fpOut = NULL);
//and these are used by old savestates
void load_old_state(u32 addr_size, u8* data, u32 datasize);
@ -145,7 +144,7 @@ public:
u8 uninitializedValue;
private:
EMUFILE_FILE *fpMC;
EMUFILE *fpMC;
std::string filename;
u32 fsize;
int readFooter();

View File

@ -3937,6 +3937,23 @@ static BOOL OpenCore(const char* filename)
MainWindowToolbar->EnableButton(IDM_RESET, true);
MainWindowToolbar->ChangeButtonBitmap(IDM_PAUSE, IDB_PAUSE);
// Warn the user if the battery save won't be written to an actual file on disk.
char batteryPath[MAX_PATH] = {0};
memset(batteryPath, 0, MAX_PATH);
path.getpathnoext(path.BATTERY, batteryPath);
std::string batteryPathString = std::string(batteryPath) + ".dsv";
FILE *testFs = fopen(batteryPathString.c_str(), "rb+");
if (testFs == NULL)
{
msgbox->warn("\
Could not get read/write access to the battery save file! The file will not be saved in this current session.\n\n\
Choose Config > Path Settings and ensure that the SaveRam directory exists and is available for read/write access.");
}
else
{
fclose(testFs);
}
return TRUE;
}
else return FALSE;