mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 09:09:52 -06:00
Wrapped fopen/close/read/write functions inside a simple "IOFile" class. Reading, writing, and error checking became simpler in most cases. It should be near impossible to forget to close a file now that the destructor takes care of it. (I hope this fixes Issue 3635) I have tested the functionality of most things, but it is possible I broke something. :p
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@7328 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
@ -62,31 +62,28 @@ void decodeCI8image(u32* dst, u8* src, u16* pal, int width, int height)
|
||||
}
|
||||
|
||||
GCMemcard::GCMemcard(const char *filename)
|
||||
{
|
||||
FILE *mcd = fopen(filename, "r+b");
|
||||
mcdFile = mcd;
|
||||
{
|
||||
mcdFile.Open(filename, "r+b");
|
||||
fail = false;
|
||||
if (!mcd)
|
||||
if (!mcdFile)
|
||||
{
|
||||
if (!AskYesNoT("\"%s\" does not exist.\n Create a new 16MB Memcard?", filename))
|
||||
{
|
||||
fail = true;
|
||||
return;
|
||||
}
|
||||
mcd = fopen(filename, "wb");
|
||||
if (!mcd)
|
||||
mcdFile.Open(filename, "wb");
|
||||
if (!mcdFile)
|
||||
{
|
||||
fail = true;
|
||||
return;
|
||||
}
|
||||
mcdFile = mcd;
|
||||
Format(!AskYesNoT("Format as ascii (NTSC\\PAL)?\nChoose no for sjis (NTSC-J)"));
|
||||
fclose(mcd);
|
||||
mcd = fopen(filename, "r+b");
|
||||
mcdFile.Open(filename, "r+b");
|
||||
}
|
||||
else
|
||||
{
|
||||
//This function can be removed once more about hdr is known and we can check for a valid header
|
||||
//This function can be removed once more about hdr is known and we can check for a valid header
|
||||
std::string fileType;
|
||||
SplitPath(filename, NULL, NULL, &fileType);
|
||||
if (strcasecmp(fileType.c_str(), ".raw") && strcasecmp(fileType.c_str(), ".gcp"))
|
||||
@ -97,41 +94,39 @@ GCMemcard::GCMemcard(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
fseeko(mcd, 0, SEEK_SET);
|
||||
if (fread(&hdr, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
|
||||
mcdFile.Seek(0, SEEK_SET);
|
||||
fail = true;
|
||||
if (!mcdFile.ReadBytes(&hdr, BLOCK_SIZE))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read header correctly\n(0x0000-0x1FFF)");
|
||||
return;
|
||||
}
|
||||
if (fread(&dir, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
|
||||
else if (!mcdFile.ReadBytes(&dir, BLOCK_SIZE))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read directory correctly\n(0x2000-0x3FFF)");
|
||||
return;
|
||||
}
|
||||
if (fread(&dir_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
|
||||
else if (!mcdFile.ReadBytes(&dir_backup, BLOCK_SIZE))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read directory backup correctly\n(0x4000-0x5FFF)");
|
||||
return;
|
||||
}
|
||||
if (fread(&bat, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
|
||||
else if (!mcdFile.ReadBytes(&bat, BLOCK_SIZE))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read block allocation table correctly\n(0x6000-0x7FFF)");
|
||||
return;
|
||||
}
|
||||
if (fread(&bat_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE)
|
||||
else if (!mcdFile.ReadBytes(&bat_backup, BLOCK_SIZE))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read block allocation table backup correctly\n(0x8000-0x9FFF)");
|
||||
return;
|
||||
}
|
||||
else
|
||||
fail = false;
|
||||
|
||||
u32 csums = TestChecksums();
|
||||
|
||||
if (csums&1)
|
||||
if (csums & 0x1)
|
||||
{
|
||||
// header checksum error!
|
||||
// invalid files do not always get here
|
||||
@ -140,9 +135,9 @@ GCMemcard::GCMemcard(const char *filename)
|
||||
return;
|
||||
}
|
||||
|
||||
if (csums&2) // directory checksum error!
|
||||
if (csums & 0x2) // directory checksum error!
|
||||
{
|
||||
if (csums&4)
|
||||
if (csums & 0x4)
|
||||
{
|
||||
// backup is also wrong!
|
||||
fail = true;
|
||||
@ -160,9 +155,9 @@ GCMemcard::GCMemcard(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
if (csums&8) // BAT checksum error!
|
||||
if (csums & 0x8) // BAT checksum error!
|
||||
{
|
||||
if (csums&16)
|
||||
if (csums & 0x10)
|
||||
{
|
||||
// backup is also wrong!
|
||||
fail = true;
|
||||
@ -188,7 +183,7 @@ GCMemcard::GCMemcard(const char *filename)
|
||||
// bat = bat_backup; // needed?
|
||||
}
|
||||
|
||||
fseeko(mcd, 0xa000, SEEK_SET);
|
||||
mcdFile.Seek(0xa000, SEEK_SET);
|
||||
|
||||
u16 sizeMb = BE16(hdr.SizeMb);
|
||||
switch (sizeMb)
|
||||
@ -204,8 +199,7 @@ GCMemcard::GCMemcard(const char *filename)
|
||||
mc_data_size = (maxBlock - MC_FST_BLOCKS) * BLOCK_SIZE;
|
||||
mc_data = new u8[mc_data_size];
|
||||
|
||||
size_t read = fread(mc_data, 1, mc_data_size, mcd);
|
||||
if (mc_data_size != read)
|
||||
if (!mcdFile.ReadBytes(mc_data, mc_data_size))
|
||||
{
|
||||
fail = true;
|
||||
PanicAlertT("Failed to read save data\n(0xA000-)\nMemcard may be truncated");
|
||||
@ -218,15 +212,9 @@ GCMemcard::GCMemcard(const char *filename)
|
||||
}
|
||||
}
|
||||
|
||||
GCMemcard::~GCMemcard()
|
||||
{
|
||||
if (!mcdFile) return;
|
||||
fclose((FILE*)mcdFile);
|
||||
}
|
||||
|
||||
bool GCMemcard::IsOpen()
|
||||
{
|
||||
return (mcdFile!=NULL);
|
||||
return mcdFile.IsOpen();
|
||||
}
|
||||
|
||||
bool GCMemcard::IsAsciiEncoding()
|
||||
@ -236,16 +224,16 @@ bool GCMemcard::IsAsciiEncoding()
|
||||
|
||||
bool GCMemcard::Save()
|
||||
{
|
||||
bool completeWrite = true;
|
||||
FILE *mcd=(FILE*)mcdFile;
|
||||
fseeko(mcd, 0, SEEK_SET);
|
||||
if (fwrite(&hdr, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
|
||||
if (fwrite(&dir, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
|
||||
if (fwrite(&dir_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
|
||||
if (fwrite(&bat, 1, BLOCK_SIZE ,mcd) != BLOCK_SIZE) completeWrite = false;
|
||||
if (fwrite(&bat_backup, 1, BLOCK_SIZE, mcd) != BLOCK_SIZE) completeWrite = false;
|
||||
if (fwrite(mc_data, 1, mc_data_size, mcd) != mc_data_size) completeWrite = false;
|
||||
return completeWrite;
|
||||
mcdFile.Seek(0, SEEK_SET);
|
||||
|
||||
mcdFile.WriteBytes(&hdr, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(&dir, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(&dir_backup, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(&bat, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(&bat_backup, BLOCK_SIZE);
|
||||
mcdFile.WriteBytes(mc_data, mc_data_size);
|
||||
|
||||
return mcdFile.IsGood();
|
||||
}
|
||||
|
||||
void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
|
||||
@ -269,7 +257,8 @@ void GCMemcard::calc_checksumsBE(u16 *buf, u32 num, u16 *c1, u16 *c2)
|
||||
|
||||
u32 GCMemcard::TestChecksums()
|
||||
{
|
||||
if (!mcdFile) return 0xFFFFFFFF;
|
||||
if (!mcdFile)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
u16 csum1=0,
|
||||
csum2=0;
|
||||
@ -296,12 +285,13 @@ u32 GCMemcard::TestChecksums()
|
||||
if (BE16(bat_backup.CheckSum1) != csum1) results |= 16;
|
||||
if (BE16(bat_backup.CheckSum2) != csum2) results |= 16;
|
||||
|
||||
return 0;
|
||||
return results;
|
||||
}
|
||||
|
||||
bool GCMemcard::FixChecksums()
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
u16 csum1=0,
|
||||
csum2=0;
|
||||
@ -341,7 +331,9 @@ bool GCMemcard::FixChecksums()
|
||||
|
||||
u8 GCMemcard::GetNumFiles()
|
||||
{
|
||||
if (!mcdFile) return 0;
|
||||
if (!mcdFile)
|
||||
return 0;
|
||||
|
||||
u8 j = 0;
|
||||
for (int i = 0; i < DIRLEN; i++)
|
||||
{
|
||||
@ -353,13 +345,16 @@ u8 GCMemcard::GetNumFiles()
|
||||
|
||||
u16 GCMemcard::GetFreeBlocks()
|
||||
{
|
||||
if (!mcdFile) return 0;
|
||||
if (!mcdFile)
|
||||
return 0;
|
||||
|
||||
return BE16(bat.FreeBlocks);
|
||||
}
|
||||
|
||||
u8 GCMemcard::TitlePresent(DEntry d)
|
||||
{
|
||||
if (!mcdFile) return DIRLEN;
|
||||
if (!mcdFile)
|
||||
return DIRLEN;
|
||||
|
||||
u8 i = 0;
|
||||
while(i < DIRLEN)
|
||||
@ -379,7 +374,8 @@ u8 GCMemcard::TitlePresent(DEntry d)
|
||||
|
||||
bool GCMemcard::DEntry_GameCode(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
memcpy(buffer, dir.Dir[index].Gamecode, 4);
|
||||
buffer[4] = 0;
|
||||
@ -388,14 +384,17 @@ bool GCMemcard::DEntry_GameCode(u8 index, char *buffer)
|
||||
|
||||
bool GCMemcard::DEntry_Markercode(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
memcpy(buffer, dir.Dir[index].Markercode, 2);
|
||||
buffer[2] = 0;
|
||||
return true;
|
||||
}
|
||||
bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
int x = dir.Dir[index].BIFlags;
|
||||
for (int i = 0; i < 8; i++)
|
||||
@ -409,7 +408,9 @@ bool GCMemcard::DEntry_BIFlags(u8 index, char *buffer)
|
||||
|
||||
bool GCMemcard::DEntry_FileName(u8 index, char *buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
memcpy (buffer, (const char*)dir.Dir[index].Filename, DENTRY_STRLEN);
|
||||
buffer[31] = 0;
|
||||
return true;
|
||||
@ -463,7 +464,9 @@ u8 GCMemcard::DEntry_CopyCounter(u8 index)
|
||||
|
||||
u16 GCMemcard::DEntry_FirstBlock(u8 index)
|
||||
{
|
||||
if (!mcdFile) return 0xFFFF;
|
||||
if (!mcdFile)
|
||||
return 0xFFFF;
|
||||
|
||||
u16 block = BE16(dir.Dir[index].FirstBlock);
|
||||
if (block > (u16) maxBlock) return 0xFFFF;
|
||||
return block;
|
||||
@ -471,7 +474,8 @@ u16 GCMemcard::DEntry_FirstBlock(u8 index)
|
||||
|
||||
u16 GCMemcard::DEntry_BlockCount(u8 index)
|
||||
{
|
||||
if (!mcdFile) return 0xFFFF;
|
||||
if (!mcdFile)
|
||||
return 0xFFFF;
|
||||
|
||||
u16 blocks = BE16(dir.Dir[index].BlockCount);
|
||||
if (blocks > (u16) maxBlock) return 0xFFFF;
|
||||
@ -485,7 +489,8 @@ u32 GCMemcard::DEntry_CommentsAddress(u8 index)
|
||||
|
||||
bool GCMemcard::DEntry_Comment1(u8 index, char* buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
|
||||
u32 DataBlock = BE16(dir.Dir[index].FirstBlock) - MC_FST_BLOCKS;
|
||||
@ -501,7 +506,8 @@ bool GCMemcard::DEntry_Comment1(u8 index, char* buffer)
|
||||
|
||||
bool GCMemcard::DEntry_Comment2(u8 index, char* buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
u32 Comment1 = BE32(dir.Dir[index].CommentsAddr);
|
||||
u32 Comment2 = Comment1 + DENTRY_STRLEN;
|
||||
@ -518,7 +524,8 @@ bool GCMemcard::DEntry_Comment2(u8 index, char* buffer)
|
||||
|
||||
bool GCMemcard::DEntry_Copy(u8 index, GCMemcard::DEntry& info)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
info = dir.Dir[index];
|
||||
return true;
|
||||
@ -526,7 +533,8 @@ bool GCMemcard::DEntry_Copy(u8 index, GCMemcard::DEntry& info)
|
||||
|
||||
u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old)
|
||||
{
|
||||
if (!mcdFile) return NOMEMCARD;
|
||||
if (!mcdFile)
|
||||
return NOMEMCARD;
|
||||
|
||||
u16 block = DEntry_FirstBlock(index);
|
||||
u16 saveLength = DEntry_BlockCount(index);
|
||||
@ -564,7 +572,8 @@ u32 GCMemcard::DEntry_GetSaveData(u8 index, u8* dest, bool old)
|
||||
|
||||
u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
||||
{
|
||||
if (!mcdFile) return NOMEMCARD;
|
||||
if (!mcdFile)
|
||||
return NOMEMCARD;
|
||||
|
||||
if (GetNumFiles() >= DIRLEN)
|
||||
{
|
||||
@ -665,7 +674,8 @@ u32 GCMemcard::ImportFile(DEntry& direntry, u8* contents, int remove)
|
||||
|
||||
u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
||||
{
|
||||
if (!mcdFile) return NOMEMCARD;
|
||||
if (!mcdFile)
|
||||
return NOMEMCARD;
|
||||
|
||||
//error checking
|
||||
u16 startingblock = 0;
|
||||
@ -747,7 +757,8 @@ u32 GCMemcard::RemoveFile(u8 index) //index in the directory array
|
||||
|
||||
u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index)
|
||||
{
|
||||
if (!mcdFile) return NOMEMCARD;
|
||||
if (!mcdFile)
|
||||
return NOMEMCARD;
|
||||
|
||||
DEntry tempDEntry;
|
||||
if (!source.DEntry_Copy(index, tempDEntry)) return NOMEMCARD;
|
||||
@ -773,18 +784,19 @@ u32 GCMemcard::CopyFrom(GCMemcard& source, u8 index)
|
||||
|
||||
u32 GCMemcard::ImportGci(const char *inputFile, std::string outputFile)
|
||||
{
|
||||
if (outputFile.empty() && !mcdFile) return OPENFAIL;
|
||||
if (outputFile.empty() && !mcdFile)
|
||||
return OPENFAIL;
|
||||
|
||||
FILE *gci = fopen(inputFile, "rb");
|
||||
if (!gci) return OPENFAIL;
|
||||
File::IOFile gci(inputFile, "rb");
|
||||
if (!gci)
|
||||
return OPENFAIL;
|
||||
|
||||
u32 result = ImportGciInternal(gci, inputFile, outputFile);
|
||||
fclose(gci);
|
||||
u32 result = ImportGciInternal(gci.ReleaseHandle(), inputFile, outputFile);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
u32 GCMemcard::ImportGciInternal(FILE *gci, const char *inputFile, std::string outputFile)
|
||||
u32 GCMemcard::ImportGciInternal(File::IOFile gci, const char *inputFile, std::string outputFile)
|
||||
{
|
||||
int offset;
|
||||
char tmp[0xD];
|
||||
@ -795,7 +807,7 @@ u32 GCMemcard::ImportGciInternal(FILE *gci, const char *inputFile, std::string o
|
||||
offset = GCI;
|
||||
else
|
||||
{
|
||||
fread(tmp, 1, 0xD, gci);
|
||||
gci.ReadBytes(tmp, 0xD);
|
||||
if (!strcasecmp(fileType.c_str(), ".gcs"))
|
||||
{
|
||||
if (!memcmp(tmp, "GCSAVE", 6)) // Header must be uppercase
|
||||
@ -813,29 +825,29 @@ u32 GCMemcard::ImportGciInternal(FILE *gci, const char *inputFile, std::string o
|
||||
else
|
||||
return OPENFAIL;
|
||||
}
|
||||
fseeko(gci, offset, SEEK_SET);
|
||||
gci.Seek(offset, SEEK_SET);
|
||||
|
||||
DEntry *tempDEntry = new DEntry;
|
||||
fread(tempDEntry, 1, DENTRY_SIZE, gci);
|
||||
int fStart = (int) ftello(gci);
|
||||
fseeko(gci, 0, SEEK_END);
|
||||
int length = (int) ftello(gci) - fStart;
|
||||
fseeko(gci, offset + DENTRY_SIZE, SEEK_SET);
|
||||
gci.ReadBytes(tempDEntry, DENTRY_SIZE);
|
||||
const int fStart = (int)gci.Tell();
|
||||
gci.Seek(0, SEEK_END);
|
||||
const int length = (int)gci.Tell() - fStart;
|
||||
gci.Seek(offset + DENTRY_SIZE, SEEK_SET);
|
||||
|
||||
Gcs_SavConvert(tempDEntry, offset, length);
|
||||
|
||||
if (length != BE16(tempDEntry->BlockCount) * BLOCK_SIZE)
|
||||
return LENGTHFAIL;
|
||||
if (ftello(gci) != offset + DENTRY_SIZE) // Verify correct file position
|
||||
if (gci.Tell() != offset + DENTRY_SIZE) // Verify correct file position
|
||||
return OPENFAIL;
|
||||
|
||||
u32 size = BE16((tempDEntry->BlockCount)) * BLOCK_SIZE;
|
||||
u8 *tempSaveData = new u8[size];
|
||||
fread(tempSaveData, 1, size, gci);
|
||||
gci.ReadBytes(tempSaveData, size);
|
||||
u32 ret;
|
||||
if(!outputFile.empty())
|
||||
if (!outputFile.empty())
|
||||
{
|
||||
FILE *gci2 = fopen(outputFile.c_str(), "wb");
|
||||
File::IOFile gci2(outputFile, "wb");
|
||||
bool completeWrite = true;
|
||||
if (!gci2)
|
||||
{
|
||||
@ -843,18 +855,19 @@ u32 GCMemcard::ImportGciInternal(FILE *gci, const char *inputFile, std::string o
|
||||
delete tempDEntry;
|
||||
return OPENFAIL;
|
||||
}
|
||||
fseeko(gci2, 0, SEEK_SET);
|
||||
gci2.Seek(0, SEEK_SET);
|
||||
|
||||
if (fwrite(tempDEntry, 1, DENTRY_SIZE, gci2) != DENTRY_SIZE)
|
||||
if (!gci2.WriteBytes(tempDEntry, DENTRY_SIZE))
|
||||
completeWrite = false;
|
||||
int fileBlocks = BE16(tempDEntry->BlockCount);
|
||||
fseeko(gci2, DENTRY_SIZE, SEEK_SET);
|
||||
gci2.Seek(DENTRY_SIZE, SEEK_SET);
|
||||
|
||||
if (fwrite(tempSaveData, 1, BLOCK_SIZE * fileBlocks, gci2) != (unsigned)(BLOCK_SIZE * fileBlocks))
|
||||
if (!gci2.WriteBytes(tempSaveData, BLOCK_SIZE * fileBlocks))
|
||||
completeWrite = false;
|
||||
fclose(gci2);
|
||||
if (completeWrite) ret = GCS;
|
||||
else ret = WRITEFAIL;
|
||||
if (completeWrite)
|
||||
ret = GCS;
|
||||
else
|
||||
ret = WRITEFAIL;
|
||||
}
|
||||
else
|
||||
ret = ImportFile(*tempDEntry, tempSaveData, 0);
|
||||
@ -866,7 +879,7 @@ u32 GCMemcard::ImportGciInternal(FILE *gci, const char *inputFile, std::string o
|
||||
|
||||
u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2)
|
||||
{
|
||||
FILE *gci;
|
||||
File::IOFile gci;
|
||||
int offset = GCI;
|
||||
if (!strcasecmp(fileName, "."))
|
||||
{
|
||||
@ -879,12 +892,12 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2)
|
||||
DEntry_GameCode(index, GameCode);
|
||||
|
||||
sprintf(filename, "%s/%s_%s.gci", fileName2->c_str(), GameCode, dir.Dir[index].Filename);
|
||||
gci = fopen((const char *)filename, "wb");
|
||||
gci.Open(filename, "wb");
|
||||
delete[] filename;
|
||||
}
|
||||
else
|
||||
{
|
||||
gci = fopen(fileName, "wb");
|
||||
gci.Open(fileName, "wb");
|
||||
|
||||
std::string fileType;
|
||||
SplitPath(fileName, NULL, NULL, &fileType);
|
||||
@ -898,10 +911,10 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2)
|
||||
}
|
||||
}
|
||||
|
||||
if (!gci) return OPENFAIL;
|
||||
bool completeWrite = true;
|
||||
if (!gci)
|
||||
return OPENFAIL;
|
||||
|
||||
fseeko(gci, 0, SEEK_SET);
|
||||
gci.Seek(0, SEEK_SET);
|
||||
|
||||
switch(offset)
|
||||
{
|
||||
@ -909,54 +922,54 @@ u32 GCMemcard::ExportGci(u8 index, const char *fileName, std::string *fileName2)
|
||||
u8 gcsHDR[GCS];
|
||||
memset(gcsHDR, 0, GCS);
|
||||
memcpy(gcsHDR, "GCSAVE", 6);
|
||||
if (fwrite(gcsHDR, 1, GCS, gci) != GCS) completeWrite = false;
|
||||
gci.WriteArray(gcsHDR, GCS);
|
||||
break;
|
||||
|
||||
case SAV:
|
||||
u8 savHDR[SAV];
|
||||
memset(savHDR, 0, SAV);
|
||||
memcpy(savHDR, "DATELGC_SAVE", 0xC);
|
||||
if (fwrite(savHDR, 1, SAV, gci) != SAV) completeWrite = false;
|
||||
gci.WriteArray(savHDR, SAV);
|
||||
break;
|
||||
}
|
||||
|
||||
DEntry tempDEntry;
|
||||
if (!DEntry_Copy(index, tempDEntry))
|
||||
{
|
||||
fclose(gci);
|
||||
return NOMEMCARD;
|
||||
}
|
||||
|
||||
|
||||
Gcs_SavConvert(&tempDEntry, offset);
|
||||
if (fwrite(&tempDEntry, 1, DENTRY_SIZE, gci) != DENTRY_SIZE) completeWrite = false;
|
||||
gci.WriteBytes(&tempDEntry, DENTRY_SIZE);
|
||||
|
||||
u32 size = DEntry_BlockCount(index);
|
||||
if (size == 0xFFFF)
|
||||
{
|
||||
fclose(gci);
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
size *= BLOCK_SIZE;
|
||||
u8 *tempSaveData = new u8[size];
|
||||
|
||||
switch(DEntry_GetSaveData(index, tempSaveData, true))
|
||||
{
|
||||
case FAIL:
|
||||
fclose(gci);
|
||||
delete[] tempSaveData;
|
||||
return FAIL;
|
||||
|
||||
case NOMEMCARD:
|
||||
fclose(gci);
|
||||
delete[] tempSaveData;
|
||||
return NOMEMCARD;
|
||||
}
|
||||
fseeko(gci, DENTRY_SIZE + offset, SEEK_SET);
|
||||
if (fwrite(tempSaveData, 1, size, gci) != size)
|
||||
completeWrite = false;
|
||||
fclose(gci);
|
||||
gci.Seek(DENTRY_SIZE + offset, SEEK_SET);
|
||||
gci.WriteBytes(tempSaveData, size);
|
||||
|
||||
delete[] tempSaveData;
|
||||
if (completeWrite) return SUCCESS;
|
||||
else return WRITEFAIL;
|
||||
|
||||
if (gci.IsGood())
|
||||
return SUCCESS;
|
||||
else
|
||||
return WRITEFAIL;
|
||||
}
|
||||
|
||||
void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length)
|
||||
@ -999,7 +1012,8 @@ void GCMemcard::Gcs_SavConvert(DEntry* tempDEntry, int saveType, int length)
|
||||
|
||||
bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer)
|
||||
{
|
||||
if (!mcdFile) return false;
|
||||
if (!mcdFile)
|
||||
return false;
|
||||
|
||||
int flags = dir.Dir[index].BIFlags;
|
||||
// Timesplitters 2 is the only game that I see this in
|
||||
@ -1039,7 +1053,8 @@ bool GCMemcard::ReadBannerRGBA8(u8 index, u32* buffer)
|
||||
|
||||
u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
|
||||
{
|
||||
if (!mcdFile) return 0;
|
||||
if (!mcdFile)
|
||||
return 0;
|
||||
|
||||
// To ensure only one type of icon is used
|
||||
// Sonic Heroes it the only game I have seen that tries to use a CI8 and RGB5A3 icon
|
||||
@ -1137,12 +1152,10 @@ u32 GCMemcard::ReadAnimRGBA8(u8 index, u32* buffer, u8 *delays)
|
||||
|
||||
bool GCMemcard::Format(bool sjis, bool New, int slot, u16 SizeMb, bool hdrOnly)
|
||||
{
|
||||
//Currently only formats cards for slot A
|
||||
u32 data_size = BLOCK_SIZE * (SizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
|
||||
// Currently only formats cards for slot A
|
||||
const u32 data_size = BLOCK_SIZE * (SizeMb * MBIT_TO_BLOCKS - MC_FST_BLOCKS);
|
||||
|
||||
SRAM m_SRAM;
|
||||
FILE * pStream;
|
||||
u64 time, rand;
|
||||
|
||||
if (New)
|
||||
{
|
||||
@ -1152,18 +1165,19 @@ bool GCMemcard::Format(bool sjis, bool New, int slot, u16 SizeMb, bool hdrOnly)
|
||||
// Only Format 16MB memcards for now
|
||||
if ((SizeMb != MemCard2043Mb) || (data_size != mc_data_size)) return false;
|
||||
|
||||
pStream = fopen(File::GetUserPath(F_GCSRAM_IDX).c_str(), "rb");
|
||||
File::IOFile pStream(File::GetUserPath(F_GCSRAM_IDX), "rb");
|
||||
if (pStream)
|
||||
{
|
||||
fread(&m_SRAM, 1, 64, pStream);
|
||||
fclose(pStream);
|
||||
pStream.ReadBytes(&m_SRAM, 64);
|
||||
pStream.Close();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_SRAM = sram_dump;
|
||||
}
|
||||
time = CEXIIPL::GetGCTime();
|
||||
rand = Common::swap64(time);
|
||||
|
||||
const u64 time = CEXIIPL::GetGCTime();
|
||||
u64 rand = Common::swap64(time);
|
||||
|
||||
memset(&hdr, 0xFF, BLOCK_SIZE);
|
||||
for(int i = 0; i < 12; i++)
|
||||
@ -1203,4 +1217,3 @@ bool GCMemcard::Format(bool sjis, bool New, int slot, u16 SizeMb, bool hdrOnly)
|
||||
Save();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ class GCMemcard
|
||||
{
|
||||
private:
|
||||
friend class CMemcardManagerDebug;
|
||||
void* mcdFile;
|
||||
File::IOFile mcdFile;
|
||||
|
||||
u32 maxBlock;
|
||||
u32 mc_data_size;
|
||||
@ -167,12 +167,8 @@ private:
|
||||
public:
|
||||
bool fail;
|
||||
|
||||
// constructor
|
||||
GCMemcard(const char* fileName);
|
||||
|
||||
// destructor
|
||||
~GCMemcard();
|
||||
|
||||
bool IsOpen();
|
||||
bool IsAsciiEncoding();
|
||||
bool Save();
|
||||
@ -232,7 +228,7 @@ public:
|
||||
// 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 *gci, const char *inputFile, std::string outputFile);
|
||||
u32 ImportGciInternal(File::IOFile gci, const char *inputFile, std::string outputFile);
|
||||
|
||||
public:
|
||||
// delete a file from the directory
|
||||
|
@ -86,20 +86,20 @@ CWiiSaveCrypted::CWiiSaveCrypted(const char* FileName, u64 title)
|
||||
|
||||
void CWiiSaveCrypted::ReadHDR()
|
||||
{
|
||||
fpData_bin = fopen(pathData_bin, "rb");
|
||||
File::IOFile fpData_bin(pathData_bin, "rb");
|
||||
if (!fpData_bin)
|
||||
{
|
||||
PanicAlertT("Cannot open %s", pathData_bin);
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
if (fread(&_encryptedHeader, HEADER_SZ, 1, fpData_bin) != 1)
|
||||
if (!fpData_bin.ReadBytes(&_encryptedHeader, HEADER_SZ))
|
||||
{
|
||||
PanicAlertT("failed to read header");
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
fclose(fpData_bin);
|
||||
fpData_bin.Close();
|
||||
|
||||
AES_cbc_encrypt((const u8*)&_encryptedHeader, (u8*)&_header, HEADER_SZ, &m_AES_KEY, SD_IV, AES_DECRYPT);
|
||||
_bannerSize = Common::swap32(_header.hdr.BannerSize);
|
||||
@ -129,12 +129,8 @@ void CWiiSaveCrypted::ReadHDR()
|
||||
if (!File::Exists(pathBanner_bin) || AskYesNoT("%s already exists, overwrite?", pathBanner_bin))
|
||||
{
|
||||
INFO_LOG(CONSOLE, "creating file %s", pathBanner_bin);
|
||||
fpBanner_bin = fopen(pathBanner_bin, "wb");
|
||||
if (fpBanner_bin)
|
||||
{
|
||||
fwrite(_header.BNR, _bannerSize, 1, fpBanner_bin);
|
||||
fclose(fpBanner_bin);
|
||||
}
|
||||
File::IOFile fpBanner_bin(pathBanner_bin, "wb");
|
||||
fpBanner_bin.WriteBytes(_header.BNR, _bannerSize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -149,31 +145,24 @@ void CWiiSaveCrypted::WriteHDR()
|
||||
memcpy(_header.hdr.Md5, MD5_BLANKER, 0x10);
|
||||
_header.hdr.Permissions = 0x3C;//0x35;
|
||||
|
||||
fpBanner_bin = fopen(pathBanner_bin, "rb");
|
||||
if (fpBanner_bin)
|
||||
File::IOFile fpBanner_bin(pathBanner_bin, "rb");
|
||||
if (!fpBanner_bin.ReadBytes(_header.BNR, Common::swap32(_header.hdr.BannerSize)))
|
||||
{
|
||||
if (fread(_header.BNR, Common::swap32(_header.hdr.BannerSize), 1, fpBanner_bin) != 1)
|
||||
{
|
||||
PanicAlertT("Failed to read banner.bin");
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
fclose(fpBanner_bin);
|
||||
PanicAlertT("Failed to read banner.bin");
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
md5((u8*)&_header, HEADER_SZ, md5_calc);
|
||||
memcpy(_header.hdr.Md5, md5_calc, 0x10);
|
||||
|
||||
AES_cbc_encrypt((const unsigned char *)&_header, (u8*)&_encryptedHeader, HEADER_SZ, &m_AES_KEY, SD_IV, AES_ENCRYPT);
|
||||
fpData_bin = fopen(pathData_bin, "wb");
|
||||
if (fpData_bin)
|
||||
|
||||
File::IOFile fpData_bin(pathData_bin, "wb");
|
||||
if (!fpData_bin.WriteBytes(&_encryptedHeader, HEADER_SZ))
|
||||
{
|
||||
if (fwrite(&_encryptedHeader, HEADER_SZ, 1, fpData_bin) != 1)
|
||||
{
|
||||
PanicAlertT("Failed to write header for %s", pathData_bin);
|
||||
b_valid = false;
|
||||
}
|
||||
fclose(fpData_bin);
|
||||
PanicAlertT("Failed to write header for %s", pathData_bin);
|
||||
b_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,21 +172,21 @@ void CWiiSaveCrypted::ReadBKHDR()
|
||||
{
|
||||
if (!b_valid) return;
|
||||
|
||||
fpData_bin = fopen(pathData_bin, "rb");
|
||||
File::IOFile fpData_bin(pathData_bin, "rb");
|
||||
if (!fpData_bin)
|
||||
{
|
||||
PanicAlertT("Cannot open %s", pathData_bin);
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
fseeko(fpData_bin, HEADER_SZ, SEEK_SET);
|
||||
if (fread(&bkhdr, BK_SZ, 1, fpData_bin) != 1)
|
||||
fpData_bin.Seek(HEADER_SZ, SEEK_SET);
|
||||
if (!fpData_bin.ReadBytes(&bkhdr, BK_SZ))
|
||||
{
|
||||
PanicAlertT("failed to read bk header");
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
fclose(fpData_bin);
|
||||
fpData_bin.Close();
|
||||
|
||||
if (bkhdr.size != Common::swap32(BK_LISTED_SZ) ||
|
||||
bkhdr.magic != Common::swap32(BK_HDR_MAGIC))
|
||||
@ -215,8 +204,6 @@ void CWiiSaveCrypted::ReadBKHDR()
|
||||
WARN_LOG(CONSOLE, "Size(%x) + cert(%x) does not equal totalsize(%x)", _sizeOfFiles, FULL_CERT_SZ, _totalSize);
|
||||
if (_saveGameTitle != Common::swap64(bkhdr.SaveGameTitle))
|
||||
WARN_LOG(CONSOLE, "encrypted title (%llx) does not match unencrypted title (%llx)", _saveGameTitle, Common::swap64(bkhdr.SaveGameTitle));
|
||||
|
||||
|
||||
}
|
||||
|
||||
void CWiiSaveCrypted::WriteBKHDR()
|
||||
@ -241,15 +228,11 @@ void CWiiSaveCrypted::WriteBKHDR()
|
||||
//
|
||||
memcpy(bkhdr.MACaddress, MAC, 6);
|
||||
|
||||
fpData_bin = fopen(pathData_bin, "ab");
|
||||
if(fpData_bin)
|
||||
File::IOFile fpData_bin(pathData_bin, "ab");
|
||||
if (!fpData_bin.WriteBytes(&bkhdr, BK_SZ))
|
||||
{
|
||||
if (fwrite(&bkhdr, BK_SZ, 1, fpData_bin) != 1)
|
||||
{
|
||||
PanicAlertT("Failed to write bkhdr");
|
||||
b_valid = false;
|
||||
}
|
||||
fclose(fpData_bin);
|
||||
PanicAlertT("Failed to write bkhdr");
|
||||
b_valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,7 +240,7 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
||||
{
|
||||
if (!b_valid) return;
|
||||
|
||||
fpData_bin = fopen(pathData_bin, "rb");
|
||||
File::IOFile fpData_bin(pathData_bin, "rb");
|
||||
if (!fpData_bin)
|
||||
{
|
||||
PanicAlertT("Cannot open %s", pathData_bin);
|
||||
@ -272,19 +255,19 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
||||
|
||||
for(u32 i = 0; i < _numberOfFiles; i++)
|
||||
{
|
||||
fseeko(fpData_bin, lastpos, SEEK_SET);
|
||||
fpData_bin.Seek(lastpos, SEEK_SET);
|
||||
memset(&_tmpFileHDR, 0, FILE_HDR_SZ);
|
||||
memset(IV, 0, 0x10);
|
||||
_fileSize = 0;
|
||||
|
||||
if (fread(&_tmpFileHDR, FILE_HDR_SZ, 1, fpData_bin) != 1)
|
||||
if (!fpData_bin.ReadBytes(&_tmpFileHDR, FILE_HDR_SZ))
|
||||
{
|
||||
PanicAlertT("Failed to write header for file %d", i);
|
||||
b_valid = false;
|
||||
}
|
||||
|
||||
lastpos += FILE_HDR_SZ;
|
||||
if(Common::swap32(_tmpFileHDR.magic) != FILE_HDR_MAGIC)
|
||||
if (Common::swap32(_tmpFileHDR.magic) != FILE_HDR_MAGIC)
|
||||
{
|
||||
PanicAlertT("Bad File Header");
|
||||
break;
|
||||
@ -306,7 +289,7 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
||||
lastpos += ROUND_UP(_fileSize, BLOCK_SZ);
|
||||
_encryptedData = new u8[_fileSize];
|
||||
_data = new u8[_fileSize];
|
||||
if (fread(_encryptedData, _fileSize, 1, fpData_bin) != 1)
|
||||
if (!fpData_bin.ReadBytes(_encryptedData, _fileSize))
|
||||
{
|
||||
PanicAlertT("Failed to read data from file %d", i);
|
||||
b_valid = false;
|
||||
@ -322,19 +305,13 @@ void CWiiSaveCrypted::ImportWiiSaveFiles()
|
||||
{
|
||||
INFO_LOG(CONSOLE, "creating file %s", pathRawSave);
|
||||
|
||||
fpRawSaveFile = fopen(pathRawSave, "wb");
|
||||
if (fpRawSaveFile)
|
||||
{
|
||||
fwrite(_data, _fileSize, 1, fpRawSaveFile);
|
||||
fclose(fpRawSaveFile);
|
||||
}
|
||||
File::IOFile fpRawSaveFile(pathRawSave, "wb");
|
||||
fpRawSaveFile.WriteBytes(_data, _fileSize);
|
||||
}
|
||||
delete []_data;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
fclose(fpData_bin);
|
||||
}
|
||||
|
||||
void CWiiSaveCrypted::ExportWiiSaveFiles()
|
||||
@ -381,11 +358,9 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
||||
}
|
||||
strncpy((char *)tmpFileHDR.name, __name.c_str(), __name.length());
|
||||
|
||||
fpData_bin = fopen(pathData_bin, "ab");
|
||||
if (fpData_bin)
|
||||
{
|
||||
fwrite(&tmpFileHDR, FILE_HDR_SZ, 1, fpData_bin);
|
||||
fclose(fpData_bin);
|
||||
File::IOFile fpData_bin(pathData_bin, "ab");
|
||||
fpData_bin.WriteBytes(&tmpFileHDR, FILE_HDR_SZ);
|
||||
}
|
||||
|
||||
if (tmpFileHDR.type == 1)
|
||||
@ -396,7 +371,7 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
||||
b_valid = false;
|
||||
return;
|
||||
}
|
||||
fpRawSaveFile = fopen(FilesList[i].c_str(), "rb");
|
||||
File::IOFile fpRawSaveFile(FilesList[i], "rb");
|
||||
if (!fpRawSaveFile)
|
||||
{
|
||||
PanicAlertT("%s failed to open", FilesList[i].c_str());
|
||||
@ -405,20 +380,17 @@ void CWiiSaveCrypted::ExportWiiSaveFiles()
|
||||
__data = new u8[_roundedfileSize];
|
||||
__ENCdata = new u8[_roundedfileSize];
|
||||
memset(__data, 0, _roundedfileSize);
|
||||
if (fread(__data, _fileSize, 1, fpRawSaveFile) != 1)
|
||||
if (!fpRawSaveFile.ReadBytes(__data, _fileSize))
|
||||
{
|
||||
PanicAlertT("failed to read data from file: %s", FilesList[i].c_str());
|
||||
b_valid = false;
|
||||
}
|
||||
fclose(fpRawSaveFile);
|
||||
|
||||
AES_cbc_encrypt((const u8*)__data, __ENCdata, _roundedfileSize, &m_AES_KEY, tmpFileHDR.IV, AES_ENCRYPT);
|
||||
fpData_bin = fopen(pathData_bin, "ab");
|
||||
if (fpData_bin)
|
||||
{
|
||||
fwrite(__ENCdata, _roundedfileSize, 1, fpData_bin);
|
||||
fclose(fpData_bin);
|
||||
}
|
||||
|
||||
File::IOFile fpData_bin(pathData_bin, "ab");
|
||||
fpData_bin.WriteBytes(__ENCdata, _roundedfileSize);
|
||||
|
||||
delete [] __data;
|
||||
delete [] __ENCdata;
|
||||
|
||||
@ -466,7 +438,7 @@ void CWiiSaveCrypted::do_sig()
|
||||
|
||||
data_size = Common::swap32(bkhdr.sizeOfFiles) + 0x80;
|
||||
|
||||
fpData_bin = fopen(pathData_bin, "rb");
|
||||
File::IOFile fpData_bin(pathData_bin, "rb");
|
||||
if (!fpData_bin)
|
||||
{
|
||||
b_valid = false;
|
||||
@ -474,14 +446,15 @@ void CWiiSaveCrypted::do_sig()
|
||||
}
|
||||
data = new u8[data_size];
|
||||
|
||||
fseeko(fpData_bin, 0xf0c0, SEEK_SET);
|
||||
if (fread(data, data_size, 1, fpData_bin) != 1)
|
||||
fpData_bin.Seek(0xf0c0, SEEK_SET);
|
||||
if (!fpData_bin.ReadBytes(data, data_size))
|
||||
PanicAlert("read data for sig check");
|
||||
|
||||
sha1(data, data_size, hash);
|
||||
sha1(hash, 20, hash);
|
||||
fclose(fpData_bin);
|
||||
delete []data;
|
||||
fpData_bin = fopen(pathData_bin, "ab");
|
||||
|
||||
fpData_bin.Open(pathData_bin, "ab");
|
||||
if (!fpData_bin)
|
||||
{
|
||||
b_valid = false;
|
||||
@ -490,15 +463,12 @@ void CWiiSaveCrypted::do_sig()
|
||||
generate_ecdsa(sig, sig + 30, ap_priv, hash);
|
||||
*(u32*)(sig + 60) = Common::swap32(0x2f536969);
|
||||
|
||||
|
||||
|
||||
if (fwrite(sig, sizeof sig, 1, fpData_bin) != 1)
|
||||
if (!fpData_bin.WriteArray(sig, sizeof(sig)))
|
||||
PanicAlert("write sig");
|
||||
if (fwrite(ng_cert, sizeof ng_cert, 1, fpData_bin) != 1)
|
||||
if (!fpData_bin.WriteArray(ng_cert, sizeof(ng_cert)))
|
||||
PanicAlert("write NG cert");
|
||||
if (fwrite(ap_cert, sizeof ap_cert, 1, fpData_bin) != 1)
|
||||
if (!fpData_bin.WriteArray(ap_cert, sizeof(ap_cert)))
|
||||
PanicAlert("write AP cert");
|
||||
fclose(fpData_bin);
|
||||
}
|
||||
|
||||
|
||||
|
@ -48,11 +48,7 @@ public:
|
||||
private:
|
||||
AES_KEY m_AES_KEY;
|
||||
u8 SD_IV[0x10];
|
||||
std::vector<std::string> FilesList;
|
||||
|
||||
FILE *fpData_bin,
|
||||
*fpBanner_bin,
|
||||
*fpRawSaveFile;
|
||||
std::vector<std::string> FilesList;
|
||||
|
||||
char pathData_bin[2048],
|
||||
pathSavedir[2048],
|
||||
|
Reference in New Issue
Block a user