mirror of
https://github.com/PrimeDecomp/prime.git
synced 2025-07-18 22:25:52 +00:00
823 lines
22 KiB
C++
823 lines
22 KiB
C++
#include "MetroidPrime/CMemoryCardDriver.hpp"
|
|
|
|
#include "MetroidPrime/CMain.hpp"
|
|
|
|
#include "Kyoto/Streams/CMemoryInStream.hpp"
|
|
|
|
#include "dolphin/os.h"
|
|
#include "stdio.h"
|
|
|
|
static bool lbl_805A9118;
|
|
static const char* const skSaveFileNames[2] = {"MetroidPrime A", "MetroidPrime B"};
|
|
|
|
bool CMemoryCardDriver::IsCardBusy(EState v) { return v >= kS_CardMount && v <= kS_CardFormat; }
|
|
|
|
bool CMemoryCardDriver::IsCardWriting(EState v) {
|
|
if (v < kS_CardProbe)
|
|
return false;
|
|
if (v == kS_CardCheck)
|
|
return false;
|
|
if (v == kS_FileRead)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
CMemoryCardDriver::CMemoryCardDriver(EMemoryCardPort cardPort, CAssetId saveBanner,
|
|
CAssetId saveIcon0, CAssetId saveIcon1, bool importPersistent)
|
|
: x0_cardPort(cardPort)
|
|
, x4_saveBanner(saveBanner)
|
|
, x8_saveIcon0(saveIcon0)
|
|
, xc_saveIcon1(saveIcon1)
|
|
, x10_state(kS_Initial)
|
|
, x14_error(kE_OK)
|
|
, x18_cardFreeBytes(0)
|
|
, x1c_cardFreeFiles(0)
|
|
, x20_fileTime(0)
|
|
, x28_cardSerial(0)
|
|
, x30_systemData(0)
|
|
, xe4_fileSlots(nullptr)
|
|
, x100_mcFileInfos()
|
|
, x194_fileIdx(-1)
|
|
, x198_fileInfo(nullptr)
|
|
, x19c_(false)
|
|
, x19d_importPersistent(importPersistent) {
|
|
lbl_805A9118 = true;
|
|
x100_mcFileInfos.push_back(rstl::pair< EFileState, SMemoryCardFileInfo >(
|
|
kFS_Unknown, SMemoryCardFileInfo(x0_cardPort, rstl::string_l("MetroidPrime A"))));
|
|
x100_mcFileInfos.push_back(rstl::pair< EFileState, SMemoryCardFileInfo >(
|
|
kFS_Unknown, SMemoryCardFileInfo(x0_cardPort, rstl::string_l("MetroidPrime B"))));
|
|
}
|
|
|
|
void CMemoryCardDriver::ClearFileInfo() { x198_fileInfo = nullptr; }
|
|
|
|
CMemoryCardDriver::~CMemoryCardDriver() {
|
|
CMemoryCardSys::UnmountCard(x0_cardPort);
|
|
lbl_805A9118 = false;
|
|
gpMain->SetCardBusy(false);
|
|
}
|
|
|
|
void CMemoryCardDriver::Update() {
|
|
ProbeResults result = CMemoryCardSys::IsMemoryCardInserted(x0_cardPort);
|
|
|
|
if (result.x0_error == kCR_NOCARD) {
|
|
if (x10_state != kS_NoCard)
|
|
NoCardFound();
|
|
gpMain->SetCardBusy(false);
|
|
return;
|
|
}
|
|
|
|
if (x10_state == kS_CardProbe) {
|
|
UpdateCardProbe();
|
|
gpMain->SetCardBusy(false);
|
|
return;
|
|
}
|
|
|
|
ECardResult resultCode = CMemoryCardSys::GetResultCode(x0_cardPort);
|
|
bool cardBusy = false;
|
|
|
|
if (IsCardBusy(x10_state)) {
|
|
cardBusy = true;
|
|
|
|
switch (x10_state) {
|
|
case kS_CardProbe:
|
|
break;
|
|
case kS_CardMount:
|
|
UpdateMountCard(resultCode);
|
|
break;
|
|
case kS_CardCheck:
|
|
UpdateCardCheck(resultCode);
|
|
break;
|
|
case kS_FileDeleteBad:
|
|
UpdateFileDeleteBad(resultCode);
|
|
break;
|
|
case kS_FileRead:
|
|
UpdateFileRead(resultCode);
|
|
break;
|
|
case kS_FileDeleteAlt:
|
|
UpdateFileDeleteAlt(resultCode);
|
|
break;
|
|
case kS_FileCreate:
|
|
UpdateFileCreate(resultCode);
|
|
break;
|
|
case kS_FileWrite:
|
|
UpdateFileWrite(resultCode);
|
|
break;
|
|
case kS_FileCreateTransactional:
|
|
UpdateFileCreateTransactional(resultCode);
|
|
break;
|
|
case kS_FileWriteTransactional:
|
|
UpdateFileWriteTransactional(resultCode);
|
|
break;
|
|
case kS_FileAltDeleteTransactional:
|
|
UpdateFileAltDeleteTransactional(resultCode);
|
|
break;
|
|
case kS_FileRenameBtoA:
|
|
UpdateFileRenameBtoA(resultCode);
|
|
break;
|
|
case kS_CardFormat:
|
|
UpdateCardFormat(resultCode);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
gpMain->SetCardBusy(cardBusy);
|
|
}
|
|
|
|
void CMemoryCardDriver::HandleCardError(ECardResult result, EState state) {
|
|
switch (result) {
|
|
case kCR_BUSY:
|
|
break;
|
|
case kCR_WRONGDEVICE:
|
|
x10_state = state;
|
|
x14_error = kE_CardWrongDevice;
|
|
break;
|
|
case kCR_NOCARD:
|
|
NoCardFound();
|
|
break;
|
|
case kCR_IOERROR:
|
|
x10_state = state;
|
|
x14_error = kE_CardIOError;
|
|
break;
|
|
case kCR_ENCODING:
|
|
x10_state = state;
|
|
x14_error = kE_CardWrongCharacterSet;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateMountCard(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_CardMountDone;
|
|
StartCardCheck();
|
|
} else if (result == kCR_BROKEN) {
|
|
x10_state = kS_CardMountDone;
|
|
x14_error = kE_CardBroken;
|
|
StartCardCheck();
|
|
} else {
|
|
HandleCardError(result, kS_CardMountFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateCardCheck(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_CardCheckDone;
|
|
if (!GetCardFreeBytes())
|
|
return;
|
|
if (CMemoryCardSys::GetSerialNo(x0_cardPort, x28_cardSerial) == kCR_READY)
|
|
return;
|
|
NoCardFound();
|
|
|
|
} else if (result == kCR_BROKEN) {
|
|
x10_state = kS_CardCheckFailed;
|
|
x14_error = kE_CardBroken;
|
|
|
|
} else {
|
|
HandleCardError(result, kS_CardCheckFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileRead(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
ECardResult readRes = x100_mcFileInfos[x194_fileIdx].second.TryFileRead();
|
|
if (x100_mcFileInfos[x194_fileIdx].second.Close() != kCR_READY) {
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
|
|
int altFileIdx;
|
|
if (x194_fileIdx == 0) {
|
|
altFileIdx = 1;
|
|
} else {
|
|
altFileIdx = 0;
|
|
}
|
|
if (readRes == kCR_READY) {
|
|
x10_state = kS_Ready;
|
|
ReadFinished();
|
|
EFileState fileSt = x100_mcFileInfos[altFileIdx].first;
|
|
if (fileSt != kFS_NoFile) {
|
|
StartFileDeleteAlt();
|
|
} else {
|
|
CheckCardCapacity();
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (readRes == kCR_CRC_MISMATCH) {
|
|
x100_mcFileInfos[x194_fileIdx].first = kFS_BadFile;
|
|
if (x100_mcFileInfos[altFileIdx].first == kFS_File) {
|
|
x10_state = kS_CardCheckDone;
|
|
IndexFiles();
|
|
} else {
|
|
x10_state = kS_FileBad;
|
|
x14_error = kE_FileCorrupted;
|
|
}
|
|
}
|
|
} else {
|
|
HandleCardError(result, kS_FileBad);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileDeleteAlt(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_Ready;
|
|
if (GetCardFreeBytes()) {
|
|
CheckCardCapacity();
|
|
}
|
|
} else {
|
|
HandleCardError(result, kS_FileDeleteAltFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileDeleteBad(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x100_mcFileInfos[x194_fileIdx].first = kFS_NoFile;
|
|
if (x100_mcFileInfos[x194_fileIdx ? 0 : 1].first == kFS_BadFile) {
|
|
x10_state = kS_FileBad;
|
|
StartFileDeleteBad();
|
|
} else {
|
|
x10_state = kS_CardCheckDone;
|
|
if (!GetCardFreeBytes()) {
|
|
return;
|
|
}
|
|
IndexFiles();
|
|
}
|
|
} else {
|
|
HandleCardError(result, kS_FileDeleteBadFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileCreate(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_FileCreateDone;
|
|
StartFileWrite();
|
|
} else {
|
|
HandleCardError(result, kS_FileCreateFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileWrite(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
ECardResult xferResult = x198_fileInfo->PumpCardTransfer();
|
|
if (xferResult == kCR_READY) {
|
|
x10_state = kS_Ready;
|
|
if (x198_fileInfo->CloseFile() != kCR_READY) {
|
|
NoCardFound();
|
|
}
|
|
return;
|
|
}
|
|
if (xferResult == kCR_BUSY) {
|
|
return;
|
|
}
|
|
if (xferResult == kCR_IOERROR) {
|
|
x10_state = kS_FileWriteFailed;
|
|
x14_error = kE_CardIOError;
|
|
return;
|
|
}
|
|
NoCardFound();
|
|
} else {
|
|
HandleCardError(result, kS_FileWriteFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileCreateTransactional(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_FileCreateTransactionalDone;
|
|
StartFileWriteTransactional();
|
|
} else {
|
|
HandleCardError(result, kS_FileCreateTransactionalFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileWriteTransactional(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
ECardResult xferResult = x198_fileInfo->PumpCardTransfer();
|
|
if (xferResult == kCR_READY) {
|
|
x10_state = kS_FileWriteTransactionalDone;
|
|
if (x198_fileInfo->CloseFile() != kCR_READY) {
|
|
NoCardFound();
|
|
} else {
|
|
StartFileDeleteAltTransactional();
|
|
}
|
|
return;
|
|
}
|
|
if (xferResult == kCR_BUSY) {
|
|
return;
|
|
}
|
|
if (xferResult == kCR_IOERROR) {
|
|
x10_state = kS_FileWriteTransactionalFailed;
|
|
x14_error = kE_CardIOError;
|
|
return;
|
|
}
|
|
NoCardFound();
|
|
} else {
|
|
HandleCardError(result, kS_FileWriteTransactionalFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileRenameBtoA(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_DriverClosed;
|
|
WriteBackupBuf();
|
|
} else {
|
|
HandleCardError(result, kS_FileRenameBtoAFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileRenameBtoA() {
|
|
if (x194_fileIdx == 1) {
|
|
/* Rename B file to A file (ideally the card is always left with 'A' only) */
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileRenameBtoA;
|
|
int bidx = x194_fileIdx == 0 ? 1 : 0;
|
|
ECardResult result =
|
|
CMemoryCardSys::Rename(x0_cardPort, rstl::string_l(skSaveFileNames[x194_fileIdx]),
|
|
rstl::string_l(skSaveFileNames[bidx]));
|
|
if (result != kCR_READY) {
|
|
UpdateFileRenameBtoA(result);
|
|
}
|
|
} else {
|
|
x10_state = kS_DriverClosed;
|
|
WriteBackupBuf();
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::WriteBackupBuf() {
|
|
gpGameState->WriteBackupBuf();
|
|
gpGameState->SetCardSerial(x28_cardSerial);
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateFileAltDeleteTransactional(ECardResult result) {
|
|
if (result == kCR_READY) {
|
|
x10_state = kS_FileAltDeleteTransactionalDone;
|
|
if (GetCardFreeBytes())
|
|
StartFileRenameBtoA();
|
|
} else {
|
|
HandleCardError(result, kS_FileAltDeleteTransactionalFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateCardFormat(ECardResult result) {
|
|
if (result == kCR_READY)
|
|
x10_state = kS_CardFormatted;
|
|
else if (result == kCR_BROKEN) {
|
|
x10_state = kS_CardFormatFailed;
|
|
x14_error = kE_CardIOError;
|
|
} else {
|
|
HandleCardError(result, kS_CardFormatFailed);
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::StartCardProbe() {
|
|
x10_state = kS_CardProbe;
|
|
x14_error = kE_OK;
|
|
UpdateCardProbe();
|
|
}
|
|
|
|
void CMemoryCardDriver::UpdateCardProbe() {
|
|
ProbeResults result = CMemoryCardSys::IsMemoryCardInserted(x0_cardPort);
|
|
ECardResult error = result.x0_error;
|
|
|
|
if (error == kCR_READY && result.x8_sectorSize != 0x2000) {
|
|
x10_state = kS_CardProbeFailed;
|
|
x14_error = kE_CardNon8KSectors;
|
|
} else if (error != kCR_BUSY) {
|
|
if (error == kCR_WRONGDEVICE) {
|
|
x10_state = kS_CardProbeFailed;
|
|
x14_error = kE_CardWrongDevice;
|
|
} else if (error != kCR_READY) {
|
|
NoCardFound();
|
|
} else {
|
|
x10_state = kS_CardProbeDone;
|
|
StartMountCard();
|
|
}
|
|
}
|
|
|
|
// switch (result.x0_error) {
|
|
// case kCR_READY:
|
|
// if (result.x8_sectorSize != 0x2000) {
|
|
// x10_state = kS_CardProbeFailed;
|
|
// x14_error = kE_CardNon8KSectors;
|
|
// } else {
|
|
// x10_state = kS_CardProbeDone;
|
|
// StartMountCard();
|
|
// }
|
|
// break;
|
|
// case kCR_BUSY:
|
|
// break;
|
|
// case kCR_WRONGDEVICE:
|
|
// x10_state = kS_CardProbeFailed;
|
|
// x14_error = kE_CardWrongDevice;
|
|
// break;
|
|
// default:
|
|
// NoCardFound();
|
|
// break;
|
|
// }
|
|
}
|
|
|
|
void CMemoryCardDriver::StartMountCard() {
|
|
x10_state = kS_CardMount;
|
|
x14_error = kE_OK;
|
|
ECardResult result = CMemoryCardSys::MountCard(x0_cardPort);
|
|
if (result != kCR_READY)
|
|
UpdateMountCard(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartCardCheck() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_CardCheck;
|
|
ECardResult result = CMemoryCardSys::CheckCard(x0_cardPort);
|
|
if (result != kCR_READY)
|
|
UpdateCardCheck(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::ClearError() { x14_error = kE_OK; }
|
|
|
|
void CMemoryCardDriver::CheckCardCapacity() {
|
|
if (x18_cardFreeBytes >= 0x2000 && x1c_cardFreeFiles >= 1) {
|
|
return;
|
|
}
|
|
x14_error = kE_CardStillFull;
|
|
}
|
|
|
|
void CMemoryCardDriver::NoCardFound() {
|
|
x10_state = kS_NoCard;
|
|
gpMain->SetCardBusy(false);
|
|
}
|
|
|
|
void CMemoryCardDriver::IndexFiles() {
|
|
x14_error = kE_OK;
|
|
for (int i = 0; i < x100_mcFileInfos.capacity(); ++i) {
|
|
rstl::pair< EFileState, SMemoryCardFileInfo >& info = x100_mcFileInfos[i];
|
|
if (info.first == kFS_Unknown) {
|
|
ECardResult result = info.second.Open();
|
|
if (result == kCR_NOFILE) {
|
|
info.first = kFS_NoFile;
|
|
continue;
|
|
} else if (result == kCR_READY) {
|
|
CardStat stat;
|
|
if (CMemoryCardSys::GetStatus(x0_cardPort, info.second.GetFileNo(), stat) == kCR_READY) {
|
|
int comment = stat.GetCommentAddr();
|
|
if (comment == -1)
|
|
info.first = kFS_BadFile;
|
|
else
|
|
info.first = kFS_File;
|
|
} else {
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
if (info.second.Close() == kCR_NOCARD) {
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
} else {
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (x100_mcFileInfos[0].first == kFS_File) {
|
|
if (x100_mcFileInfos[1].first == kFS_File) {
|
|
CardStat stat;
|
|
if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[0].second.GetFileNo(), stat) ==
|
|
kCR_READY) {
|
|
u32 timeA = stat.GetTime();
|
|
if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[1].second.GetFileNo(), stat) ==
|
|
kCR_READY) {
|
|
u32 timeB = stat.GetTime();
|
|
if (timeA > timeB)
|
|
x194_fileIdx = 0;
|
|
else
|
|
x194_fileIdx = 1;
|
|
StartFileRead();
|
|
return;
|
|
}
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
x194_fileIdx = 0;
|
|
StartFileRead();
|
|
return;
|
|
}
|
|
|
|
if (x100_mcFileInfos[1].first == kFS_File) {
|
|
x194_fileIdx = 1;
|
|
StartFileRead();
|
|
return;
|
|
}
|
|
|
|
if (x100_mcFileInfos[0].first == kFS_BadFile || x100_mcFileInfos[1].first == kFS_BadFile) {
|
|
x14_error = kE_FileCorrupted;
|
|
x10_state = kS_FileBad;
|
|
} else {
|
|
x14_error = kE_FileMissing;
|
|
x10_state = kS_FileBad;
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileDeleteBad() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileDeleteBad;
|
|
|
|
for (int idx = 0; idx < x100_mcFileInfos.capacity(); ++idx) {
|
|
rstl::pair< EFileState, SMemoryCardFileInfo >& info = x100_mcFileInfos[idx];
|
|
if (info.first == kFS_BadFile) {
|
|
x194_fileIdx = idx;
|
|
ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, info.second.GetFileNo());
|
|
if (result != kCR_READY) {
|
|
UpdateFileDeleteBad(result);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileDeleteAlt() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileDeleteAlt;
|
|
|
|
int altFileIdx;
|
|
if (x194_fileIdx == 0) {
|
|
altFileIdx = 1;
|
|
} else {
|
|
altFileIdx = 0;
|
|
}
|
|
|
|
SMemoryCardFileInfo& fileInfo = x100_mcFileInfos[altFileIdx].second;
|
|
ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, fileInfo.GetFileNo());
|
|
if (result != kCR_READY)
|
|
UpdateFileDeleteAlt(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileRead() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileRead;
|
|
ECardResult result = x100_mcFileInfos[x194_fileIdx].second.Open();
|
|
if (result != kCR_READY) {
|
|
UpdateFileRead(result);
|
|
return;
|
|
}
|
|
|
|
result = x100_mcFileInfos[x194_fileIdx].second.StartRead();
|
|
if (result != kCR_READY)
|
|
UpdateFileRead(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileCreate() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileCreate;
|
|
if (x18_cardFreeBytes < 0x4000 || x1c_cardFreeFiles < 2) {
|
|
x10_state = kS_FileCreateFailed;
|
|
x14_error = kE_CardFull;
|
|
return;
|
|
}
|
|
|
|
x194_fileIdx = 0;
|
|
x198_fileInfo = new CCardFileInfo(x0_cardPort, rstl::string_l(skSaveFileNames[x194_fileIdx]));
|
|
InitializeFileInfo();
|
|
ECardResult result = x198_fileInfo->CreateFile();
|
|
if (result != kCR_READY)
|
|
UpdateFileCreate(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileWrite() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileWrite;
|
|
ECardResult result = x198_fileInfo->WriteFile();
|
|
if (result != kCR_READY)
|
|
UpdateFileWrite(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileCreateTransactional() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileCreateTransactional;
|
|
ClearFileInfo();
|
|
if (x18_cardFreeBytes < 8192 || x1c_cardFreeFiles < 1) {
|
|
x10_state = kS_FileCreateTransactionalFailed;
|
|
x14_error = kE_CardFull;
|
|
return;
|
|
}
|
|
|
|
int altFileIdx;
|
|
if (x194_fileIdx == 0) {
|
|
altFileIdx = 1;
|
|
} else {
|
|
altFileIdx = 0;
|
|
}
|
|
|
|
x194_fileIdx = altFileIdx;
|
|
x198_fileInfo = new CCardFileInfo(x0_cardPort, rstl::string_l(skSaveFileNames[x194_fileIdx]));
|
|
InitializeFileInfo();
|
|
ECardResult result = x198_fileInfo->CreateFile();
|
|
if (result != kCR_READY)
|
|
UpdateFileCreateTransactional(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileWriteTransactional() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileWriteTransactional;
|
|
ECardResult result = x198_fileInfo->WriteFile();
|
|
if (result != kCR_READY)
|
|
UpdateFileWriteTransactional(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartFileDeleteAltTransactional() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_FileAltDeleteTransactional;
|
|
int bidx = x194_fileIdx == 0 ? 1 : 0;
|
|
ECardResult result =
|
|
CMemoryCardSys::DeleteFile(x0_cardPort, rstl::string_l(skSaveFileNames[bidx]));
|
|
if (result != kCR_READY)
|
|
UpdateFileAltDeleteTransactional(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::StartCardFormat() {
|
|
x14_error = kE_OK;
|
|
x10_state = kS_CardFormat;
|
|
ECardResult result = CMemoryCardSys::FormatCard(x0_cardPort);
|
|
if (result != kCR_READY)
|
|
UpdateCardFormat(result);
|
|
}
|
|
|
|
void CMemoryCardDriver::InitializeFileInfo() {
|
|
CCardFileInfo& fileInfo = *x198_fileInfo;
|
|
ExportPersistentOptions();
|
|
|
|
const char nameConstant[33] = "Metroid Prime ";
|
|
|
|
OSCalendarTime time;
|
|
OSTicksToCalendarTime(OSGetTime(), &time);
|
|
|
|
char nameBuffer[36];
|
|
|
|
sprintf(nameBuffer, "%02d.%02d.%02d %02d:%02d", time.x10_mon + 1, time.xc_mday,
|
|
time.x14_year % 100, time.x8_hour, time.x4_min);
|
|
|
|
fileInfo.SetComment(rstl::string_l(nameConstant) + nameBuffer);
|
|
fileInfo.LockBannerToken(x4_saveBanner, *gpSimplePool);
|
|
fileInfo.LockIconToken(x8_saveIcon0, 2, *gpSimplePool);
|
|
|
|
// CMemoryStreamOut w(fileInfo.BeginMemoryOut(3004));
|
|
|
|
rstl::vector< u8 >& saveBuffer = fileInfo.SaveBuffer();
|
|
saveBuffer.resize(3004, '\x00');
|
|
CMemoryStreamOut w(saveBuffer.data(), 3004);
|
|
|
|
SSaveHeader header(0);
|
|
for (int i = 0; i < xe4_fileSlots.capacity(); ++i) {
|
|
header.x4_savePresent[i] = !xe4_fileSlots[i].null();
|
|
}
|
|
w.Put(header);
|
|
|
|
w.Put(x30_systemData.data(), x30_systemData.capacity());
|
|
|
|
for (rstl::reserved_vector< rstl::auto_ptr< SGameFileSlot >, 3 >::iterator it =
|
|
xe4_fileSlots.begin();
|
|
it != xe4_fileSlots.end(); ++it) {
|
|
if (!it->null()) {
|
|
w.Put(**it);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::ReadFinished() {
|
|
SMemoryCardFileInfo& fileInfo = x100_mcFileInfos[x194_fileIdx].second;
|
|
CardStat stat;
|
|
if (CMemoryCardSys::GetStatus(fileInfo.x0_fileInfo.slot, fileInfo.GetFileNo(), stat) !=
|
|
kCR_READY) {
|
|
NoCardFound();
|
|
return;
|
|
}
|
|
|
|
x20_fileTime = stat.GetTime();
|
|
|
|
CMemoryInStream r(fileInfo.x34_saveData.data(), 3004);
|
|
SSaveHeader header(r);
|
|
r.Get(x30_systemData.data(), x30_systemData.capacity());
|
|
|
|
for (int i = 0; i < xe4_fileSlots.capacity(); ++i) {
|
|
if (header.x4_savePresent[i]) {
|
|
xe4_fileSlots[i] = new SGameFileSlot(r);
|
|
} else {
|
|
xe4_fileSlots[i] = nullptr;
|
|
}
|
|
}
|
|
|
|
if (x19d_importPersistent) {
|
|
ImportPersistentOptions();
|
|
}
|
|
}
|
|
|
|
void CMemoryCardDriver::EraseFileSlot(int saveIdx) { xe4_fileSlots[saveIdx] = nullptr; }
|
|
|
|
void CMemoryCardDriver::BuildNewFileSlot(int saveIdx) {
|
|
bool fusionBackup = gpGameState->SystemOptions().GetHasFusion();
|
|
gpGameState->SetFileIdx(saveIdx);
|
|
|
|
rstl::auto_ptr< SGameFileSlot >& slot = xe4_fileSlots[saveIdx];
|
|
if (slot.null())
|
|
slot = new SGameFileSlot();
|
|
|
|
slot->LoadGameState(saveIdx);
|
|
|
|
{
|
|
CMemoryInStream r(x30_systemData.data(), x30_systemData.capacity());
|
|
gpGameState->ReadSystemOptions(r);
|
|
}
|
|
|
|
ImportPersistentOptions();
|
|
gpGameState->SetCardSerial(x28_cardSerial);
|
|
gpGameState->SystemOptions().SetHasFusion(fusionBackup);
|
|
}
|
|
|
|
void CMemoryCardDriver::BuildExistingFileSlot(int saveIdx) {
|
|
gpGameState->SetFileIdx(saveIdx);
|
|
|
|
rstl::auto_ptr< SGameFileSlot >& slot = xe4_fileSlots[saveIdx];
|
|
if (slot.null())
|
|
slot = new SGameFileSlot();
|
|
else
|
|
slot->InitializeFromGameState();
|
|
|
|
CMemoryStreamOut w(x30_systemData.data(), x30_systemData.capacity());
|
|
gpGameState->WriteSystemOptions(w);
|
|
}
|
|
|
|
void CMemoryCardDriver::ImportPersistentOptions() {
|
|
CMemoryInStream r(x30_systemData.data(), x30_systemData.capacity());
|
|
CSystemOptions opts(r);
|
|
gpGameState->ImportPersistentOptions(opts);
|
|
}
|
|
|
|
void CMemoryCardDriver::ExportPersistentOptions() {
|
|
u8* data = x30_systemData.data();
|
|
CMemoryInStream r(data, x30_systemData.capacity());
|
|
CSystemOptions opts(r);
|
|
gpGameState->ExportPersistentOptions(opts);
|
|
|
|
CMemoryStreamOut w(data, x30_systemData.capacity());
|
|
w.Put(opts);
|
|
}
|
|
|
|
SSaveHeader::SSaveHeader(int i) : x0_version(i) {}
|
|
|
|
SSaveHeader::SSaveHeader(CMemoryInStream& in) {
|
|
x0_version = in.ReadLong();
|
|
for (int i = 0; i < 3; ++i) {
|
|
x4_savePresent[i] = in.ReadBool();
|
|
}
|
|
}
|
|
|
|
void SSaveHeader::PutTo(COutputStream& out) const {
|
|
out.WriteLong(x0_version);
|
|
for (int i = 0; i < 3; ++i) {
|
|
out.Put(x4_savePresent[i]);
|
|
}
|
|
}
|
|
|
|
SGameFileSlot::SGameFileSlot() : x0_saveBuffer('\x00') { InitializeFromGameState(); }
|
|
|
|
SGameFileSlot::SGameFileSlot(CMemoryInStream& in) : x0_saveBuffer('\x00') {
|
|
in.Get(x0_saveBuffer.data(), x0_saveBuffer.capacity());
|
|
x944_fileInfo = gpGameState->LoadGameFileState(x0_saveBuffer.data());
|
|
}
|
|
|
|
void SGameFileSlot::PutTo(COutputStream& w) const {
|
|
w.Put(x0_saveBuffer.data(), x0_saveBuffer.capacity());
|
|
}
|
|
|
|
void SGameFileSlot::InitializeFromGameState() {
|
|
{
|
|
CMemoryStreamOut w(x0_saveBuffer.data(), x0_saveBuffer.capacity());
|
|
w.Put(*gpGameState);
|
|
}
|
|
x944_fileInfo = CGameState::LoadGameFileState(x0_saveBuffer.data());
|
|
}
|
|
|
|
void SGameFileSlot::LoadGameState(int idx) {
|
|
CMemoryInStream r(x0_saveBuffer.data(), x0_saveBuffer.capacity());
|
|
gpMain->StreamNewGameState(r, idx);
|
|
}
|
|
|
|
const CGameState::GameFileStateInfo* CMemoryCardDriver::GetGameFileStateInfo(int saveIdx) {
|
|
if (xe4_fileSlots[saveIdx].null()) {
|
|
return nullptr;
|
|
}
|
|
return &xe4_fileSlots[saveIdx]->x944_fileInfo;
|
|
};
|
|
|
|
bool CMemoryCardDriver::GetCardFreeBytes() {
|
|
if (CMemoryCardSys::GetNumFreeBytes(x0_cardPort, x18_cardFreeBytes, x1c_cardFreeFiles) !=
|
|
kCR_READY) {
|
|
NoCardFound();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|