make it significantly harder to choose an invalid memory card file in the main dolphin config
should fix most errors of "Can not use memory card in slot A" also fix display of a (rarely seen) panicalertT when the same file is chosen for both memorycards recent examples ... http://forums.dolphin-emulator.com/showthread.php?tid=18408 http://forums.dolphin-emulator.com/showthread.php?tid=18354 git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7694 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
2a829fe36c
commit
5f9591cf9d
|
@ -37,7 +37,7 @@
|
|||
#include "Frame.h"
|
||||
#include "HotkeyDlg.h"
|
||||
#include "Main.h"
|
||||
|
||||
#include "MemoryCards\GCMemcard.h"
|
||||
#include "VideoBackendBase.h"
|
||||
|
||||
#define TEXT_BOX(page, text) new wxStaticText(page, wxID_ANY, text, wxDefaultPosition, wxDefaultSize)
|
||||
|
@ -1008,6 +1008,17 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
|
|||
|
||||
if (!filename.empty())
|
||||
{
|
||||
if (File::Exists(filename))
|
||||
{
|
||||
GCMemcard memorycard(filename.c_str());
|
||||
if (!memorycard.IsValid())
|
||||
{
|
||||
PanicAlertT("Cannot use that file as a memory card.\n%s\n" \
|
||||
"is not a valid gamecube memory card file", filename.c_str());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// also check that the path isn't used for the other memcard...
|
||||
if (filename.compare(isSlotA ? SConfig::GetInstance().m_strMemoryCardB
|
||||
: SConfig::GetInstance().m_strMemoryCardA) != 0)
|
||||
|
@ -1025,7 +1036,7 @@ void CConfigMain::ChooseMemcardPath(std::string& strMemcard, bool isSlotA)
|
|||
}
|
||||
else
|
||||
{
|
||||
PanicAlertT("Cannot use that file as a memory card.\n"
|
||||
PanicAlertT("Cannot use that file as a memory card.\n" \
|
||||
"Are you trying to use the same file in both slots?");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -606,7 +606,7 @@ bool CMemcardManager::ReloadMemcard(const char *fileName, int card)
|
|||
// TODO: add error checking and animate icons
|
||||
memoryCard[card] = new GCMemcard(fileName);
|
||||
|
||||
if (memoryCard[card]->fail) return false;
|
||||
if (!memoryCard[card]->IsValid()) return false;
|
||||
|
||||
int j;
|
||||
|
||||
|
|
|
@ -61,25 +61,20 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height)
|
|||
}
|
||||
}
|
||||
|
||||
GCMemcard::GCMemcard(const char *filename)
|
||||
GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis) : m_valid(false), m_fileName(filename)
|
||||
{
|
||||
mcdFile.Open(filename, "r+b");
|
||||
fail = false;
|
||||
if (!mcdFile)
|
||||
File::IOFile mcdFile(m_fileName, "r+b");
|
||||
if (!mcdFile.IsOpen())
|
||||
{
|
||||
if (!AskYesNoT("\"%s\" does not exist.\n Create a new 16MB Memcard?", filename))
|
||||
if (!forceCreation && !AskYesNoT("\"%s\" does not exist.\n Create a new 16MB Memcard?", filename))
|
||||
{
|
||||
fail = true;
|
||||
return;
|
||||
}
|
||||
mcdFile.Open(filename, "wb");
|
||||
if (!mcdFile)
|
||||
Format(forceCreation ? sjis : !AskYesNoT("Format as ascii (NTSC\\PAL)?\nChoose no for sjis (NTSC-J)"));
|
||||
if (!mcdFile.Open(m_fileName, "r+b"))
|
||||
{
|
||||
fail = true;
|
||||
return;
|
||||
}
|
||||
Format(!AskYesNoT("Format as ascii (NTSC\\PAL)?\nChoose no for sjis (NTSC-J)"));
|
||||
mcdFile.Open(filename, "r+b");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -88,41 +83,73 @@ GCMemcard::GCMemcard(const char *filename)
|
|||
SplitPath(filename, NULL, NULL, &fileType);
|
||||
if (strcasecmp(fileType.c_str(), ".raw") && strcasecmp(fileType.c_str(), ".gcp"))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("File has the extension \"%s\"\nvalid extensions are (.raw/.gcp)", fileType.c_str());
|
||||
return;
|
||||
}
|
||||
u32 size = mcdFile.GetSize();
|
||||
if (size < MC_FST_BLOCKS*BLOCK_SIZE)
|
||||
{
|
||||
PanicAlertT("%s failed to load as a memorycard \nfile is not large enough to be a valid memory card file (0x%x bytes)", filename, size);
|
||||
return;
|
||||
}
|
||||
if (size % BLOCK_SIZE)
|
||||
{
|
||||
PanicAlertT("%s failed to load as a memorycard \n Card file size is invalid (0x%x bytes)", filename, size);
|
||||
return;
|
||||
}
|
||||
|
||||
m_sizeMb = (size/BLOCK_SIZE) / MBIT_TO_BLOCKS;
|
||||
switch (m_sizeMb)
|
||||
{
|
||||
case MemCard59Mb:
|
||||
case MemCard123Mb:
|
||||
case MemCard251Mb:
|
||||
case Memcard507Mb:
|
||||
case MemCard1019Mb:
|
||||
case MemCard2043Mb:
|
||||
break;
|
||||
default:
|
||||
PanicAlertT("%s failed to load as a memorycard \n Card size is invalid (0x%x bytes)", filename, size);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mcdFile.Seek(0, SEEK_SET);
|
||||
fail = true;
|
||||
if (!mcdFile.ReadBytes(&hdr, BLOCK_SIZE))
|
||||
{
|
||||
PanicAlertT("Failed to read header correctly\n(0x0000-0x1FFF)");
|
||||
return;
|
||||
}
|
||||
else if (!mcdFile.ReadBytes(&dir, BLOCK_SIZE))
|
||||
if (m_sizeMb != BE16(hdr.SizeMb))
|
||||
{
|
||||
PanicAlertT("Memorycard filesize does not match the header size");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mcdFile.ReadBytes(&dir, BLOCK_SIZE))
|
||||
{
|
||||
PanicAlertT("Failed to read directory correctly\n(0x2000-0x3FFF)");
|
||||
return;
|
||||
}
|
||||
else if (!mcdFile.ReadBytes(&dir_backup, BLOCK_SIZE))
|
||||
|
||||
if (!mcdFile.ReadBytes(&dir_backup, BLOCK_SIZE))
|
||||
{
|
||||
PanicAlertT("Failed to read directory backup correctly\n(0x4000-0x5FFF)");
|
||||
return;
|
||||
}
|
||||
else if (!mcdFile.ReadBytes(&bat, BLOCK_SIZE))
|
||||
|
||||
if (!mcdFile.ReadBytes(&bat, BLOCK_SIZE))
|
||||
{
|
||||
PanicAlertT("Failed to read block allocation table correctly\n(0x6000-0x7FFF)");
|
||||
return;
|
||||
}
|
||||
else if (!mcdFile.ReadBytes(&bat_backup, BLOCK_SIZE))
|
||||
|
||||
if (!mcdFile.ReadBytes(&bat_backup, BLOCK_SIZE))
|
||||
{
|
||||
PanicAlertT("Failed to read block allocation table backup correctly\n(0x8000-0x9FFF)");
|
||||
return;
|
||||
}
|
||||
else
|
||||
fail = false;
|
||||
|
||||
u32 csums = TestChecksums();
|
||||
|
||||
|
@ -130,7 +157,6 @@ GCMemcard::GCMemcard(const char *filename)
|
|||
{
|
||||
// header checksum error!
|
||||
// invalid files do not always get here
|
||||
fail = true;
|
||||
PanicAlertT("Header checksum failed");
|
||||
return;
|
||||
}
|
||||
|
@ -140,7 +166,6 @@ GCMemcard::GCMemcard(const char *filename)
|
|||
if (csums & 0x4)
|
||||
{
|
||||
// backup is also wrong!
|
||||
fail = true;
|
||||
PanicAlertT("Directory checksum failed\n and Directory backup checksum failed");
|
||||
return;
|
||||
}
|
||||
|
@ -160,7 +185,6 @@ GCMemcard::GCMemcard(const char *filename)
|
|||
if (csums & 0x10)
|
||||
{
|
||||
// backup is also wrong!
|
||||
fail = true;
|
||||
PanicAlertT("Block Allocation Table checksum failed");
|
||||
return;
|
||||
}
|
||||
|
@ -185,36 +209,20 @@ GCMemcard::GCMemcard(const char *filename)
|
|||
|
||||
mcdFile.Seek(0xa000, SEEK_SET);
|
||||
|
||||
u16 sizeMb = BE16(hdr.SizeMb);
|
||||
switch (sizeMb)
|
||||
{
|
||||
case MemCard59Mb:
|
||||
case MemCard123Mb:
|
||||
case MemCard251Mb:
|
||||
case Memcard507Mb:
|
||||
case MemCard1019Mb:
|
||||
case MemCard2043Mb:
|
||||
{
|
||||
maxBlock = (u32)sizeMb * MBIT_TO_BLOCKS;
|
||||
mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE;
|
||||
mc_data = new u8[mc_data_size];
|
||||
maxBlock = (u32)m_sizeMb * MBIT_TO_BLOCKS;
|
||||
mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE;
|
||||
mc_data = new u8[mc_data_size];
|
||||
|
||||
if (!mcdFile.ReadBytes(mc_data, mc_data_size))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read save data\n(0xA000-)\nMemcard may be truncated");
|
||||
}
|
||||
break;
|
||||
if (mcdFile.ReadBytes(mc_data, mc_data_size))
|
||||
{
|
||||
m_valid = true;
|
||||
}
|
||||
default:
|
||||
fail = true;
|
||||
PanicAlertT("Memcard failed to load\n Card size is invalid (%04X)", sizeMb);
|
||||
else
|
||||
{
|
||||
PanicAlertT("Failed to read save data\n(0xA000-)\nMemcard may be truncated");
|
||||
}
|
||||
}
|
||||
|
||||
bool GCMemcard::IsOpen()
|
||||
{
|
||||
return mcdFile.IsOpen();
|
||||
mcdFile.Close();
|
||||
}
|
||||
|
||||
bool GCMemcard::IsAsciiEncoding()
|
||||
|
@ -224,6 +232,7 @@ bool GCMemcard::IsAsciiEncoding()
|
|||
|
||||
bool GCMemcard::Save()
|
||||
{
|
||||
File::IOFile mcdFile(m_fileName, "wb");
|
||||
mcdFile.Seek(0, SEEK_SET);
|
||||
|
||||
mcdFile.WriteBytes(&hdr, BLOCK_SIZE);
|
||||
|
@ -233,7 +242,7 @@ bool GCMemcard::Save()
|
|||
mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(mc_data, mc_data_size);
|
||||
|
||||
return mcdFile.IsGood();
|
||||
return mcdFile.Close();
|
||||
}
|
||||
|
||||
void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
|
||||
|
@ -257,9 +266,6 @@ void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
|
|||
|
||||
u32 GCMemcard::TestChecksums()
|
||||
{
|
||||
if (!mcdFile)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
u16 csum1=0,
|
||||
csum2=0;
|
||||
|
||||
|
@ -290,7 +296,7 @@ u32 GCMemcard::TestChecksums()
|
|||
|
||||
bool GCMemcard::FixChecksums()
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
u16 csum1=0,
|
||||
|
@ -331,7 +337,7 @@ bool GCMemcard::FixChecksums()
|
|||
|
||||
u8 GCMemcard::GetNumFiles()
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return 0;
|
||||
|
||||
u8 j = 0;
|
||||
|
@ -345,7 +351,7 @@ u8 GCMemcard::GetNumFiles()
|
|||
|
||||
u16 GCMemcard::GetFreeBlocks()
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return 0;
|
||||
|
||||
return BE16(bat.FreeBlocks);
|
||||
|
@ -353,7 +359,7 @@ u16 GCMemcard::GetFreeBlocks()
|
|||
|
||||
u8 GCMemcard::TitlePresent(DEntry d)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return DIRLEN;
|
||||
|
||||
u8 i = 0;
|
||||
|
@ -374,7 +380,7 @@ u8 GCMemcard::TitlePresent(DEntry d)
|
|||
|
||||
bool GCMemcard::DEntry_GameCode(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
memcpy(buffer, dir.Dir[index].Gamecode, 4);
|
||||
|
@ -384,7 +390,7 @@ bool GCMemcard::DEntry_GameCode(u8 index, char *buffer)
|
|||
|
||||
bool GCMemcard::DEntry_Markercode(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
memcpy(buffer, dir.Dir[index].Markercode, 2);
|
||||
|
@ -393,7 +399,7 @@ bool GCMemcard::DEntry_Markercode(u8 index, char *buffer)
|
|||
}
|
||||
bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
int x = dir.Dir[index].BIFlags;
|
||||
|
@ -408,7 +414,7 @@ bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer)
|
|||
|
||||
bool GCMemcard::DEntry_FileName(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
memcpy (buffer, (const char*)dir.Dir[index].Filename, DENTRY_STRLEN);
|
||||
|
@ -428,7 +434,7 @@ u32 GCMemcard::DEntry_ImageOffset(u8 index)
|
|||
|
||||
bool GCMemcard::DEntry_IconFmt(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!m_valid) return false;
|
||||
|
||||
int x = dir.Dir[index].IconFmt[0];
|
||||
for(int i = 0; i < 16; i++)
|
||||
|
@ -449,7 +455,7 @@ u16 GCMemcard::DEntry_AnimSpeed(u8 index)
|
|||
|
||||
bool GCMemcard::DEntry_Permissions(u8 index, char *fn)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!m_valid) return false;
|
||||
fn[0] = (dir.Dir[index].Permissions & 16) ? 'x' : 'M';
|
||||
fn[1] = (dir.Dir[index].Permissions & 8) ? 'x' : 'C';
|
||||
fn[2] = (dir.Dir[index].Permissions & 4) ? 'P' : 'x';
|
||||
|
@ -464,7 +470,7 @@ u8 GCMemcard::DEntry_CopyCounter(u8 index)
|
|||
|
||||
u16 GCMemcard::DEntry_FirstBlock(u8 index)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return 0xFFFF;
|
||||
|
||||
u16 block = BE16(dir.Dir[index].FirstBlock);
|
||||
|
@ -474,7 +480,7 @@ u16 GCMemcard::DEntry_FirstBlock(u8 index)
|
|||
|
||||
u16 GCMemcard::DEntry_BlockCount(u8 index)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return 0xFFFF;
|
||||
|
||||
u16 blocks = BE16(dir.Dir[index].BlockCount);
|
||||
|
@ -489,7 +495,7 @@ u32 GCMemcard::DEntry_CommentsAddress(u8 index)
|
|||
|
||||
bool GCMemcard::DEntry_Comment1(u8 index, char* buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
|
||||
|
@ -506,7 +512,7 @@ bool GCMemcard::DEntry_Comment1(u8 index, char* buffer)
|
|||
|
||||
bool GCMemcard::DEntry_Comment2(u8 index, char* buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
|
||||
|
@ -524,7 +530,7 @@ bool GCMemcard::DEntry_Comment2(u8 index, char* buffer)
|
|||
|
||||
bool GCMemcard::DEntry_Copy(u8 index, GCMemcard::DEntry& info)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
info = dir.Dir[index];
|
||||
|
@ -533,7 +539,7 @@ bool GCMemcard::DEntry_Copy(u8 index, GCMemcard::DEntry& info)
|
|||
|
||||
u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return NOMEMCARD;
|
||||
|
||||
u16 block = DEntry_FirstBlock(index);
|
||||
|
@ -572,7 +578,7 @@ u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old)
|
|||
|
||||
u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return NOMEMCARD;
|
||||
|
||||
if (GetNumFiles() >= DIRLEN)
|
||||
|
@ -674,7 +680,7 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
|||
|
||||
u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return NOMEMCARD;
|
||||
|
||||
//error checking
|
||||
|
@ -757,7 +763,7 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
|||
|
||||
u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return NOMEMCARD;
|
||||
|
||||
DEntry tempDEntry;
|
||||
|
@ -784,7 +790,7 @@ u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index)
|
|||
|
||||
u32 GCMemcard::ImportGci(const char *inputFile, std::string outputFile)
|
||||
{
|
||||
if (outputFile.empty() && !mcdFile)
|
||||
if (outputFile.empty() && !m_valid)
|
||||
return OPENFAIL;
|
||||
|
||||
File::IOFile gci(inputFile, "rb");
|
||||
|
@ -1013,7 +1019,7 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length)
|
|||
|
||||
bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return false;
|
||||
|
||||
int flags = dir.Dir[index].BIFlags;
|
||||
|
@ -1054,7 +1060,7 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer)
|
|||
|
||||
u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
|
||||
{
|
||||
if (!mcdFile)
|
||||
if (!m_valid)
|
||||
return 0;
|
||||
|
||||
// To ensure only one type of icon is used
|
||||
|
|
|
@ -71,12 +71,15 @@ class GCMemcard
|
|||
{
|
||||
private:
|
||||
friend class CMemcardManagerDebug;
|
||||
File::IOFile mcdFile;
|
||||
bool m_valid;
|
||||
std::string m_fileName;
|
||||
|
||||
u32 maxBlock;
|
||||
u32 mc_data_size;
|
||||
u8* mc_data;
|
||||
|
||||
u16 m_sizeMb;
|
||||
|
||||
#pragma pack(push,1)
|
||||
struct OSTime {
|
||||
u32 low;
|
||||
|
@ -164,12 +167,12 @@ private:
|
|||
} bat,bat_backup;
|
||||
#pragma pack(pop)
|
||||
|
||||
u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile);
|
||||
|
||||
public:
|
||||
bool fail;
|
||||
|
||||
GCMemcard(const char* fileName);
|
||||
|
||||
bool IsOpen();
|
||||
GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false);
|
||||
bool IsValid() { return m_valid; }
|
||||
bool IsAsciiEncoding();
|
||||
bool Save();
|
||||
bool Format(bool sjis = false, bool New = true, int slot = 0, u16 SizeMb = MemCard2043Mb, bool hdrOnly = false);
|
||||
|
@ -227,10 +230,7 @@ public:
|
|||
// adds the file to the directory and copies its contents
|
||||
// if remove > 0 it will pad bat.map with 0's sizeof remove
|
||||
u32 ImportFile(DEntry& direntry, u8* contents, int remove);
|
||||
private:
|
||||
u32 ImportGciInternal(FILE* gcih, const char *inputFile, std::string outputFile);
|
||||
|
||||
public:
|
||||
// delete a file from the directory
|
||||
u32 RemoveFile(u8 index);
|
||||
|
||||
|
|
Loading…
Reference in New Issue