Kabufuda updates and dolphin memory card path resolution

This commit is contained in:
Jack Andersen 2016-12-28 11:39:38 -10:00
parent 563ff28848
commit fe3d375120
7 changed files with 216 additions and 28 deletions

View File

@ -11,8 +11,9 @@ namespace urde
using ECardResult = kabufuda::ECardResult; using ECardResult = kabufuda::ECardResult;
kabufuda::SystemString g_CardImagePaths[2] = {}; static kabufuda::SystemString g_CardImagePaths[2] = {};
kabufuda::Card g_CardStates[2] = {}; static kabufuda::Card g_CardStates[2] = {};
static kabufuda::ECardResult g_OpResults[2] = {};
CSaveWorldIntermediate::CSaveWorldIntermediate(ResId mlvl, ResId savw) CSaveWorldIntermediate::CSaveWorldIntermediate(ResId mlvl, ResId savw)
: x0_mlvlId(mlvl), x8_savwId(savw) : x0_mlvlId(mlvl), x8_savwId(savw)
@ -62,6 +63,9 @@ bool CSaveWorldIntermediate::InitializePump()
CMemoryCardSys::CMemoryCardSys() CMemoryCardSys::CMemoryCardSys()
{ {
g_CardImagePaths[0] = ResolveDolphinCardPath(kabufuda::ECardSlot::SlotA);
g_CardImagePaths[1] = ResolveDolphinCardPath(kabufuda::ECardSlot::SlotB);
x0_hints = g_SimplePool->GetObj("HINT_Hints"); x0_hints = g_SimplePool->GetObj("HINT_Hints");
xc_memoryWorlds.reserve(16); xc_memoryWorlds.reserve(16);
x1c_worldInter.emplace(); x1c_worldInter.emplace();
@ -261,7 +265,7 @@ ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer()
result = GetStatus(stat); result = GetStatus(stat);
if (result != ECardResult::READY) if (result != ECardResult::READY)
return result; return result;
result = CMemoryCardSys::SetStatus(GetCardPort(), GetFileNo(), stat); result = CMemoryCardSys::SetStatus(m_handle, stat);
if (result != ECardResult::READY) if (result != ECardResult::READY)
return result; return result;
return ECardResult::BUSY; return ECardResult::BUSY;
@ -277,7 +281,7 @@ ECardResult CMemoryCardSys::CCardFileInfo::PumpCardTransfer()
ECardResult CMemoryCardSys::CCardFileInfo::GetStatus(kabufuda::CardStat& stat) const ECardResult CMemoryCardSys::CCardFileInfo::GetStatus(kabufuda::CardStat& stat) const
{ {
ECardResult result = CMemoryCardSys::GetStatus(GetCardPort(), GetFileNo(), stat); ECardResult result = CMemoryCardSys::GetStatus(m_handle, stat);
if (result != ECardResult::READY) if (result != ECardResult::READY)
return result; return result;
@ -333,7 +337,9 @@ ECardResult CMemoryCardSys::CCardFileInfo::CloseFile()
kabufuda::ProbeResults CMemoryCardSys::CardProbe(kabufuda::ECardSlot port) kabufuda::ProbeResults CMemoryCardSys::CardProbe(kabufuda::ECardSlot port)
{ {
return kabufuda::Card::probeCardFile(g_CardImagePaths[int(port)]); kabufuda::ProbeResults res = kabufuda::Card::probeCardFile(g_CardImagePaths[int(port)]);
g_OpResults[int(port)] = res.x0_error;
return res;
} }
ECardResult CMemoryCardSys::MountCard(kabufuda::ECardSlot port) ECardResult CMemoryCardSys::MountCard(kabufuda::ECardSlot port)
@ -341,6 +347,7 @@ ECardResult CMemoryCardSys::MountCard(kabufuda::ECardSlot port)
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
card = kabufuda::Card(g_CardImagePaths[int(port)], "GM8E", "01"); card = kabufuda::Card(g_CardImagePaths[int(port)], "GM8E", "01");
ECardResult result = card.getError(); ECardResult result = card.getError();
g_OpResults[int(port)] = result;
if (result == ECardResult::READY) if (result == ECardResult::READY)
return ECardResult::READY; return ECardResult::READY;
card = kabufuda::Card(); card = kabufuda::Card();
@ -350,40 +357,61 @@ ECardResult CMemoryCardSys::MountCard(kabufuda::ECardSlot port)
ECardResult CMemoryCardSys::CheckCard(kabufuda::ECardSlot port) ECardResult CMemoryCardSys::CheckCard(kabufuda::ECardSlot port)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
return card.getError(); ECardResult result = card.getError();
g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::CreateFile(kabufuda::ECardSlot port, const char* name, u32 size, CardFileHandle& info) ECardResult CMemoryCardSys::CreateFile(kabufuda::ECardSlot port, const char* name, u32 size, CardFileHandle& info)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
}
info.slot = port; info.slot = port;
return card.createFile(name, size, info.handle); ECardResult result = card.createFile(name, size, info.handle);
g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::OpenFile(kabufuda::ECardSlot port, const char* name, CardFileHandle& info) ECardResult CMemoryCardSys::OpenFile(kabufuda::ECardSlot port, const char* name, CardFileHandle& info)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
}
info.slot = port; info.slot = port;
info.handle = card.openFile(name); ECardResult result = card.openFile(name, info.handle);
return info.handle ? ECardResult::READY : ECardResult::NOFILE; g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::FastOpenFile(kabufuda::ECardSlot port, int fileNo, CardFileHandle& info) ECardResult CMemoryCardSys::FastOpenFile(kabufuda::ECardSlot port, int fileNo, CardFileHandle& info)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
}
info.slot = port; info.slot = port;
info.handle = card.openFile(fileNo); ECardResult result = card.openFile(fileNo, info.handle);
return info.handle ? ECardResult::READY : ECardResult::NOFILE; g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::CloseFile(CardFileHandle& info) ECardResult CMemoryCardSys::CloseFile(CardFileHandle& info)
{ {
kabufuda::Card& card = g_CardStates[int(info.slot)];
if (CardResult err = card.getError())
{
g_OpResults[int(info.slot)] = err;
return err;
}
info.handle.reset(); info.handle.reset();
return ECardResult::READY; return ECardResult::READY;
} }
@ -392,9 +420,13 @@ ECardResult CMemoryCardSys::ReadFile(const CardFileHandle& info, void* buf, s32
{ {
kabufuda::Card& card = g_CardStates[int(info.slot)]; kabufuda::Card& card = g_CardStates[int(info.slot)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(info.slot)] = err;
return err; return err;
}
card.seek(info, offset, kabufuda::SeekOrigin::Begin); card.seek(info, offset, kabufuda::SeekOrigin::Begin);
card.read(info, buf, length); card.read(info, buf, length);
g_OpResults[int(info.slot)] = ECardResult::READY;
return ECardResult::READY; return ECardResult::READY;
} }
@ -402,9 +434,13 @@ ECardResult CMemoryCardSys::WriteFile(const CardFileHandle& info, const void* bu
{ {
kabufuda::Card& card = g_CardStates[int(info.slot)]; kabufuda::Card& card = g_CardStates[int(info.slot)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(info.slot)] = err;
return err; return err;
}
card.seek(info, offset, kabufuda::SeekOrigin::Begin); card.seek(info, offset, kabufuda::SeekOrigin::Begin);
card.write(info, buf, length); card.write(info, buf, length);
g_OpResults[int(info.slot)] = ECardResult::READY;
return ECardResult::READY; return ECardResult::READY;
} }
@ -412,8 +448,12 @@ ECardResult CMemoryCardSys::GetNumFreeBytes(kabufuda::ECardSlot port, s32& freeB
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
}
card.getFreeBlocks(freeBytes, freeFiles); card.getFreeBlocks(freeBytes, freeFiles);
g_OpResults[int(port)] = ECardResult::READY;
return ECardResult::READY; return ECardResult::READY;
} }
@ -421,56 +461,95 @@ ECardResult CMemoryCardSys::GetSerialNo(kabufuda::ECardSlot port, u64& serialOut
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
}
card.getSerial(serialOut); card.getSerial(serialOut);
g_OpResults[int(port)] = ECardResult::READY;
return ECardResult::READY; return ECardResult::READY;
} }
ECardResult CMemoryCardSys::GetResultCode(kabufuda::ECardSlot port) ECardResult CMemoryCardSys::GetResultCode(kabufuda::ECardSlot port)
{ {
return ECardResult::READY; return g_OpResults[int(port)];
} }
ECardResult CMemoryCardSys::GetStatus(kabufuda::ECardSlot port, int fileNo, CardStat& statOut) ECardResult CMemoryCardSys::GetStatus(const CardFileHandle& info, CardStat& statOut)
{ {
return ECardResult::READY; kabufuda::Card& card = g_CardStates[int(info.slot)];
if (CardResult err = card.getError())
{
g_OpResults[int(info.slot)] = err;
return err;
}
ECardResult result = card.getStatus(info, statOut);
g_OpResults[int(info.slot)] = result;
return result;
} }
ECardResult CMemoryCardSys::SetStatus(kabufuda::ECardSlot port, int fileNo, const CardStat& stat) ECardResult CMemoryCardSys::SetStatus(const CardFileHandle& info, const CardStat& stat)
{ {
return ECardResult::READY; kabufuda::Card& card = g_CardStates[int(info.slot)];
if (CardResult err = card.getError())
{
g_OpResults[int(info.slot)] = err;
return err;
}
ECardResult result = card.setStatus(info, stat);
g_OpResults[int(info.slot)] = result;
return result;
} }
ECardResult CMemoryCardSys::DeleteFile(kabufuda::ECardSlot port, const char* name) ECardResult CMemoryCardSys::DeleteFile(kabufuda::ECardSlot port, const char* name)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
return card.deleteFile(name); }
ECardResult result = card.deleteFile(name);
g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::FastDeleteFile(kabufuda::ECardSlot port, int fileNo) ECardResult CMemoryCardSys::FastDeleteFile(kabufuda::ECardSlot port, int fileNo)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
return card.deleteFile(fileNo); }
ECardResult result = card.deleteFile(fileNo);
g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::Rename(kabufuda::ECardSlot port, const char* oldName, const char* newName) ECardResult CMemoryCardSys::Rename(kabufuda::ECardSlot port, const char* oldName, const char* newName)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
return card.renameFile(oldName, newName); }
ECardResult result = card.renameFile(oldName, newName);
g_OpResults[int(port)] = result;
return result;
} }
ECardResult CMemoryCardSys::FormatCard(kabufuda::ECardSlot port) ECardResult CMemoryCardSys::FormatCard(kabufuda::ECardSlot port)
{ {
kabufuda::Card& card = g_CardStates[int(port)]; kabufuda::Card& card = g_CardStates[int(port)];
if (CardResult err = card.getError()) if (CardResult err = card.getError())
{
g_OpResults[int(port)] = err;
return err; return err;
}
card.format(port); card.format(port);
g_OpResults[int(port)] = ECardResult::READY;
return ECardResult::READY; return ECardResult::READY;
} }

View File

@ -58,6 +58,8 @@ class CMemoryCardSys
std::experimental::optional<std::vector<CSaveWorldIntermediate>> x1c_worldInter; /* used to be auto_ptr of vector */ std::experimental::optional<std::vector<CSaveWorldIntermediate>> x1c_worldInter; /* used to be auto_ptr of vector */
std::vector<std::pair<ResId, CSaveWorld::EScanCategory>> x20_scanStates; std::vector<std::pair<ResId, CSaveWorld::EScanCategory>> x20_scanStates;
public: public:
static kabufuda::SystemString ResolveDolphinCardPath(kabufuda::ECardSlot slot);
using ECardResult = kabufuda::ECardResult; using ECardResult = kabufuda::ECardResult;
struct CardResult struct CardResult
{ {
@ -153,8 +155,8 @@ public:
static ECardResult GetNumFreeBytes(kabufuda::ECardSlot port, s32& freeBytes, s32& freeFiles); static ECardResult GetNumFreeBytes(kabufuda::ECardSlot port, s32& freeBytes, s32& freeFiles);
static ECardResult GetSerialNo(kabufuda::ECardSlot port, u64& serialOut); static ECardResult GetSerialNo(kabufuda::ECardSlot port, u64& serialOut);
static ECardResult GetResultCode(kabufuda::ECardSlot port); static ECardResult GetResultCode(kabufuda::ECardSlot port);
static ECardResult GetStatus(kabufuda::ECardSlot port, int fileNo, CardStat& statOut); static ECardResult GetStatus(const CardFileHandle& info, CardStat& statOut);
static ECardResult SetStatus(kabufuda::ECardSlot port, int fileNo, const CardStat& stat); static ECardResult SetStatus(const CardFileHandle& info, const CardStat& stat);
static ECardResult DeleteFile(kabufuda::ECardSlot port, const char* name); static ECardResult DeleteFile(kabufuda::ECardSlot port, const char* name);
static ECardResult FastDeleteFile(kabufuda::ECardSlot port, int fileNo); static ECardResult FastDeleteFile(kabufuda::ECardSlot port, int fileNo);
static ECardResult Rename(kabufuda::ECardSlot port, const char* oldName, const char* newName); static ECardResult Rename(kabufuda::ECardSlot port, const char* oldName, const char* newName);

View File

@ -3,4 +3,31 @@
namespace urde namespace urde
{ {
kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlot slot)
{
const char* home = getenv("HOME");
if (!home || home[0] != '/')
return {};
const char* dataHome = getenv("XDG_DATA_HOME");
/* XDG-selected data path */
kabufuda::SystemString path =
(dataHome && dataHome[0] == '/') ? dataHome : (home + "/.local/share") + "/.dolphin-emu";
path += hecl::Format("/GC/MemoryCard%c.USA.raw",
slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B');
hecl::Sstat theStat;
if (hecl::Stat(path.c_str(), &theStat) || !S_ISREG(theStat.st_mode))
{
/* legacy case for older dolphin versions */
path = home;
path += hecl::Format("/.dolphin-emu/GC/MemoryCard%c.USA.raw",
slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B');
if (hecl::Stat(path.c_str(), &theStat) || !S_ISREG(theStat.st_mode))
return {};
}
return path;
}
} }

View File

@ -0,0 +1,23 @@
#include "CMemoryCardSys.hpp"
namespace urde
{
kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlot slot)
{
const char* home = getenv("HOME");
if (!home)
return {};
kabufuda::SystemString path = home;
path += hecl::Format("/Library/Application Support/Dolphin/GC/MemoryCard%c.USA.raw",
slot == kabufuda::ECardSlot::SlotA ? 'A' : 'B');
hecl::Sstat theStat;
if (hecl::Stat(path.c_str(), &theStat) || !S_ISREG(theStat.st_mode))
return {};
return path;
}
}

View File

@ -0,0 +1,57 @@
#include "CMemoryCardSys.hpp"
#include <shlobj.h>
namespace urde
{
/* Partial path-selection logic from
* https://github.com/dolphin-emu/dolphin/blob/master/Source/Core/UICommon/UICommon.cpp
* Modified to not use dolphin-binary-relative paths. */
kabufuda::SystemString CMemoryCardSys::ResolveDolphinCardPath(kabufuda::ECardSlot slot)
{
kabufuda::SystemString userPath;
/* Detect where the User directory is. There are two different cases
* 1. HKCU\Software\Dolphin Emulator\UserConfigPath exists
* -> Use this as the user directory path
* 2. My Documents exists
* -> Use My Documents\Dolphin Emulator as the User directory path
*/
/* Check our registry keys */
HKEY hkey;
kabufuda::SystemChar configPath[MAX_PATH] = {0};
if (RegOpenKeyEx(HKEY_CURRENT_USER, _S("Software\\Dolphin Emulator"), 0, KEY_QUERY_VALUE,
&hkey) == ERROR_SUCCESS)
{
DWORD size = MAX_PATH;
if (RegQueryValueEx(hkey, _S("UserConfigPath"), nullptr, nullptr, (LPBYTE)configPath,
&size) != ERROR_SUCCESS)
configPath[0] = 0;
RegCloseKey(hkey);
}
/* Get My Documents path in case we need it. */
kabufuda::SystemChar my_documents[MAX_PATH];
bool my_documents_found = SUCCEEDED(
SHGetFolderPath(nullptr, CSIDL_MYDOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, my_documents));
if (configPath[0]) /* Case 1 */
userPath = configPath;
else if (my_documents_found) /* Case 2 */
userPath = my_documents + _S("/Dolphin Emulator");
else /* Unable to find */
return {};
kabufuda::SystemString path = userPath;
path += hecl::SysFormat(_S("/GC/MemoryCard%c.USA.raw"),
slot == kabufuda::ECardSlot::SlotA ? _S('A') : _S('B'));
hecl::Sstat theStat;
if (hecl::Stat(path.c_str(), &theStat) || !S_ISREG(theStat.st_mode))
return {};
return path;
}
}

View File

@ -29,7 +29,7 @@ ECardResult CMemoryCardDriver::SFileInfo::Close()
ECardResult CMemoryCardDriver::SFileInfo::StartRead() ECardResult CMemoryCardDriver::SFileInfo::StartRead()
{ {
CMemoryCardSys::CardStat stat = {}; CMemoryCardSys::CardStat stat = {};
ECardResult result = CMemoryCardSys::GetStatus(GetFileCardPort(), GetFileNo(), stat); ECardResult result = CMemoryCardSys::GetStatus(x0_fileInfo, stat);
if (result != ECardResult::READY) if (result != ECardResult::READY)
return result; return result;
@ -78,7 +78,7 @@ ECardResult CMemoryCardDriver::SFileInfo::FileRead()
ECardResult CMemoryCardDriver::SFileInfo::GetSaveDataOffset(u32& offOut) ECardResult CMemoryCardDriver::SFileInfo::GetSaveDataOffset(u32& offOut)
{ {
CMemoryCardSys::CardStat stat = {}; CMemoryCardSys::CardStat stat = {};
ECardResult result = CMemoryCardSys::GetStatus(GetFileCardPort(), GetFileNo(), stat); ECardResult result = CMemoryCardSys::GetStatus(x0_fileInfo, stat);
if (result != ECardResult::READY) if (result != ECardResult::READY)
{ {
offOut = -1; offOut = -1;
@ -183,7 +183,7 @@ void CMemoryCardDriver::ReadFinished()
{ {
CMemoryCardSys::CardStat stat = {}; CMemoryCardSys::CardStat stat = {};
SFileInfo& fileInfo = x100_mcFileInfos[x194_fileIdx].second; SFileInfo& fileInfo = x100_mcFileInfos[x194_fileIdx].second;
if (CMemoryCardSys::GetStatus(x0_cardPort, fileInfo.GetFileNo(), stat) != ECardResult::READY) if (CMemoryCardSys::GetStatus(fileInfo.x0_fileInfo, stat) != ECardResult::READY)
{ {
NoCardFound(); NoCardFound();
return; return;
@ -239,7 +239,7 @@ void CMemoryCardDriver::IndexFiles()
else if (result == ECardResult::READY) else if (result == ECardResult::READY)
{ {
CMemoryCardSys::CardStat stat = {}; CMemoryCardSys::CardStat stat = {};
if (CMemoryCardSys::GetStatus(x0_cardPort, info.second.GetFileNo(), stat) == if (CMemoryCardSys::GetStatus(info.second.x0_fileInfo, stat) ==
ECardResult::READY) ECardResult::READY)
{ {
u32 comment = stat.GetCommentAddr(); u32 comment = stat.GetCommentAddr();
@ -272,11 +272,11 @@ void CMemoryCardDriver::IndexFiles()
if (x100_mcFileInfos[1].first == EFileState::File) if (x100_mcFileInfos[1].first == EFileState::File)
{ {
CMemoryCardSys::CardStat stat = {}; CMemoryCardSys::CardStat stat = {};
if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[0].second.GetFileNo(), stat) == if (CMemoryCardSys::GetStatus(x100_mcFileInfos[0].second.x0_fileInfo, stat) ==
ECardResult::READY) ECardResult::READY)
{ {
u32 timeA = stat.GetTime(); u32 timeA = stat.GetTime();
if (CMemoryCardSys::GetStatus(x0_cardPort, x100_mcFileInfos[1].second.GetFileNo(), stat) == if (CMemoryCardSys::GetStatus(x100_mcFileInfos[1].second.x0_fileInfo, stat) ==
ECardResult::READY) ECardResult::READY)
{ {
u32 timeB = stat.GetTime(); u32 timeB = stat.GetTime();

@ -1 +1 @@
Subproject commit 223ea9a56ebc8ad7e03a2b920dbdc9d621cda551 Subproject commit 7315a1dedd0ff060b5266e0d7a9d783447ed5cf2