metaforce/Runtime/MP1/CMemoryCardDriver.cpp

943 lines
26 KiB
C++
Raw Normal View History

#include "CMemoryCardDriver.hpp"
#include "MP1.hpp"
2016-12-20 21:51:50 +00:00
#include "CCRC32.hpp"
namespace urde
{
namespace MP1
{
2016-12-23 06:41:39 +00:00
static const char* SaveFileNames[] =
{
"MetroidPrime A",
"MetroidPrime B"
};
2016-12-28 08:51:28 +00:00
using ECardResult = kabufuda::ECardResult;
using ECardSlot = kabufuda::ECardSlot;
2016-12-23 06:41:39 +00:00
ECardResult CMemoryCardDriver::SFileInfo::Open()
{
2016-12-28 08:51:28 +00:00
return CMemoryCardSys::OpenFile(GetFileCardPort(), x14_name.c_str(), x0_fileInfo);
2016-12-23 06:41:39 +00:00
}
2016-12-20 21:51:50 +00:00
ECardResult CMemoryCardDriver::SFileInfo::Close()
{
2016-12-28 08:51:28 +00:00
return CMemoryCardSys::CloseFile(x0_fileInfo);
2016-12-20 21:51:50 +00:00
}
2016-12-28 08:51:28 +00:00
ECardResult CMemoryCardDriver::SFileInfo::StartRead()
2016-12-23 06:41:39 +00:00
{
2016-12-28 08:51:28 +00:00
CMemoryCardSys::CardStat stat = {};
2017-01-24 07:41:33 +00:00
ECardResult result = CMemoryCardSys::GetStatus(x0_fileInfo.slot, x0_fileInfo.getFileNo(), stat);
2016-12-24 05:23:50 +00:00
if (result != ECardResult::READY)
2016-12-23 06:41:39 +00:00
return result;
u32 length = stat.GetFileLength();
x34_saveData.clear();
x24_saveFileData.resize(length);
2016-12-28 08:51:28 +00:00
return CMemoryCardSys::ReadFile(x0_fileInfo, x24_saveFileData.data(), length, 0);
2016-12-23 06:41:39 +00:00
}
2016-12-20 21:51:50 +00:00
ECardResult CMemoryCardDriver::SFileInfo::TryFileRead()
{
ECardResult res = CMemoryCardSys::GetResultCode(GetFileCardPort());
2016-12-24 05:23:50 +00:00
if (res == ECardResult::READY)
2016-12-20 21:51:50 +00:00
res = FileRead();
return res;
}
ECardResult CMemoryCardDriver::SFileInfo::FileRead()
{
x34_saveData.clear();
u32 existingCrc = hecl::SBig(*reinterpret_cast<u32*>(x24_saveFileData.data()));
u32 newCrc = CCRC32::Calculate(x24_saveFileData.data() + 4, x24_saveFileData.size() - 4);
if (existingCrc == newCrc)
{
u32 saveDataOff;
ECardResult result = GetSaveDataOffset(saveDataOff);
2016-12-24 05:23:50 +00:00
if (result != ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
x24_saveFileData.clear();
return result;
}
u32 saveSize = x24_saveFileData.size() - saveDataOff;
x34_saveData.resize(saveSize);
memmove(x34_saveData.data(), x24_saveFileData.data() + saveDataOff, saveSize);
x24_saveFileData.clear();
2016-12-24 05:23:50 +00:00
return ECardResult::READY;
2016-12-20 21:51:50 +00:00
}
else
{
x24_saveFileData.clear();
2016-12-24 05:23:50 +00:00
return ECardResult::CRC_MISMATCH;
2016-12-20 21:51:50 +00:00
}
}
ECardResult CMemoryCardDriver::SFileInfo::GetSaveDataOffset(u32& offOut)
{
2016-12-28 08:51:28 +00:00
CMemoryCardSys::CardStat stat = {};
2017-01-24 07:41:33 +00:00
ECardResult result = CMemoryCardSys::GetStatus(x0_fileInfo.slot, x0_fileInfo.getFileNo(), stat);
2016-12-24 05:23:50 +00:00
if (result != ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
offOut = -1;
return result;
}
offOut = 4;
offOut += 64;
switch (stat.GetBannerFormat())
{
2016-12-28 08:51:28 +00:00
case kabufuda::EImageFormat::C8:
2016-12-20 21:51:50 +00:00
offOut += 3584;
break;
2016-12-28 08:51:28 +00:00
case kabufuda::EImageFormat::RGB5A3:
2016-12-20 21:51:50 +00:00
offOut += 6144;
break;
default: break;
}
int idx = 0;
bool paletteIcon = false;
2016-12-28 08:51:28 +00:00
for (kabufuda::EImageFormat fmt = stat.GetIconFormat(idx);
fmt != kabufuda::EImageFormat::None;
fmt = stat.GetIconFormat(idx))
2016-12-20 21:51:50 +00:00
{
2016-12-28 08:51:28 +00:00
if (fmt == kabufuda::EImageFormat::C8)
2016-12-20 21:51:50 +00:00
{
paletteIcon = true;
offOut += 1024;
}
else
offOut += 2048;
++idx;
}
if (paletteIcon)
offOut += 512;
2016-12-24 05:23:50 +00:00
return ECardResult::READY;
2016-12-20 21:51:50 +00:00
}
CMemoryCardDriver::SGameFileSlot::SGameFileSlot()
{
InitializeFromGameState();
}
CMemoryCardDriver::SGameFileSlot::SGameFileSlot(CMemoryInStream& in)
{
in.readBytesToBuf(x0_saveBuffer, 940);
x944_fileInfo = CGameState::LoadGameFileState(x0_saveBuffer);
}
2016-12-20 21:51:50 +00:00
void CMemoryCardDriver::SGameFileSlot::InitializeFromGameState()
{
CBitStreamWriter w(x0_saveBuffer, 940);
g_GameState->PutTo(w);
2017-02-06 03:21:58 +00:00
w.Flush();
2016-12-20 21:51:50 +00:00
x944_fileInfo = CGameState::LoadGameFileState(x0_saveBuffer);
}
2016-12-30 06:37:01 +00:00
void CMemoryCardDriver::SGameFileSlot::LoadGameState(u32 idx)
{
CBitStreamReader r(x0_saveBuffer, 940);
static_cast<MP1::CMain*>(g_Main)->StreamNewGameState(r, idx);
}
2017-11-13 06:19:18 +00:00
CMemoryCardDriver::SFileInfo::SFileInfo(kabufuda::ECardSlot port, std::string_view name)
2016-12-28 08:51:28 +00:00
: x0_fileInfo(port), x14_name(name) {}
2016-12-20 21:51:50 +00:00
2017-08-13 05:26:14 +00:00
CMemoryCardDriver::CMemoryCardDriver(kabufuda::ECardSlot cardPort, CAssetId saveBanner,
CAssetId saveIcon0, CAssetId saveIcon1, bool importPersistent)
: x0_cardPort(cardPort), x4_saveBanner(saveBanner),
2017-02-04 03:46:12 +00:00
x8_saveIcon0(saveIcon0), xc_saveIcon1(saveIcon1), x19d_importPersistent(importPersistent)
{
2016-12-20 21:51:50 +00:00
x100_mcFileInfos.reserve(2);
2016-12-24 05:23:50 +00:00
x100_mcFileInfos.emplace_back(EFileState::Unknown, SFileInfo(x0_cardPort, SaveFileNames[0]));
x100_mcFileInfos.emplace_back(EFileState::Unknown, SFileInfo(x0_cardPort, SaveFileNames[1]));
}
void CMemoryCardDriver::NoCardFound()
{
2016-12-23 06:41:39 +00:00
x10_state = EState::NoCard;
2016-12-24 05:23:50 +00:00
static_cast<CMain*>(g_Main)->SetCardBusy(false);
2016-12-20 21:51:50 +00:00
}
2016-12-30 06:37:01 +00:00
const CGameState::GameFileStateInfo* CMemoryCardDriver::GetGameFileStateInfo(int idx)
2016-12-20 21:51:50 +00:00
{
SGameFileSlot* slot = xe4_fileSlots[idx].get();
if (!slot)
return nullptr;
return &slot->x944_fileInfo;
}
2016-12-20 21:51:50 +00:00
CMemoryCardDriver::SSaveHeader CMemoryCardDriver::LoadSaveHeader(CMemoryInStream& in)
{
SSaveHeader ret;
2016-12-24 00:45:51 +00:00
ret.x0_version = in.readUint32Big();
2016-12-20 21:51:50 +00:00
for (int i=0 ; i<3 ; ++i)
2016-12-24 00:45:51 +00:00
ret.x4_savePresent[i] = in.readBool();
2016-12-20 21:51:50 +00:00
return ret;
}
std::unique_ptr<CMemoryCardDriver::SGameFileSlot> CMemoryCardDriver::LoadSaveFile(CMemoryInStream& in)
{
return std::make_unique<CMemoryCardDriver::SGameFileSlot>(in);
2016-12-20 21:51:50 +00:00
}
void CMemoryCardDriver::ReadFinished()
{
2016-12-28 08:51:28 +00:00
CMemoryCardSys::CardStat stat = {};
2016-12-20 21:51:50 +00:00
SFileInfo& fileInfo = x100_mcFileInfos[x194_fileIdx].second;
2017-01-24 07:41:33 +00:00
if (CMemoryCardSys::GetStatus(fileInfo.x0_fileInfo.slot,
fileInfo.x0_fileInfo.getFileNo(), stat) != ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
NoCardFound();
return;
}
x20_fileTime = stat.GetTime();
CMemoryInStream r(fileInfo.x34_saveData.data(), 3004);
SSaveHeader header = LoadSaveHeader(r);
r.readBytesToBuf(x30_systemData, 174);
for (int i=0 ; i<3 ; ++i)
2017-01-24 07:41:33 +00:00
if (header.x4_savePresent[i])
xe4_fileSlots[i] = LoadSaveFile(r);
2016-12-20 21:51:50 +00:00
2017-02-04 03:46:12 +00:00
if (x19d_importPersistent)
2016-12-23 06:41:39 +00:00
ImportPersistentOptions();
2016-12-20 21:51:50 +00:00
}
2016-12-23 06:41:39 +00:00
void CMemoryCardDriver::ImportPersistentOptions()
2016-12-20 21:51:50 +00:00
{
CBitStreamReader r(x30_systemData, 174);
CPersistentOptions opts(r);
2016-12-23 06:41:39 +00:00
g_GameState->ImportPersistentOptions(opts);
}
void CMemoryCardDriver::ExportPersistentOptions()
{
CBitStreamReader r(x30_systemData, 174);
CPersistentOptions opts(r);
g_GameState->ExportPersistentOptions(opts);
CBitStreamWriter w(x30_systemData, 174);
opts.PutTo(w);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::CheckCardCapacity()
{
if (x18_cardFreeBytes < 0x2000 || !x1c_cardFreeFiles)
x14_error = EError::CardStillFull;
}
void CMemoryCardDriver::IndexFiles()
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
x14_error = EError::OK;
for (std::pair<EFileState, SFileInfo>& info : x100_mcFileInfos)
{
if (info.first == EFileState::Unknown)
{
ECardResult result = info.second.Open();
if (result == ECardResult::NOFILE)
{
info.first = EFileState::NoFile;
continue;
}
else if (result == ECardResult::READY)
{
2016-12-28 08:51:28 +00:00
CMemoryCardSys::CardStat stat = {};
2017-01-24 07:41:33 +00:00
if (CMemoryCardSys::GetStatus(info.second.x0_fileInfo.slot,
info.second.x0_fileInfo.getFileNo(), stat) ==
2016-12-28 08:51:28 +00:00
ECardResult::READY)
2016-12-24 05:23:50 +00:00
{
u32 comment = stat.GetCommentAddr();
if (comment == -1)
info.first = EFileState::BadFile;
else
info.first = EFileState::File;
}
else
{
NoCardFound();
return;
}
if (info.second.Close() == ECardResult::NOCARD)
{
NoCardFound();
return;
}
}
else
{
NoCardFound();
return;
}
}
}
if (x100_mcFileInfos[0].first == EFileState::File)
{
if (x100_mcFileInfos[1].first == EFileState::File)
{
2016-12-28 08:51:28 +00:00
CMemoryCardSys::CardStat stat = {};
2017-01-24 07:41:33 +00:00
if (CMemoryCardSys::GetStatus(x100_mcFileInfos[0].second.x0_fileInfo.slot,
x100_mcFileInfos[0].second.x0_fileInfo.getFileNo(), stat) ==
2016-12-24 05:23:50 +00:00
ECardResult::READY)
{
u32 timeA = stat.GetTime();
2017-01-24 07:41:33 +00:00
if (CMemoryCardSys::GetStatus(x100_mcFileInfos[1].second.x0_fileInfo.slot,
x100_mcFileInfos[1].second.x0_fileInfo.getFileNo(), stat) ==
2016-12-24 05:23:50 +00:00
ECardResult::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 == EFileState::File)
{
x194_fileIdx = 1;
StartFileRead();
return;
}
if (x100_mcFileInfos[0].first == EFileState::BadFile ||
x100_mcFileInfos[1].first == EFileState::BadFile)
{
x10_state = EState::FileBad;
x14_error = EError::FileCorrupted;
}
else
{
x10_state = EState::FileBad;
x14_error = EError::FileMissing;
}
}
void CMemoryCardDriver::StartCardProbe()
{
x10_state = EState::CardProbe;
x14_error = EError::OK;
UpdateCardProbe();
}
void CMemoryCardDriver::StartMountCard()
{
x10_state = EState::CardMount;
x14_error = EError::OK;
ECardResult result = CMemoryCardSys::MountCard(x0_cardPort);
if (result != ECardResult::READY)
UpdateMountCard(result);
}
void CMemoryCardDriver::StartCardCheck()
{
x14_error = EError::OK;
x10_state = EState::CardCheck;
ECardResult result = CMemoryCardSys::CheckCard(x0_cardPort);
if (result != ECardResult::READY)
UpdateCardCheck(result);
}
void CMemoryCardDriver::StartFileDeleteBad()
{
x14_error = EError::OK;
x10_state = EState::FileDeleteBad;
int idx = 0;
for (std::pair<EFileState, SFileInfo>& info : x100_mcFileInfos)
{
if (info.first == EFileState::BadFile)
{
x194_fileIdx = idx;
ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, info.second.GetFileNo());
if (result != ECardResult::READY)
{
UpdateFileDeleteBad(result);
return;
}
}
++idx;
}
}
void CMemoryCardDriver::StartFileRead()
{
x14_error = EError::OK;
x10_state = EState::FileRead;
ECardResult result = x100_mcFileInfos[x194_fileIdx].second.Open();
if (result != ECardResult::READY)
{
UpdateFileRead(result);
return;
}
result = x100_mcFileInfos[x194_fileIdx].second.StartRead();
if (result != ECardResult::READY)
UpdateFileRead(result);
}
void CMemoryCardDriver::StartFileDeleteAlt()
{
x14_error = EError::OK;
x10_state = EState::FileDeleteAlt;
2016-12-23 06:41:39 +00:00
SFileInfo& fileInfo = x100_mcFileInfos[!bool(x194_fileIdx)].second;
2016-12-20 21:51:50 +00:00
ECardResult result = CMemoryCardSys::FastDeleteFile(x0_cardPort, fileInfo.GetFileNo());
2016-12-24 05:23:50 +00:00
if (result != ECardResult::READY)
UpdateFileDeleteAlt(result);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::StartFileCreate()
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
x14_error = EError::OK;
x10_state = EState::FileCreate;
if (x18_cardFreeBytes < 8192 || x1c_cardFreeFiles < 2)
{
x10_state = EState::FileCreateFailed;
x14_error = EError::CardFull;
return;
}
2017-02-04 03:46:12 +00:00
x194_fileIdx = 0;
2016-12-24 05:23:50 +00:00
x198_fileInfo = std::make_unique<CMemoryCardSys::CCardFileInfo>(x0_cardPort, SaveFileNames[x194_fileIdx]);
InitializeFileInfo();
ECardResult result = x198_fileInfo->CreateFile();
if (result != ECardResult::READY)
UpdateFileCreate(result);
}
void CMemoryCardDriver::StartFileWrite()
{
x14_error = EError::OK;
x10_state = EState::FileWrite;
2016-12-28 08:51:28 +00:00
ECardResult result = x198_fileInfo->WriteFile();
2016-12-24 05:23:50 +00:00
if (result != ECardResult::READY)
UpdateFileWrite(result);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::StartFileCreateTransactional()
{
x14_error = EError::OK;
x10_state = EState::FileCreateTransactional;
ClearFileInfo();
if (x18_cardFreeBytes < 8192 || !x1c_cardFreeFiles)
{
x10_state = EState::FileCreateTransactionalFailed;
x14_error = EError::CardFull;
return;
}
x194_fileIdx = !bool(x194_fileIdx);
x198_fileInfo = std::make_unique<CMemoryCardSys::CCardFileInfo>(x0_cardPort, SaveFileNames[x194_fileIdx]);
InitializeFileInfo();
ECardResult result = x198_fileInfo->CreateFile();
if (result != ECardResult::READY)
UpdateFileCreateTransactional(result);
}
void CMemoryCardDriver::StartFileWriteTransactional()
{
x14_error = EError::OK;
x10_state = EState::FileWriteTransactional;
2016-12-28 08:51:28 +00:00
ECardResult result = x198_fileInfo->WriteFile();
2016-12-24 05:23:50 +00:00
if (result != ECardResult::READY)
UpdateFileWriteTransactional(result);
}
void CMemoryCardDriver::StartFileDeleteAltTransactional()
{
x14_error = EError::OK;
x10_state = EState::FileDeleteAltTransactional;
ECardResult result = CMemoryCardSys::DeleteFile(x0_cardPort,
SaveFileNames[!bool(x194_fileIdx)]);
if (result != ECardResult::READY)
UpdateFileDeleteAltTransactional(result);
}
void CMemoryCardDriver::StartFileRenameBtoA()
{
if (x194_fileIdx == 1)
{
/* Rename B file to A file (ideally the card is always left with 'A' only) */
x14_error = EError::OK;
x10_state = EState::FileRenameBtoA;
ECardResult result = CMemoryCardSys::Rename(x0_cardPort,
SaveFileNames[x194_fileIdx],
SaveFileNames[!bool(x194_fileIdx)]);
if (result != ECardResult::READY)
UpdateFileRenameBtoA(result);
}
else
{
x10_state = EState::DriverClosed;
WriteBackupBuf();
}
}
void CMemoryCardDriver::StartCardFormat()
{
x14_error = EError::OK;
x10_state = EState::CardFormat;
ECardResult result = CMemoryCardSys::FormatCard(x0_cardPort);
if (result != ECardResult::READY)
UpdateCardFormat(result);
}
void CMemoryCardDriver::UpdateMountCard(ECardResult result)
{
switch (result)
{
2016-12-24 05:23:50 +00:00
case ECardResult::READY:
2016-12-23 06:41:39 +00:00
x10_state = EState::CardMountDone;
2016-12-24 05:23:50 +00:00
StartCardCheck();
break;
2016-12-24 05:23:50 +00:00
case ECardResult::BROKEN:
2016-12-23 06:41:39 +00:00
x10_state = EState::CardMountDone;
2016-12-24 05:23:50 +00:00
x14_error = EError::CardBroken;
2017-02-04 03:46:12 +00:00
//StartCardCheck();
break;
default:
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::CardMountFailed);
break;
}
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateCardProbe()
{
auto result = CMemoryCardSys::CardProbe(x0_cardPort);
switch (result.x0_error)
{
case ECardResult::READY:
if (result.x8_sectorSize != 0x2000)
{
x10_state = EState::CardProbeFailed;
x14_error = EError::CardNon8KSectors;
return;
}
x10_state = EState::CardProbeDone;
StartMountCard();
break;
case ECardResult::BUSY:
break;
case ECardResult::WRONGDEVICE:
x10_state = EState::CardProbeFailed;
x14_error = EError::CardWrongDevice;
break;
default:
NoCardFound();
break;
}
}
void CMemoryCardDriver::UpdateCardCheck(ECardResult result)
{
switch (result)
{
2016-12-24 05:23:50 +00:00
case ECardResult::READY:
x10_state = EState::CardCheckDone;
if (!GetCardFreeBytes())
return;
2016-12-24 05:23:50 +00:00
if (CMemoryCardSys::GetSerialNo(x0_cardPort, x28_cardSerial) == ECardResult::READY)
return;
NoCardFound();
break;
2016-12-24 05:23:50 +00:00
case ECardResult::BROKEN:
x10_state = EState::CardCheckFailed;
x14_error = EError::CardBroken;
break;
default:
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::CardCheckFailed);
}
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileDeleteBad(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
x100_mcFileInfos[x194_fileIdx].first = EFileState::NoFile;
if (x100_mcFileInfos[!bool(x194_fileIdx)].first == EFileState::BadFile)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileBad;
StartFileDeleteBad();
2016-12-20 21:51:50 +00:00
}
else
{
2016-12-24 05:23:50 +00:00
x10_state = EState::CardCheckDone;
2016-12-20 21:51:50 +00:00
if (!GetCardFreeBytes())
return;
2016-12-24 05:23:50 +00:00
IndexFiles();
2016-12-20 21:51:50 +00:00
}
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileDeleteBadFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileRead(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
auto& fileInfo = x100_mcFileInfos[x194_fileIdx];
ECardResult readRes = fileInfo.second.TryFileRead();
2016-12-24 05:23:50 +00:00
if (fileInfo.second.Close() != ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
NoCardFound();
return;
}
2016-12-24 05:23:50 +00:00
u32 altFileIdx = !bool(x194_fileIdx);
if (readRes == ECardResult::READY)
2016-12-20 21:51:50 +00:00
{
2016-12-23 06:41:39 +00:00
x10_state = EState::Ready;
2016-12-20 21:51:50 +00:00
ReadFinished();
2016-12-24 05:23:50 +00:00
EFileState fileSt = x100_mcFileInfos[altFileIdx].first;
if (fileSt == EFileState::NoFile)
2016-12-20 21:51:50 +00:00
CheckCardCapacity();
else
2016-12-24 05:23:50 +00:00
StartFileDeleteAlt();
2016-12-20 21:51:50 +00:00
return;
}
2016-12-24 05:23:50 +00:00
if (readRes == ECardResult::CRC_MISMATCH)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
x100_mcFileInfos[x194_fileIdx].first = EFileState::BadFile;
if (x100_mcFileInfos[altFileIdx].first == EFileState::File)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::CardCheckDone;
IndexFiles();
2016-12-20 21:51:50 +00:00
}
else
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileBad;
x14_error = EError::FileCorrupted;
2016-12-20 21:51:50 +00:00
}
}
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileBad);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileDeleteAlt(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
x10_state = EState::Ready;
if (GetCardFreeBytes())
CheckCardCapacity();
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileDeleteAltFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileCreate(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileCreateDone;
StartFileWrite();
2016-12-23 06:41:39 +00:00
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileCreateFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileWrite(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
ECardResult xferResult = x198_fileInfo->PumpCardTransfer();
2016-12-24 05:23:50 +00:00
if (xferResult == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
x10_state = EState::Ready;
2016-12-28 08:51:28 +00:00
if (x198_fileInfo->CloseFile() == ECardResult::READY)
2017-02-04 03:46:12 +00:00
{
CMemoryCardSys::CommitToDisk(x0_cardPort);
2016-12-23 06:41:39 +00:00
return;
2017-02-04 03:46:12 +00:00
}
2016-12-23 06:41:39 +00:00
NoCardFound();
return;
}
2016-12-24 05:23:50 +00:00
if (xferResult == ECardResult::BUSY)
2016-12-23 06:41:39 +00:00
return;
2016-12-24 05:23:50 +00:00
if (xferResult == ECardResult::IOERROR)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileWriteFailed;
x14_error = EError::CardIOError;
2016-12-23 06:41:39 +00:00
return;
}
NoCardFound();
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileWriteFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileCreateTransactional(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileCreateTransactionalDone;
StartFileWriteTransactional();
2016-12-23 06:41:39 +00:00
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileCreateTransactionalFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileWriteTransactional(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
ECardResult xferResult = x198_fileInfo->PumpCardTransfer();
2016-12-24 05:23:50 +00:00
if (xferResult == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileWriteTransactionalDone;
2016-12-28 08:51:28 +00:00
if (x198_fileInfo->CloseFile() != ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
NoCardFound();
return;
}
2016-12-24 05:23:50 +00:00
StartFileDeleteAltTransactional();
2016-12-23 06:41:39 +00:00
return;
}
2016-12-24 05:23:50 +00:00
if (xferResult == ECardResult::BUSY)
2016-12-23 06:41:39 +00:00
return;
2016-12-24 05:23:50 +00:00
if (xferResult == ECardResult::IOERROR)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileWriteTransactionalFailed;
x14_error = EError::CardIOError;
2016-12-23 06:41:39 +00:00
return;
}
NoCardFound();
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileWriteTransactionalFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileDeleteAltTransactional(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::FileDeleteAltTransactionalDone;
2016-12-23 06:41:39 +00:00
if (GetCardFreeBytes())
2016-12-24 05:23:50 +00:00
StartFileRenameBtoA();
2016-12-23 06:41:39 +00:00
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileDeleteAltTransactionalFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateFileRenameBtoA(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::DriverClosed;
2017-02-04 03:46:12 +00:00
CMemoryCardSys::CommitToDisk(x0_cardPort);
2016-12-23 06:41:39 +00:00
WriteBackupBuf();
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::FileRenameBtoAFailed);
2016-12-20 21:51:50 +00:00
}
2016-12-24 05:23:50 +00:00
void CMemoryCardDriver::UpdateCardFormat(ECardResult result)
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
2016-12-23 06:41:39 +00:00
x10_state = EState::CardFormatted;
2016-12-24 05:23:50 +00:00
else if (result == ECardResult::BROKEN)
2016-12-23 06:41:39 +00:00
{
2016-12-24 05:23:50 +00:00
x10_state = EState::CardFormatFailed;
x14_error = EError::CardIOError;
2016-12-23 06:41:39 +00:00
}
else
2016-12-24 05:23:50 +00:00
HandleCardError(result, EState::CardFormatFailed);
2016-12-23 06:41:39 +00:00
}
2016-12-30 06:37:01 +00:00
void CMemoryCardDriver::BuildNewFileSlot(u32 saveIdx)
{
g_GameState->SetFileIdx(saveIdx);
2017-01-01 06:46:52 +00:00
bool fusionBackup = g_GameState->SystemOptions().GetPlayerFusionSuitActive();
2016-12-30 06:37:01 +00:00
std::unique_ptr<SGameFileSlot>& slot = xe4_fileSlots[saveIdx];
if (!slot)
slot = std::make_unique<SGameFileSlot>();
slot->LoadGameState(saveIdx);
CBitStreamReader r(x30_systemData, 174);
g_GameState->ReadPersistentOptions(r);
ImportPersistentOptions();
g_GameState->SetCardSerial(x28_cardSerial);
2017-01-01 06:46:52 +00:00
g_GameState->SystemOptions().SetPlayerFusionSuitActive(fusionBackup);
2016-12-30 06:37:01 +00:00
}
2016-12-31 00:51:51 +00:00
void CMemoryCardDriver::EraseFileSlot(u32 saveIdx)
{
xe4_fileSlots[saveIdx].reset();
}
2016-12-30 06:37:01 +00:00
void CMemoryCardDriver::BuildExistingFileSlot(u32 saveIdx)
{
g_GameState->SetFileIdx(saveIdx);
std::unique_ptr<SGameFileSlot>& slot = xe4_fileSlots[saveIdx];
if (!slot)
slot = std::make_unique<SGameFileSlot>();
else
slot->InitializeFromGameState();
CBitStreamWriter w(x30_systemData, 174);
g_GameState->PutTo(w);
}
2016-12-23 06:41:39 +00:00
void CMemoryCardDriver::InitializeFileInfo()
{
ExportPersistentOptions();
2016-12-24 00:45:51 +00:00
OSCalendarTime time = CBasics::ToCalendarTime(std::chrono::system_clock::now());
char timeString[32];
snprintf(timeString, 32, "%02d.%02d.%02d %02d:%02d",
time.x10_mon + 1, time.xc_mday, time.x14_year % 100,
time.x8_hour, time.x4_min);
std::string comment("Metroid Prime ");
comment += timeString;
x198_fileInfo->SetComment(comment);
x198_fileInfo->LockBannerToken(x4_saveBanner, *g_SimplePool);
2016-12-28 08:51:28 +00:00
x198_fileInfo->LockIconToken(x8_saveIcon0, kabufuda::EAnimationSpeed::Middle, *g_SimplePool);
2016-12-24 00:45:51 +00:00
CMemoryOutStream w = x198_fileInfo->BeginMemoryOut(3004);
SSaveHeader header;
for (int i=0 ; i<3 ; ++i)
header.x4_savePresent[i] = xe4_fileSlots[i].operator bool();
header.DoPut(w);
w.writeBytes(x30_systemData, 174);
for (int i=0 ; i<3 ; ++i)
if (xe4_fileSlots[i])
xe4_fileSlots[i]->DoPut(w);
2016-12-23 06:41:39 +00:00
}
void CMemoryCardDriver::WriteBackupBuf()
{
g_GameState->WriteBackupBuf();
g_GameState->SetCardSerial(x28_cardSerial);
2016-12-20 21:51:50 +00:00
}
bool CMemoryCardDriver::GetCardFreeBytes()
{
2016-12-20 21:51:50 +00:00
ECardResult result = CMemoryCardSys::GetNumFreeBytes(x0_cardPort,
x18_cardFreeBytes,
x1c_cardFreeFiles);
2016-12-24 05:23:50 +00:00
if (result == ECardResult::READY)
return true;
NoCardFound();
return false;
}
2016-12-20 21:51:50 +00:00
void CMemoryCardDriver::HandleCardError(ECardResult result, EState state)
{
switch (result)
{
2016-12-24 05:23:50 +00:00
case ECardResult::WRONGDEVICE:
x10_state = state;
2016-12-24 05:23:50 +00:00
x14_error = EError::CardWrongDevice;
break;
2016-12-24 05:23:50 +00:00
case ECardResult::NOCARD:
NoCardFound();
break;
2016-12-24 05:23:50 +00:00
case ECardResult::IOERROR:
x10_state = state;
2016-12-24 05:23:50 +00:00
x14_error = EError::CardIOError;
case ECardResult::ENCODING:
x10_state = state;
2016-12-24 05:23:50 +00:00
x14_error = EError::CardWrongCharacterSet;
break;
default: break;
}
}
void CMemoryCardDriver::Update()
{
2016-12-28 08:51:28 +00:00
kabufuda::ProbeResults result = CMemoryCardSys::CardProbe(x0_cardPort);
2016-12-24 05:23:50 +00:00
if (result.x0_error == ECardResult::NOCARD)
{
2016-12-23 06:41:39 +00:00
if (x10_state != EState::NoCard)
NoCardFound();
2016-12-24 05:23:50 +00:00
static_cast<CMain*>(g_Main)->SetCardBusy(false);
return;
}
2016-12-24 05:23:50 +00:00
if (x10_state == EState::CardProbe)
{
2016-12-24 05:23:50 +00:00
UpdateCardProbe();
static_cast<CMain*>(g_Main)->SetCardBusy(false);
2016-12-20 21:51:50 +00:00
return;
}
2016-12-20 21:51:50 +00:00
2016-12-24 05:23:50 +00:00
ECardResult resultCode = CMemoryCardSys::GetResultCode(x0_cardPort);
bool cardBusy = false;
2016-12-20 21:51:50 +00:00
2016-12-24 05:23:50 +00:00
if (IsCardBusy(x10_state))
2016-12-20 21:51:50 +00:00
{
2016-12-24 05:23:50 +00:00
cardBusy = true;
2016-12-20 21:51:50 +00:00
switch (x10_state)
{
2016-12-23 06:41:39 +00:00
case EState::CardMount:
2016-12-24 05:23:50 +00:00
UpdateMountCard(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::CardCheck:
UpdateCardCheck(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileDeleteBad:
UpdateFileDeleteBad(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileRead:
UpdateFileRead(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileDeleteAlt:
UpdateFileDeleteAlt(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileCreate:
UpdateFileCreate(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileWrite:
UpdateFileWrite(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileCreateTransactional:
UpdateFileCreateTransactional(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileWriteTransactional:
UpdateFileWriteTransactional(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileDeleteAltTransactional:
UpdateFileDeleteAltTransactional(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-24 05:23:50 +00:00
case EState::FileRenameBtoA:
UpdateFileRenameBtoA(resultCode);
2016-12-20 21:51:50 +00:00
break;
2016-12-23 06:41:39 +00:00
case EState::CardFormat:
2016-12-24 05:23:50 +00:00
UpdateCardFormat(resultCode);
2016-12-20 21:51:50 +00:00
break;
default: break;
}
}
2016-12-24 05:23:50 +00:00
static_cast<CMain*>(g_Main)->SetCardBusy(cardBusy);
}
}
}