186 lines
4.7 KiB
C++
186 lines
4.7 KiB
C++
#include "NDS.h"
|
|
#include "NDSCart.h"
|
|
#include "GBACart.h"
|
|
#include "DSi.h"
|
|
#include "DSi_NAND.h"
|
|
#include "Platform.h"
|
|
|
|
namespace Platform
|
|
{
|
|
|
|
constexpr u32 DSIWARE_CATEGORY = 0x00030004;
|
|
|
|
static bool NdsSaveRamIsDirty = false;
|
|
static bool GbaSaveRamIsDirty = false;
|
|
|
|
ECL_EXPORT void PutSaveRam(u8* data, u32 len)
|
|
{
|
|
const u32 ndsSaveLen = NDSCart::GetSaveMemoryLength();
|
|
const u32 gbaSaveLen = GBACart::GetSaveMemoryLength();
|
|
|
|
if (len >= ndsSaveLen)
|
|
{
|
|
NDS::LoadSave(data, len);
|
|
NdsSaveRamIsDirty = false;
|
|
|
|
if (gbaSaveLen && len >= (ndsSaveLen + gbaSaveLen))
|
|
{
|
|
// don't use GBACart::LoadSave! it will re-allocate the save buffer (bad!)
|
|
// NDS::LoadSave is fine (and should be used)
|
|
memcpy(GBACart::GetSaveMemory(), data + ndsSaveLen, gbaSaveLen);
|
|
GbaSaveRamIsDirty = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
ECL_EXPORT void GetSaveRam(u8* data)
|
|
{
|
|
const u32 ndsSaveLen = NDSCart::GetSaveMemoryLength();
|
|
const u32 gbaSaveLen = GBACart::GetSaveMemoryLength();
|
|
|
|
if (ndsSaveLen)
|
|
{
|
|
memcpy(data, NDSCart::GetSaveMemory(), ndsSaveLen);
|
|
NdsSaveRamIsDirty = false;
|
|
}
|
|
|
|
if (gbaSaveLen)
|
|
{
|
|
memcpy(data + ndsSaveLen, GBACart::GetSaveMemory(), gbaSaveLen);
|
|
GbaSaveRamIsDirty = false;
|
|
}
|
|
}
|
|
|
|
ECL_EXPORT u32 GetSaveRamLength()
|
|
{
|
|
return NDSCart::GetSaveMemoryLength() + GBACart::GetSaveMemoryLength();
|
|
}
|
|
|
|
ECL_EXPORT bool SaveRamIsDirty()
|
|
{
|
|
return NdsSaveRamIsDirty || GbaSaveRamIsDirty;
|
|
}
|
|
|
|
static void ImportTitleData(DSi_NAND::NANDMount& mount, u32 titleId, int which, const char* path, u8** in)
|
|
{
|
|
if (auto file = Platform::OpenFile(path, Platform::FileMode::Write))
|
|
{
|
|
auto len = Platform::FileLength(file);
|
|
Platform::FileRewind(file);
|
|
Platform::FileWrite(*in, len, 1, file);
|
|
Platform::CloseFile(file);
|
|
*in += len;
|
|
}
|
|
|
|
mount.ImportTitleData(DSIWARE_CATEGORY, titleId, which, path);
|
|
}
|
|
|
|
ECL_EXPORT void ImportDSiWareSavs(u32 titleId, u8* data)
|
|
{
|
|
auto& nand = DSi::NANDImage;
|
|
if (nand && *nand)
|
|
{
|
|
if (auto mount = DSi_NAND::NANDMount(*nand))
|
|
{
|
|
ImportTitleData(mount, titleId, DSi_NAND::TitleData_PublicSav, "public.sav", &data);
|
|
ImportTitleData(mount, titleId, DSi_NAND::TitleData_PrivateSav, "private.sav", &data);
|
|
ImportTitleData(mount, titleId, DSi_NAND::TitleData_BannerSav, "banner.sav", &data);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void ExportTitleData(DSi_NAND::NANDMount& mount, u32 titleId, int which, const char* path, u8** out)
|
|
{
|
|
mount.ExportTitleData(DSIWARE_CATEGORY, titleId, which, path);
|
|
|
|
if (auto file = Platform::OpenFile(path, Platform::FileMode::Read))
|
|
{
|
|
auto len = Platform::FileLength(file);
|
|
Platform::FileRewind(file);
|
|
Platform::FileRead(*out, len, 1, file);
|
|
Platform::CloseFile(file);
|
|
*out += len;
|
|
}
|
|
}
|
|
|
|
ECL_EXPORT void ExportDSiWareSavs(u32 titleId, u8* data)
|
|
{
|
|
auto& nand = DSi::NANDImage;
|
|
if (nand && *nand)
|
|
{
|
|
if (auto mount = DSi_NAND::NANDMount(*nand))
|
|
{
|
|
ExportTitleData(mount, titleId, DSi_NAND::TitleData_PublicSav, "public.sav", &data);
|
|
ExportTitleData(mount, titleId, DSi_NAND::TitleData_PrivateSav, "private.sav", &data);
|
|
ExportTitleData(mount, titleId, DSi_NAND::TitleData_BannerSav, "banner.sav", &data);
|
|
}
|
|
}
|
|
}
|
|
|
|
ECL_EXPORT void DSiWareSavsLength(u32 titleId, u32* publicSavSize, u32* privateSavSize, u32* bannerSavSize)
|
|
{
|
|
*publicSavSize = *privateSavSize = *bannerSavSize = 0;
|
|
|
|
auto& nand = DSi::NANDImage;
|
|
if (nand && *nand)
|
|
{
|
|
if (auto mount = DSi_NAND::NANDMount(*nand))
|
|
{
|
|
u32 version;
|
|
NDSHeader header{};
|
|
|
|
mount.GetTitleInfo(DSIWARE_CATEGORY, titleId, version, &header, nullptr);
|
|
*publicSavSize = header.DSiPublicSavSize;
|
|
*privateSavSize = header.DSiPrivateSavSize;
|
|
*bannerSavSize = (header.AppFlags & 0x04) ? 0x4000 : 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO - I don't like this approach with NAND
|
|
// Perhaps instead it would be better to use FileFlush to write to disk
|
|
// (guarded by frontend determinism switch, of course)
|
|
|
|
ECL_EXPORT u32 GetNANDSize()
|
|
{
|
|
auto& nand = DSi::NANDImage;
|
|
if (nand && *nand)
|
|
{
|
|
return nand->GetLength();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
ECL_EXPORT void GetNANDData(u8* buf)
|
|
{
|
|
auto& nand = DSi::NANDImage;
|
|
if (nand && *nand)
|
|
{
|
|
auto len = nand->GetLength();
|
|
auto file = nand->GetFile();
|
|
Platform::FileRewind(file);
|
|
Platform::FileRead(buf, 1, len, file);
|
|
}
|
|
}
|
|
|
|
void WriteNDSSave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
|
|
{
|
|
NdsSaveRamIsDirty = true;
|
|
}
|
|
|
|
void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen)
|
|
{
|
|
GbaSaveRamIsDirty = true;
|
|
}
|
|
|
|
void WriteFirmware(const SPI_Firmware::Firmware& firmware, u32 writeoffset, u32 writelen)
|
|
{
|
|
}
|
|
|
|
void WriteDateTime(int year, int month, int day, int hour, int minute, int second)
|
|
{
|
|
}
|
|
|
|
}
|