Assorted portability enhancements (#1800)

* Introduce some Platform calls for managing dynamic libraries

* Add Platform::WriteFATSectors

* Introduce some Platform calls for managing dynamic libraries

* Add Platform::WriteFATSectors

* Change includes of "../types.h" to "types.h"

- Makes it easier to directly include these headers in downstream projects

* Change an include of "../Wifi.h" to "Wifi.h"

* Allow CommonFuncs.cpp to compile on Android

* Tidy up some logging calls

- Use Platform::Log in LAN_Socket.cpp
- Soften some warnings to Debug logs (since they don't necessarily represent problems)

* Add Platform::EnterGBAMode

- Gracefully stop the emulator if trying to enter GBA mode

* Soften some logs that most players won't care about

* Soften some more logs

* Introduce Platform wrappers for file operations

* Fix pointer spacing

* Fix more style nits

* Log the errno when ftruncate fails

* Fix FileSeek offset argument

- With an s32 offset, we couldn't access files larger than 2GB

* Revise Platform::StopEmu to address feedback

- Remove Platform::EnterGBAMode in favor of adding a reason to Platform::StopEmu
- Also rename Platform::StopEmu to Platform::SignalStop
- Add an optional argument to NDS::Stop
- Use the new argument everywhere that the console stops itself

* Rename FileGetString to FileReadLine

- It conveys the meaning better

* Rename FileSeekOrigin::Set to Start

- It conveys the meaning better

* Change definition of FileGetString to FileReadLine

- Oops, almost forgot it

* Rename FlushFile to FileFlush

- To remain consistent with the other File functions

* Add a FileType usage

* Fix line break in FileSeekOrigin

* Document Platform::DeInit

* Clarify that StopReason::Unknown doesn't always mean an error

* Move and document FileType::HostFile

* Remove Platform::OpenDataFile

- Nothing currently uses it

* Refactor Platform::OpenFile and Platform::OpenLocalFile to accept a FileMode enum instead of a string

- The enum is converted to fopen flags under the hood
- The file type is used to decide whether to add the "b" flag
- Some helper functions are exposed for the benefit of consistent behavior among frontends
- Equivalent behavior is maintained

* Fix a tab that should be spaces

* Use Windows' 64-bit implementations of fseek/ftell

* Move Platform::IsBinaryFile to Platform.cpp

- It could vary by frontend

* Remove an unused FileType

* Rename an enum constant

* Document various Platform items

* Use Platform::DynamicLibrary to load libandroid

- And clean it up at the end

* Fix a typo

* Pass the correct filetype to FATStorage

- Since it can be used for DSI NAND images or for SD cards

* Remove Platform::FileType
This commit is contained in:
Jesse Talavera-Greenberg 2023-08-18 16:50:57 -04:00 committed by GitHub
parent f454eba3c3
commit ee55677086
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 787 additions and 443 deletions

View File

@ -21,8 +21,7 @@
#include "ARCodeFile.h" #include "ARCodeFile.h"
#include "Platform.h" #include "Platform.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
// TODO: import codes from other sources (usrcheat.dat, ...) // TODO: import codes from other sources (usrcheat.dat, ...)
// TODO: more user-friendly error reporting // TODO: more user-friendly error reporting
@ -47,7 +46,7 @@ ARCodeFile::~ARCodeFile()
bool ARCodeFile::Load() bool ARCodeFile::Load()
{ {
FILE* f = Platform::OpenFile(Filename, "r"); FileHandle* f = OpenFile(Filename, FileMode::ReadText);
if (!f) return true; if (!f) return true;
Categories.clear(); Categories.clear();
@ -59,9 +58,9 @@ bool ARCodeFile::Load()
ARCode curcode; ARCode curcode;
char linebuf[1024]; char linebuf[1024];
while (!feof(f)) while (!IsEndOfFile(f))
{ {
if (fgets(linebuf, 1024, f) == nullptr) if (!FileReadLine(linebuf, 1024, f))
break; break;
linebuf[1023] = '\0'; linebuf[1023] = '\0';
@ -82,7 +81,7 @@ bool ARCodeFile::Load()
if (ret < 1) if (ret < 1)
{ {
Log(LogLevel::Error, "AR: malformed CAT line: %s\n", start); Log(LogLevel::Error, "AR: malformed CAT line: %s\n", start);
fclose(f); CloseFile(f);
return false; return false;
} }
@ -105,14 +104,14 @@ bool ARCodeFile::Load()
if (ret < 2) if (ret < 2)
{ {
Log(LogLevel::Error, "AR: malformed CODE line: %s\n", start); Log(LogLevel::Error, "AR: malformed CODE line: %s\n", start);
fclose(f); CloseFile(f);
return false; return false;
} }
if (!isincat) if (!isincat)
{ {
Log(LogLevel::Error, "AR: encountered CODE line with no category started\n"); Log(LogLevel::Error, "AR: encountered CODE line with no category started\n");
fclose(f); CloseFile(f);
return false; return false;
} }
@ -131,21 +130,21 @@ bool ARCodeFile::Load()
if (ret < 2) if (ret < 2)
{ {
Log(LogLevel::Error, "AR: malformed data line: %s\n", start); Log(LogLevel::Error, "AR: malformed data line: %s\n", start);
fclose(f); CloseFile(f);
return false; return false;
} }
if (!isincode) if (!isincode)
{ {
Log(LogLevel::Error, "AR: encountered data line with no code started\n"); Log(LogLevel::Error, "AR: encountered data line with no code started\n");
fclose(f); CloseFile(f);
return false; return false;
} }
if (curcode.CodeLen >= 2*64) if (curcode.CodeLen >= 2*64)
{ {
Log(LogLevel::Error, "AR: code too long!\n"); Log(LogLevel::Error, "AR: code too long!\n");
fclose(f); CloseFile(f);
return false; return false;
} }
@ -159,36 +158,36 @@ bool ARCodeFile::Load()
if (isincode) curcat.Codes.push_back(curcode); if (isincode) curcat.Codes.push_back(curcode);
if (isincat) Categories.push_back(curcat); if (isincat) Categories.push_back(curcat);
fclose(f); CloseFile(f);
return true; return true;
} }
bool ARCodeFile::Save() bool ARCodeFile::Save()
{ {
FILE* f = Platform::OpenFile(Filename, "w"); FileHandle* f = Platform::OpenFile(Filename, FileMode::WriteText);
if (!f) return false; if (!f) return false;
for (ARCodeCatList::iterator it = Categories.begin(); it != Categories.end(); it++) for (ARCodeCatList::iterator it = Categories.begin(); it != Categories.end(); it++)
{ {
ARCodeCat& cat = *it; ARCodeCat& cat = *it;
if (it != Categories.begin()) fprintf(f, "\r\n"); if (it != Categories.begin()) FileWriteFormatted(f, "\r\n");
fprintf(f, "CAT %s\r\n\r\n", cat.Name.c_str()); FileWriteFormatted(f, "CAT %s\r\n\r\n", cat.Name.c_str());
for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++) for (ARCodeList::iterator jt = cat.Codes.begin(); jt != cat.Codes.end(); jt++)
{ {
ARCode& code = *jt; ARCode& code = *jt;
fprintf(f, "CODE %d %s\r\n", code.Enabled, code.Name.c_str()); FileWriteFormatted(f, "CODE %d %s\r\n", code.Enabled, code.Name.c_str());
for (u32 i = 0; i < code.CodeLen; i+=2) for (u32 i = 0; i < code.CodeLen; i+=2)
{ {
fprintf(f, "%08X %08X\r\n", code.Code[i], code.Code[i+1]); FileWriteFormatted(f, "%08X %08X\r\n", code.Code[i], code.Code[i + 1]);
} }
fprintf(f, "\r\n"); FileWriteFormatted(f, "\r\n");
} }
} }
fclose(f); CloseFile(f);
return true; return true;
} }

View File

@ -548,7 +548,7 @@ void ARMv5::PrefetchAbort()
if (!(PU_Map[ExceptionBase>>12] & 0x04)) if (!(PU_Map[ExceptionBase>>12] & 0x04))
{ {
Log(LogLevel::Error, "!!!!! EXCEPTION REGION NOT EXECUTABLE. THIS IS VERY BAD!!\n"); Log(LogLevel::Error, "!!!!! EXCEPTION REGION NOT EXECUTABLE. THIS IS VERY BAD!!\n");
NDS::Stop(); NDS::Stop(Platform::StopReason::BadExceptionRegion);
return; return;
} }

View File

@ -112,6 +112,7 @@ bool FaultHandler(FaultDescription& faultDesc);
#if defined(__ANDROID__) #if defined(__ANDROID__)
#define ASHMEM_DEVICE "/dev/ashmem" #define ASHMEM_DEVICE "/dev/ashmem"
Platform::DynamicLibrary* Libandroid = nullptr;
#endif #endif
#if defined(__SWITCH__) #if defined(__SWITCH__)
@ -753,14 +754,13 @@ void Init()
MemoryBase = MemoryBase + AddrSpaceSize*2; MemoryBase = MemoryBase + AddrSpaceSize*2;
#if defined(__ANDROID__) #if defined(__ANDROID__)
static void* libandroid = dlopen("libandroid.so", RTLD_LAZY | RTLD_LOCAL); Libandroid = Platform::DynamicLibrary_Load("libandroid.so");
using type_ASharedMemory_create = int(*)(const char* name, size_t size); using type_ASharedMemory_create = int(*)(const char* name, size_t size);
static void* symbol = dlsym(libandroid, "ASharedMemory_create"); auto ASharedMemory_create = reinterpret_cast<type_ASharedMemory_create>(Platform::DynamicLibrary_LoadFunction(Libandroid, "ASharedMemory_create"));
static auto shared_memory_create = reinterpret_cast<type_ASharedMemory_create>(symbol);
if (shared_memory_create) if (ASharedMemory_create)
{ {
MemoryFile = shared_memory_create("melondsfastmem", MemoryTotalSize); MemoryFile = ASharedMemory_create("melondsfastmem", MemoryTotalSize);
} }
else else
{ {
@ -775,13 +775,13 @@ void Init()
MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600); MemoryFile = shm_open(fastmemPidName, O_RDWR | O_CREAT | O_EXCL, 0600);
if (MemoryFile == -1) if (MemoryFile == -1)
{ {
Log(LogLevel::Error, "Failed to open memory using shm_open!"); Log(LogLevel::Error, "Failed to open memory using shm_open! (%s)", strerror(errno));
} }
shm_unlink(fastmemPidName); shm_unlink(fastmemPidName);
#endif #endif
if (ftruncate(MemoryFile, MemoryTotalSize) < 0) if (ftruncate(MemoryFile, MemoryTotalSize) < 0)
{ {
Log(LogLevel::Error, "Failed to allocate memory using ftruncate!"); Log(LogLevel::Error, "Failed to allocate memory using ftruncate! (%s)", strerror(errno));
} }
struct sigaction sa; struct sigaction sa;
@ -830,6 +830,15 @@ void DeInit()
munmap(MemoryBase, MemoryTotalSize); munmap(MemoryBase, MemoryTotalSize);
close(MemoryFile); close(MemoryFile);
#if defined(__ANDROID__)
if (Libandroid)
{
Platform::DynamicLibrary_Unload(Libandroid);
Libandroid = nullptr;
}
#endif
#endif #endif
} }

View File

@ -668,7 +668,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
return; return;
if ((id & 0xF00) != 0x700) if ((id & 0xF00) != 0x700)
Log(LogLevel::Warn, "unknown CP15 write op %03X %08X\n", id, val); Log(LogLevel::Debug, "unknown CP15 write op %03X %08X\n", id, val);
} }
u32 ARMv5::CP15Read(u32 id) u32 ARMv5::CP15Read(u32 id)
@ -764,7 +764,7 @@ u32 ARMv5::CP15Read(u32 id)
if ((id & 0xF00) == 0xF00) // test/debug shit? if ((id & 0xF00) == 0xF00) // test/debug shit?
return 0; return 0;
Log(LogLevel::Warn, "unknown CP15 read op %03X\n", id); Log(LogLevel::Debug, "unknown CP15 read op %03X\n", id);
return 0; return 0;
} }

View File

@ -43,8 +43,7 @@
#include "tiny-AES-c/aes.hpp" #include "tiny-AES-c/aes.hpp"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
namespace DSi namespace DSi
{ {
@ -719,13 +718,13 @@ void SoftReset()
bool LoadBIOS() bool LoadBIOS()
{ {
FILE* f; Platform::FileHandle* f;
u32 i; u32 i;
memset(ARM9iBIOS, 0, 0x10000); memset(ARM9iBIOS, 0, 0x10000);
memset(ARM7iBIOS, 0, 0x10000); memset(ARM7iBIOS, 0, 0x10000);
f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_BIOS9Path), "rb"); f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_BIOS9Path), FileMode::Read);
if (!f) if (!f)
{ {
Log(LogLevel::Warn, "ARM9i BIOS not found\n"); Log(LogLevel::Warn, "ARM9i BIOS not found\n");
@ -735,14 +734,14 @@ bool LoadBIOS()
} }
else else
{ {
fseek(f, 0, SEEK_SET); FileRewind(f);
fread(ARM9iBIOS, 0x10000, 1, f); FileRead(ARM9iBIOS, 0x10000, 1, f);
Log(LogLevel::Info, "ARM9i BIOS loaded\n"); Log(LogLevel::Info, "ARM9i BIOS loaded\n");
fclose(f); Platform::CloseFile(f);
} }
f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_BIOS7Path), "rb"); f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::DSi_BIOS7Path), FileMode::Read);
if (!f) if (!f)
{ {
Log(LogLevel::Warn, "ARM7i BIOS not found\n"); Log(LogLevel::Warn, "ARM7i BIOS not found\n");
@ -754,11 +753,11 @@ bool LoadBIOS()
{ {
// TODO: check if the first 32 bytes are crapoed // TODO: check if the first 32 bytes are crapoed
fseek(f, 0, SEEK_SET); FileRewind(f);
fread(ARM7iBIOS, 0x10000, 1, f); FileRead(ARM7iBIOS, 0x10000, 1, f);
Log(LogLevel::Info, "ARM7i BIOS loaded\n"); Log(LogLevel::Info, "ARM7i BIOS loaded\n");
fclose(f); CloseFile(f);
} }
if (!Platform::GetConfigBool(Platform::DSi_FullBIOSBoot)) if (!Platform::GetConfigBool(Platform::DSi_FullBIOSBoot))
@ -785,7 +784,7 @@ bool LoadNAND()
return false; return false;
} }
FILE* nand = DSi_NAND::GetFile(); FileHandle* nand = DSi_NAND::GetFile();
// Make sure NWRAM is accessible. // Make sure NWRAM is accessible.
// The Bits are set to the startup values in Reset() and we might // The Bits are set to the startup values in Reset() and we might
@ -829,8 +828,8 @@ bool LoadNAND()
} }
else else
{ {
fseek(nand, 0x220, SEEK_SET); FileSeek(nand, 0x220, FileSeekOrigin::Start);
fread(bootparams, 4, 8, nand); FileRead(bootparams, 4, 8, nand);
Log(LogLevel::Debug, "ARM9: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n", Log(LogLevel::Debug, "ARM9: offset=%08X size=%08X RAM=%08X size_aligned=%08X\n",
bootparams[0], bootparams[1], bootparams[2], bootparams[3]); bootparams[0], bootparams[1], bootparams[2], bootparams[3]);
@ -843,8 +842,8 @@ bool LoadNAND()
MBK[1][8] = 0; MBK[1][8] = 0;
u32 mbk[12]; u32 mbk[12];
fseek(nand, 0x380, SEEK_SET); FileSeek(nand, 0x380, FileSeekOrigin::Start);
fread(mbk, 4, 12, nand); FileRead(mbk, 4, 12, nand);
MapNWRAM_A(0, mbk[0] & 0xFF); MapNWRAM_A(0, mbk[0] & 0xFF);
MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF); MapNWRAM_A(1, (mbk[0] >> 8) & 0xFF);
@ -898,12 +897,12 @@ bool LoadNAND()
AES_init_ctx_iv(&ctx, boot2key, boot2iv); AES_init_ctx_iv(&ctx, boot2key, boot2iv);
fseek(nand, bootparams[0], SEEK_SET); FileSeek(nand, bootparams[0], FileSeekOrigin::Start);
dstaddr = bootparams[2]; dstaddr = bootparams[2];
for (u32 i = 0; i < bootparams[3]; i += 16) for (u32 i = 0; i < bootparams[3]; i += 16)
{ {
u8 data[16]; u8 data[16];
fread(data, 16, 1, nand); FileRead(data, 16, 1, nand);
for (int j = 0; j < 16; j++) tmp[j] = data[15-j]; for (int j = 0; j < 16; j++) tmp[j] = data[15-j];
AES_CTR_xcrypt_buffer(&ctx, tmp, 16); AES_CTR_xcrypt_buffer(&ctx, tmp, 16);
@ -923,12 +922,12 @@ bool LoadNAND()
AES_init_ctx_iv(&ctx, boot2key, boot2iv); AES_init_ctx_iv(&ctx, boot2key, boot2iv);
fseek(nand, bootparams[4], SEEK_SET); FileSeek(nand, bootparams[4], FileSeekOrigin::Start);
dstaddr = bootparams[6]; dstaddr = bootparams[6];
for (u32 i = 0; i < bootparams[7]; i += 16) for (u32 i = 0; i < bootparams[7]; i += 16)
{ {
u8 data[16]; u8 data[16];
fread(data, 16, 1, nand); FileRead(data, 16, 1, nand);
for (int j = 0; j < 16; j++) tmp[j] = data[15-j]; for (int j = 0; j < 16; j++) tmp[j] = data[15-j];
AES_CTR_xcrypt_buffer(&ctx, tmp, 16); AES_CTR_xcrypt_buffer(&ctx, tmp, 16);

View File

@ -247,7 +247,7 @@ u8 Read8(u32 addr)
{ {
// //
Log(LogLevel::Warn, "unknown DSi cam read8 %08X\n", addr); Log(LogLevel::Debug, "unknown DSi cam read8 %08X\n", addr);
return 0; return 0;
} }
@ -259,7 +259,7 @@ u16 Read16(u32 addr)
case 0x04004202: return Cnt; case 0x04004202: return Cnt;
} }
Log(LogLevel::Warn, "unknown DSi cam read16 %08X\n", addr); Log(LogLevel::Debug, "unknown DSi cam read16 %08X\n", addr);
return 0; return 0;
} }
@ -285,7 +285,7 @@ u32 Read32(u32 addr)
case 0x04004214: return CropEnd; case 0x04004214: return CropEnd;
} }
Log(LogLevel::Warn, "unknown DSi cam read32 %08X\n", addr); Log(LogLevel::Debug, "unknown DSi cam read32 %08X\n", addr);
return 0; return 0;
} }
@ -293,7 +293,7 @@ void Write8(u32 addr, u8 val)
{ {
// //
Log(LogLevel::Warn, "unknown DSi cam write8 %08X %02X\n", addr, val); Log(LogLevel::Debug, "unknown DSi cam write8 %08X %02X\n", addr, val);
} }
void Write16(u32 addr, u16 val) void Write16(u32 addr, u16 val)
@ -372,7 +372,7 @@ void Write16(u32 addr, u16 val)
return; return;
} }
Log(LogLevel::Warn, "unknown DSi cam write16 %08X %04X\n", addr, val); Log(LogLevel::Debug, "unknown DSi cam write16 %08X %04X\n", addr, val);
} }
void Write32(u32 addr, u32 val) void Write32(u32 addr, u32 val)
@ -389,7 +389,7 @@ void Write32(u32 addr, u32 val)
return; return;
} }
Log(LogLevel::Warn, "unknown DSi cam write32 %08X %08X\n", addr, val); Log(LogLevel::Debug, "unknown DSi cam write32 %08X %08X\n", addr, val);
} }
@ -638,7 +638,7 @@ u16 Camera::I2C_ReadReg(u16 addr)
case 0x301A: return ((~StandbyCnt) & 0x4000) >> 12; case 0x301A: return ((~StandbyCnt) & 0x4000) >> 12;
} }
if(Num==1) Log(LogLevel::Warn, "DSi_Camera%d: unknown read %04X\n", Num, addr); if(Num==1) Log(LogLevel::Debug, "DSi_Camera%d: unknown read %04X\n", Num, addr);
return 0; return 0;
} }
@ -704,7 +704,7 @@ void Camera::I2C_WriteReg(u16 addr, u16 val)
return; return;
} }
if(Num==1) Log(LogLevel::Warn, "DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val); if(Num==1) Log(LogLevel::Debug, "DSi_Camera%d: unknown write %04X %04X\n", Num, addr, val);
} }

View File

@ -199,7 +199,7 @@ void DoHardwareReset(bool direct)
void DoShutdown() void DoShutdown()
{ {
ResetButtonState(); ResetButtonState();
NDS::Stop(); NDS::Stop(Platform::StopReason::PowerOff);
} }

View File

@ -29,13 +29,12 @@
#include "fatfs/ff.h" #include "fatfs/ff.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
namespace DSi_NAND namespace DSi_NAND
{ {
FILE* CurFile; FileHandle* CurFile;
FATFS CurFS; FATFS CurFS;
u8 eMMC_CID[16]; u8 eMMC_CID[16];
@ -58,21 +57,19 @@ bool Init(u8* es_keyY)
std::string nandpath = Platform::GetConfigString(Platform::DSi_NANDPath); std::string nandpath = Platform::GetConfigString(Platform::DSi_NANDPath);
std::string instnand = nandpath + Platform::InstanceFileSuffix(); std::string instnand = nandpath + Platform::InstanceFileSuffix();
FILE* nandfile = Platform::OpenLocalFile(instnand, "r+b"); FileHandle* nandfile = Platform::OpenLocalFile(instnand, FileMode::ReadWriteExisting);
if ((!nandfile) && (Platform::InstanceID() > 0)) if ((!nandfile) && (Platform::InstanceID() > 0))
{ {
FILE* orig = Platform::OpenLocalFile(nandpath, "rb"); FileHandle* orig = Platform::OpenLocalFile(nandpath, FileMode::Read);
if (!orig) if (!orig)
{ {
Log(LogLevel::Error, "Failed to open DSi NAND\n"); Log(LogLevel::Error, "Failed to open DSi NAND\n");
return false; return false;
} }
fseek(orig, 0, SEEK_END); long len = FileLength(orig);
long len = ftell(orig);
fseek(orig, 0, SEEK_SET);
nandfile = Platform::OpenLocalFile(instnand, "w+b"); nandfile = Platform::OpenLocalFile(instnand, FileMode::ReadWrite);
if (nandfile) if (nandfile)
{ {
u8* tmpbuf = new u8[0x10000]; u8* tmpbuf = new u8[0x10000];
@ -81,23 +78,22 @@ bool Init(u8* es_keyY)
long blklen = 0x10000; long blklen = 0x10000;
if ((i+blklen) > len) blklen = len-i; if ((i+blklen) > len) blklen = len-i;
fread(tmpbuf, blklen, 1, orig); FileRead(tmpbuf, blklen, 1, orig);
fwrite(tmpbuf, blklen, 1, nandfile); FileWrite(tmpbuf, blklen, 1, nandfile);
} }
delete[] tmpbuf; delete[] tmpbuf;
} }
fclose(orig); Platform::CloseFile(orig);
fclose(nandfile); Platform::CloseFile(nandfile);
nandfile = Platform::OpenLocalFile(instnand, "r+b"); nandfile = Platform::OpenLocalFile(instnand, FileMode::ReadWriteExisting);
} }
if (!nandfile) if (!nandfile)
return false; return false;
fseek(nandfile, 0, SEEK_END); u64 nandlen = FileLength(nandfile);
u64 nandlen = ftell(nandfile);
ff_disk_open(FF_ReadNAND, FF_WriteNAND, (LBA_t)(nandlen>>9)); ff_disk_open(FF_ReadNAND, FF_WriteNAND, (LBA_t)(nandlen>>9));
@ -113,18 +109,18 @@ bool Init(u8* es_keyY)
// read the nocash footer // read the nocash footer
fseek(nandfile, -0x40, SEEK_END); FileSeek(nandfile, -0x40, FileSeekOrigin::End);
char nand_footer[16]; char nand_footer[16];
const char* nand_footer_ref = "DSi eMMC CID/CPU"; const char* nand_footer_ref = "DSi eMMC CID/CPU";
fread(nand_footer, 1, 16, nandfile); FileRead(nand_footer, 1, 16, nandfile);
if (memcmp(nand_footer, nand_footer_ref, 16)) if (memcmp(nand_footer, nand_footer_ref, 16))
{ {
// There is another copy of the footer at 000FF800h for the case // There is another copy of the footer at 000FF800h for the case
// that by external tools the image was cut off // that by external tools the image was cut off
// See https://problemkaputt.de/gbatek.htm#dsisdmmcimages // See https://problemkaputt.de/gbatek.htm#dsisdmmcimages
fseek(nandfile, 0x000FF800, SEEK_SET); FileSeek(nandfile, 0x000FF800, FileSeekOrigin::Start);
fread(nand_footer, 1, 16, nandfile); FileRead(nand_footer, 1, 16, nandfile);
if (memcmp(nand_footer, nand_footer_ref, 16)) if (memcmp(nand_footer, nand_footer_ref, 16))
{ {
Log(LogLevel::Error, "ERROR: NAND missing nocash footer\n"); Log(LogLevel::Error, "ERROR: NAND missing nocash footer\n");
@ -132,8 +128,8 @@ bool Init(u8* es_keyY)
} }
} }
fread(eMMC_CID, 1, 16, nandfile); FileRead(eMMC_CID, 1, 16, nandfile);
fread(&ConsoleID, 1, 8, nandfile); FileRead(&ConsoleID, 1, 8, nandfile);
// init NAND crypto // init NAND crypto
@ -180,12 +176,12 @@ void DeInit()
f_unmount("0:"); f_unmount("0:");
ff_disk_close(); ff_disk_close();
if (CurFile) fclose(CurFile); if (CurFile) CloseFile(CurFile);
CurFile = nullptr; CurFile = nullptr;
} }
FILE* GetFile() FileHandle* GetFile()
{ {
return CurFile; return CurFile;
} }
@ -229,8 +225,8 @@ u32 ReadFATBlock(u64 addr, u32 len, u8* buf)
AES_ctx ctx; AES_ctx ctx;
SetupFATCrypto(&ctx, ctr); SetupFATCrypto(&ctx, ctr);
fseek(CurFile, addr, SEEK_SET); FileSeek(CurFile, addr, FileSeekOrigin::Start);
u32 res = fread(buf, len, 1, CurFile); u32 res = FileRead(buf, len, 1, CurFile);
if (!res) return 0; if (!res) return 0;
for (u32 i = 0; i < len; i += 16) for (u32 i = 0; i < len; i += 16)
@ -251,7 +247,7 @@ u32 WriteFATBlock(u64 addr, u32 len, u8* buf)
AES_ctx ctx; AES_ctx ctx;
SetupFATCrypto(&ctx, ctr); SetupFATCrypto(&ctx, ctr);
fseek(CurFile, addr, SEEK_SET); FileSeek(CurFile, addr, FileSeekOrigin::Start);
for (u32 s = 0; s < len; s += 0x200) for (u32 s = 0; s < len; s += 0x200)
{ {
@ -265,7 +261,7 @@ u32 WriteFATBlock(u64 addr, u32 len, u8* buf)
DSi_AES::Swap16(&tempbuf[i], tmp); DSi_AES::Swap16(&tempbuf[i], tmp);
} }
u32 res = fwrite(tempbuf, 0x200, 1, CurFile); u32 res = FileWrite(tempbuf, sizeof(tempbuf), 1, CurFile);
if (!res) return 0; if (!res) return 0;
} }

View File

@ -38,7 +38,7 @@ enum
bool Init(u8* es_keyY); bool Init(u8* es_keyY);
void DeInit(); void DeInit();
FILE* GetFile(); Platform::FileHandle* GetFile();
void GetIDs(u8* emmc_cid, u64& consoleid); void GetIDs(u8* emmc_cid, u64& consoleid);

View File

@ -356,7 +356,7 @@ u8 DSi_NWifi::F0_Read(u32 addr)
return CIS1[addr & 0xFF]; return CIS1[addr & 0xFF];
} }
Log(LogLevel::Warn, "NWIFI: unknown func0 read %05X\n", addr); Log(LogLevel::Debug, "NWIFI: unknown func0 read %05X\n", addr);
return 0; return 0;
} }
@ -370,7 +370,7 @@ void DSi_NWifi::F0_Write(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "NWIFI: unknown func0 write %05X %02X\n", addr, val); Log(LogLevel::Debug, "NWIFI: unknown func0 write %05X %02X\n", addr, val);
} }
@ -582,7 +582,7 @@ void DSi_NWifi::F1_Write(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "NWIFI: unknown func1 write %05X %02X\n", addr, val); Log(LogLevel::Debug, "NWIFI: unknown func1 write %05X %02X\n", addr, val);
} }
@ -594,7 +594,7 @@ u8 DSi_NWifi::SDIO_Read(u32 func, u32 addr)
case 1: return F1_Read(addr); case 1: return F1_Read(addr);
} }
Log(LogLevel::Warn, "NWIFI: unknown SDIO read %d %05X\n", func, addr); Log(LogLevel::Debug, "NWIFI: unknown SDIO read %d %05X\n", func, addr);
return 0; return 0;
} }
@ -606,7 +606,7 @@ void DSi_NWifi::SDIO_Write(u32 func, u32 addr, u8 val)
case 1: return F1_Write(addr, val); case 1: return F1_Write(addr, val);
} }
Log(LogLevel::Warn, "NWIFI: unknown SDIO write %d %05X %02X\n", func, addr, val); Log(LogLevel::Debug, "NWIFI: unknown SDIO write %d %05X %02X\n", func, addr, val);
} }
@ -874,7 +874,7 @@ void DSi_NWifi::HTC_Command()
{ {
u16 svc_id = MB_Read16(0); u16 svc_id = MB_Read16(0);
u16 conn_flags = MB_Read16(0); u16 conn_flags = MB_Read16(0);
Log(LogLevel::Info, "service connect %04X %04X %04X\n", svc_id, conn_flags, MB_Read16(0)); Log(LogLevel::Debug, "service connect %04X %04X %04X\n", svc_id, conn_flags, MB_Read16(0));
u8 svc_resp[8]; u8 svc_resp[8];
// responses from hardware: // responses from hardware:
@ -952,7 +952,7 @@ void DSi_NWifi::WMI_Command()
if (ConnectionStatus != 1) if (ConnectionStatus != 1)
Log(LogLevel::Warn, "WMI: ?? trying to disconnect while not connected\n"); Log(LogLevel::Warn, "WMI: ?? trying to disconnect while not connected\n");
Log(LogLevel::Info, "WMI: disconnect\n"); Log(LogLevel::Debug, "WMI: disconnect\n");
ConnectionStatus = 0; ConnectionStatus = 0;
u8 reply[11]; u8 reply[11];
@ -1218,7 +1218,7 @@ void DSi_NWifi::WMI_ConnectToNetwork()
return; return;
} }
Log(LogLevel::Info, "WMI: connecting to network %s\n", ssid); Log(LogLevel::Debug, "WMI: connecting to network %s\n", ssid);
u8 reply[20]; u8 reply[20];

View File

@ -23,8 +23,7 @@
#include "DSi_NWifi.h" #include "DSi_NWifi.h"
#include "Platform.h" #include "Platform.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
// observed IRQ behavior during transfers // observed IRQ behavior during transfers
// //
@ -773,7 +772,7 @@ DSi_MMCStorage::DSi_MMCStorage(DSi_SDHost* host, bool internal, const std::strin
: DSi_SDDevice(host) : DSi_SDDevice(host)
{ {
Internal = internal; Internal = internal;
File = Platform::OpenLocalFile(filename, "r+b"); File = Platform::OpenLocalFile(filename, FileMode::ReadWriteExisting);
SD = nullptr; SD = nullptr;
@ -801,7 +800,7 @@ DSi_MMCStorage::~DSi_MMCStorage()
} }
if (File) if (File)
{ {
fclose(File); CloseFile(File);
} }
} }
@ -926,7 +925,7 @@ void DSi_MMCStorage::SendCMD(u8 cmd, u32 param)
case 12: // stop operation case 12: // stop operation
SetState(0x04); SetState(0x04);
if (File) fflush(File); if (File) FileFlush(File);
RWCommand = 0; RWCommand = 0;
Host->SendResponse(CSR, true); Host->SendResponse(CSR, true);
return; return;
@ -1055,8 +1054,8 @@ u32 DSi_MMCStorage::ReadBlock(u64 addr)
} }
else if (File) else if (File)
{ {
fseek(File, addr, SEEK_SET); FileSeek(File, addr, FileSeekOrigin::Start);
fread(&data[addr & 0x1FF], 1, len, File); FileRead(&data[addr & 0x1FF], 1, len, File);
} }
return Host->DataRX(&data[addr & 0x1FF], len); return Host->DataRX(&data[addr & 0x1FF], len);
@ -1085,8 +1084,8 @@ u32 DSi_MMCStorage::WriteBlock(u64 addr)
} }
else if (File) else if (File)
{ {
fseek(File, addr, SEEK_SET); FileSeek(File, addr, FileSeekOrigin::Start);
fwrite(&data[addr & 0x1FF], 1, len, File); FileWrite(&data[addr & 0x1FF], 1, len, File);
} }
} }
} }

View File

@ -142,7 +142,7 @@ public:
private: private:
bool Internal; bool Internal;
FILE* File; Platform::FileHandle* File;
FATStorage* SD; FATStorage* SD;
u8 CID[16]; u8 CID[16];

View File

@ -25,17 +25,7 @@
#include "Platform.h" #include "Platform.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
using namespace Platform;
// really, Windows?
#ifdef __WIN32__
#define melon_fseek _fseeki64
#define melon_ftell _ftelli64
#else
#define melon_fseek fseek
#define melon_ftell ftell
#endif // __WIN32__
FATStorage::FATStorage(const std::string& filename, u64 size, bool readonly, const std::string& sourcedir) FATStorage::FATStorage(const std::string& filename, u64 size, bool readonly, const std::string& sourcedir)
{ {
@ -53,7 +43,7 @@ FATStorage::~FATStorage()
bool FATStorage::Open() bool FATStorage::Open()
{ {
File = Platform::OpenLocalFile(FilePath.c_str(), "r+b"); File = Platform::OpenLocalFile(FilePath, FileMode::ReadWriteExisting);
if (!File) if (!File)
{ {
return false; return false;
@ -64,7 +54,7 @@ bool FATStorage::Open()
void FATStorage::Close() void FATStorage::Close()
{ {
if (File) fclose(File); if (File) CloseFile(File);
File = nullptr; File = nullptr;
} }
@ -124,7 +114,7 @@ u32 FATStorage::WriteSectors(u32 start, u32 num, u8* data)
} }
FILE* FATStorage::FF_File; FileHandle* FATStorage::FF_File;
u64 FATStorage::FF_FileSize; u64 FATStorage::FF_FileSize;
UINT FATStorage::FF_ReadStorage(BYTE* buf, LBA_t sector, UINT num) UINT FATStorage::FF_ReadStorage(BYTE* buf, LBA_t sector, UINT num)
@ -138,7 +128,7 @@ UINT FATStorage::FF_WriteStorage(BYTE* buf, LBA_t sector, UINT num)
} }
u32 FATStorage::ReadSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num, u8* data) u32 FATStorage::ReadSectorsInternal(FileHandle* file, u64 filelen, u32 start, u32 num, u8* data)
{ {
if (!file) return 0; if (!file) return 0;
@ -152,12 +142,12 @@ u32 FATStorage::ReadSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num,
num = len >> 9; num = len >> 9;
} }
melon_fseek(file, addr, SEEK_SET); FileSeek(file, addr, FileSeekOrigin::Start);
u32 res = fread(data, 0x200, num, file); u32 res = FileRead(data, 0x200, num, file);
if (res < num) if (res < num)
{ {
if (feof(file)) if (IsEndOfFile(file))
{ {
memset(&data[0x200*res], 0, 0x200*(num-res)); memset(&data[0x200*res], 0, 0x200*(num-res));
return num; return num;
@ -167,7 +157,7 @@ u32 FATStorage::ReadSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num,
return res; return res;
} }
u32 FATStorage::WriteSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num, u8* data) u32 FATStorage::WriteSectorsInternal(FileHandle* file, u64 filelen, u32 start, u32 num, u8* data)
{ {
if (!file) return 0; if (!file) return 0;
@ -181,9 +171,9 @@ u32 FATStorage::WriteSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num
num = len >> 9; num = len >> 9;
} }
melon_fseek(file, addr, SEEK_SET); FileSeek(file, addr, FileSeekOrigin::Start);
u32 res = fwrite(data, 0x200, num, file); u32 res = Platform::FileWrite(data, 0x200, num, file);
return res; return res;
} }
@ -193,13 +183,13 @@ void FATStorage::LoadIndex()
DirIndex.clear(); DirIndex.clear();
FileIndex.clear(); FileIndex.clear();
FILE* f = Platform::OpenLocalFile(IndexPath.c_str(), "r"); FileHandle* f = OpenLocalFile(IndexPath, FileMode::ReadText);
if (!f) return; if (!f) return;
char linebuf[1536]; char linebuf[1536];
while (!feof(f)) while (!IsEndOfFile(f))
{ {
if (fgets(linebuf, 1536, f) == nullptr) if (!FileReadLine(linebuf, 1536, f))
break; break;
if (linebuf[0] == 'S') if (linebuf[0] == 'S')
@ -258,7 +248,7 @@ void FATStorage::LoadIndex()
} }
} }
fclose(f); CloseFile(f);
// ensure the indexes are sane // ensure the indexes are sane
@ -325,31 +315,31 @@ void FATStorage::LoadIndex()
void FATStorage::SaveIndex() void FATStorage::SaveIndex()
{ {
FILE* f = Platform::OpenLocalFile(IndexPath.c_str(), "w"); FileHandle* f = OpenLocalFile(IndexPath, FileMode::WriteText);
if (!f) return; if (!f) return;
fprintf(f, "SIZE %" PRIu64 "\r\n", FileSize); FileWriteFormatted(f, "SIZE %" PRIu64 "\r\n", FileSize);
for (const auto& [key, val] : DirIndex) for (const auto& [key, val] : DirIndex)
{ {
fprintf(f, "DIR %u %s\r\n", FileWriteFormatted(f, "DIR %u %s\r\n",
val.IsReadOnly?1:0, val.Path.c_str()); val.IsReadOnly?1:0, val.Path.c_str());
} }
for (const auto& [key, val] : FileIndex) for (const auto& [key, val] : FileIndex)
{ {
fprintf(f, "FILE %u %" PRIu64 " %" PRId64 " %u %s\r\n", FileWriteFormatted(f, "FILE %u %" PRIu64 " %" PRId64 " %u %s\r\n",
val.IsReadOnly?1:0, val.Size, val.LastModified, val.LastModifiedInternal, val.Path.c_str()); val.IsReadOnly?1:0, val.Size, val.LastModified, val.LastModifiedInternal, val.Path.c_str());
} }
fclose(f); CloseFile(f);
} }
bool FATStorage::ExportFile(const std::string& path, fs::path out) bool FATStorage::ExportFile(const std::string& path, fs::path out)
{ {
FF_FIL file; FF_FIL file;
FILE* fout; FileHandle* fout;
FRESULT res; FRESULT res;
res = f_open(&file, path.c_str(), FA_OPEN_EXISTING | FA_READ); res = f_open(&file, path.c_str(), FA_OPEN_EXISTING | FA_READ);
@ -367,7 +357,7 @@ bool FATStorage::ExportFile(const std::string& path, fs::path out)
err); err);
} }
fout = Platform::OpenFile(out.u8string().c_str(), "wb"); fout = OpenFile(out.u8string(), FileMode::Write);
if (!fout) if (!fout)
{ {
f_close(&file); f_close(&file);
@ -385,10 +375,10 @@ bool FATStorage::ExportFile(const std::string& path, fs::path out)
u32 nread; u32 nread;
f_read(&file, buf, blocklen, &nread); f_read(&file, buf, blocklen, &nread);
fwrite(buf, blocklen, 1, fout); FileWrite(buf, blocklen, 1, fout);
} }
fclose(fout); CloseFile(fout);
f_close(&file); f_close(&file);
return true; return true;
@ -782,27 +772,25 @@ void FATStorage::CleanupDirectory(const std::string& sourcedir, const std::strin
bool FATStorage::ImportFile(const std::string& path, fs::path in) bool FATStorage::ImportFile(const std::string& path, fs::path in)
{ {
FF_FIL file; FF_FIL file;
FILE* fin; FileHandle* fin;
FRESULT res; FRESULT res;
fin = Platform::OpenFile(in.u8string().c_str(), "rb"); fin = Platform::OpenFile(in.u8string(), FileMode::Read);
if (!fin) if (!fin)
return false; return false;
fseek(fin, 0, SEEK_END); u32 len = FileLength(fin);
u32 len = (u32)ftell(fin);
fseek(fin, 0, SEEK_SET);
if (!CanFitFile(len)) if (!CanFitFile(len))
{ {
fclose(fin); CloseFile(fin);
return false; return false;
} }
res = f_open(&file, path.c_str(), FA_CREATE_ALWAYS | FA_WRITE); res = f_open(&file, path.c_str(), FA_CREATE_ALWAYS | FA_WRITE);
if (res != FR_OK) if (res != FR_OK)
{ {
fclose(fin); CloseFile(fin);
return false; return false;
} }
@ -816,11 +804,11 @@ bool FATStorage::ImportFile(const std::string& path, fs::path in)
blocklen = 0x1000; blocklen = 0x1000;
u32 nwrite; u32 nwrite;
fread(buf, blocklen, 1, fin); FileRead(buf, blocklen, 1, fin);
f_write(&file, buf, blocklen, &nwrite); f_write(&file, buf, blocklen, &nwrite);
} }
fclose(fin); CloseFile(fin);
f_close(&file); f_close(&file);
return true; return true;
@ -961,16 +949,10 @@ bool FATStorage::Load(const std::string& filename, u64 size, const std::string&
// * if no image: if sourcing from a directory, size is calculated from that // * if no image: if sourcing from a directory, size is calculated from that
// with a minimum 128MB extra, otherwise size is defaulted to 512MB // with a minimum 128MB extra, otherwise size is defaulted to 512MB
bool isnew = false; bool isnew = !Platform::LocalFileExists(filename);
FF_File = Platform::OpenLocalFile(filename.c_str(), "r+b"); FF_File = Platform::OpenLocalFile(filename, static_cast<FileMode>(FileMode::ReadWrite | FileMode::Preserve));
if (!FF_File) if (!FF_File)
{ return false;
FF_File = Platform::OpenLocalFile(filename.c_str(), "w+b");
if (!FF_File)
return false;
isnew = true;
}
IndexPath = FilePath + ".idx"; IndexPath = FilePath + ".idx";
if (isnew) if (isnew)
@ -985,8 +967,7 @@ bool FATStorage::Load(const std::string& filename, u64 size, const std::string&
if (FileSize == 0) if (FileSize == 0)
{ {
melon_fseek(FF_File, 0, SEEK_END); FileSize = FileLength(FF_File);
FileSize = melon_ftell(FF_File);
} }
} }
@ -1076,7 +1057,7 @@ bool FATStorage::Load(const std::string& filename, u64 size, const std::string&
f_unmount("0:"); f_unmount("0:");
ff_disk_close(); ff_disk_close();
fclose(FF_File); CloseFile(FF_File);
FF_File = nullptr; FF_File = nullptr;
return true; return true;
@ -1089,7 +1070,7 @@ bool FATStorage::Save()
return true; return true;
} }
FF_File = Platform::OpenLocalFile(FilePath.c_str(), "r+b"); FF_File = Platform::OpenLocalFile(FilePath, FileMode::ReadWriteExisting);
if (!FF_File) if (!FF_File)
{ {
return false; return false;
@ -1105,7 +1086,7 @@ bool FATStorage::Save()
if (res != FR_OK) if (res != FR_OK)
{ {
ff_disk_close(); ff_disk_close();
fclose(FF_File); CloseFile(FF_File);
FF_File = nullptr; FF_File = nullptr;
return false; return false;
} }
@ -1117,7 +1098,7 @@ bool FATStorage::Save()
f_unmount("0:"); f_unmount("0:");
ff_disk_close(); ff_disk_close();
fclose(FF_File); CloseFile(FF_File);
FF_File = nullptr; FF_File = nullptr;
return true; return true;

View File

@ -24,6 +24,7 @@
#include <map> #include <map>
#include <filesystem> #include <filesystem>
#include "Platform.h"
#include "types.h" #include "types.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
@ -48,16 +49,16 @@ private:
std::string SourceDir; std::string SourceDir;
bool ReadOnly; bool ReadOnly;
FILE* File; Platform::FileHandle* File;
u64 FileSize; u64 FileSize;
static FILE* FF_File; static Platform::FileHandle* FF_File;
static u64 FF_FileSize; static u64 FF_FileSize;
static UINT FF_ReadStorage(BYTE* buf, LBA_t sector, UINT num); static UINT FF_ReadStorage(BYTE* buf, LBA_t sector, UINT num);
static UINT FF_WriteStorage(BYTE* buf, LBA_t sector, UINT num); static UINT FF_WriteStorage(BYTE* buf, LBA_t sector, UINT num);
static u32 ReadSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num, u8* data); static u32 ReadSectorsInternal(Platform::FileHandle* file, u64 filelen, u32 start, u32 num, u8* data);
static u32 WriteSectorsInternal(FILE* file, u64 filelen, u32 start, u32 num, u8* data); static u32 WriteSectorsInternal(Platform::FileHandle* file, u64 filelen, u32 start, u32 num, u8* data);
void LoadIndex(); void LoadIndex();
void SaveIndex(); void SaveIndex();

View File

@ -519,7 +519,7 @@ void CartGame::SRAMWrite_FLASH(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "GBACart_SRAM::Write_Flash: unknown write 0x%02X @ 0x%04X (state: 0x%02X)\n", Log(LogLevel::Debug, "GBACart_SRAM::Write_Flash: unknown write 0x%02X @ 0x%04X (state: 0x%02X)\n",
val, addr, SRAMFlashState.state); val, addr, SRAMFlashState.state);
} }

View File

@ -220,7 +220,7 @@ u8 Unit::Read8(u32 addr)
case 0x04D: return 0; case 0x04D: return 0;
} }
Log(LogLevel::Warn, "unknown GPU read8 %08X\n", addr); Log(LogLevel::Debug, "unknown GPU read8 %08X\n", addr);
return 0; return 0;
} }
@ -249,7 +249,7 @@ u16 Unit::Read16(u32 addr)
case 0x06C: return MasterBrightness; case 0x06C: return MasterBrightness;
} }
Log(LogLevel::Warn, "unknown GPU read16 %08X\n", addr); Log(LogLevel::Debug, "unknown GPU read16 %08X\n", addr);
return 0; return 0;
} }
@ -366,7 +366,7 @@ void Unit::Write8(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "unknown GPU write8 %08X %02X\n", addr, val); Log(LogLevel::Debug, "unknown GPU write8 %08X %02X\n", addr, val);
} }
void Unit::Write16(u32 addr, u16 val) void Unit::Write16(u32 addr, u16 val)

View File

@ -2727,7 +2727,7 @@ u8 Read8(u32 addr)
} }
} }
Log(LogLevel::Warn, "unknown GPU3D read8 %08X\n", addr); Log(LogLevel::Debug, "unknown GPU3D read8 %08X\n", addr);
return 0; return 0;
} }
@ -2771,7 +2771,7 @@ u16 Read16(u32 addr)
case 0x04000634: return VecTestResult[2]; case 0x04000634: return VecTestResult[2];
} }
Log(LogLevel::Warn, "unknown GPU3D read16 %08X\n", addr); Log(LogLevel::Debug, "unknown GPU3D read16 %08X\n", addr);
return 0; return 0;
} }
@ -2875,7 +2875,7 @@ void Write8(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "unknown GPU3D write8 %08X %02X\n", addr, val); Log(LogLevel::Debug, "unknown GPU3D write8 %08X %02X\n", addr, val);
} }
void Write16(u32 addr, u16 val) void Write16(u32 addr, u16 val)
@ -2962,7 +2962,7 @@ void Write16(u32 addr, u16 val)
return; return;
} }
Log(LogLevel::Warn, "unknown GPU3D write16 %08X %04X\n", addr, val); Log(LogLevel::Debug, "unknown GPU3D write16 %08X %04X\n", addr, val);
} }
void Write32(u32 addr, u32 val) void Write32(u32 addr, u32 val)
@ -3059,7 +3059,7 @@ void Write32(u32 addr, u32 val)
return; return;
} }
Log(LogLevel::Warn, "unknown GPU3D write32 %08X %08X\n", addr, val); Log(LogLevel::Debug, "unknown GPU3D write32 %08X %08X\n", addr, val);
} }
Renderer3D::Renderer3D(bool Accelerated) Renderer3D::Renderer3D(bool Accelerated)

View File

@ -45,8 +45,7 @@
#include "DSi_Camera.h" #include "DSi_Camera.h"
#include "DSi_DSP.h" #include "DSi_DSP.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
namespace NDS namespace NDS
{ {
@ -509,7 +508,7 @@ void SetupDirectBoot(const std::string& romname)
void Reset() void Reset()
{ {
FILE* f; Platform::FileHandle* f;
u32 i; u32 i;
#ifdef JIT_ENABLED #ifdef JIT_ENABLED
@ -527,7 +526,7 @@ void Reset()
if (Platform::GetConfigBool(Platform::ExternalBIOSEnable)) if (Platform::GetConfigBool(Platform::ExternalBIOSEnable))
{ {
f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::BIOS9Path), "rb"); f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::BIOS9Path), FileMode::Read);
if (!f) if (!f)
{ {
Log(LogLevel::Warn, "ARM9 BIOS not found\n"); Log(LogLevel::Warn, "ARM9 BIOS not found\n");
@ -537,14 +536,14 @@ void Reset()
} }
else else
{ {
fseek(f, 0, SEEK_SET); FileRewind(f);
fread(ARM9BIOS, 0x1000, 1, f); FileRead(ARM9BIOS, 0x1000, 1, f);
Log(LogLevel::Info, "ARM9 BIOS loaded\n"); Log(LogLevel::Info, "ARM9 BIOS loaded\n");
fclose(f); Platform::CloseFile(f);
} }
f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::BIOS7Path), "rb"); f = Platform::OpenLocalFile(Platform::GetConfigString(Platform::BIOS7Path), FileMode::Read);
if (!f) if (!f)
{ {
Log(LogLevel::Warn, "ARM7 BIOS not found\n"); Log(LogLevel::Warn, "ARM7 BIOS not found\n");
@ -554,11 +553,11 @@ void Reset()
} }
else else
{ {
fseek(f, 0, SEEK_SET); FileRewind(f);
fread(ARM7BIOS, 0x4000, 1, f); FileRead(ARM7BIOS, 0x4000, 1, f);
Log(LogLevel::Info, "ARM7 BIOS loaded\n"); Log(LogLevel::Info, "ARM7 BIOS loaded\n");
fclose(f); Platform::CloseFile(f);
} }
} }
else else
@ -694,11 +693,44 @@ void Start()
Running = true; Running = true;
} }
void Stop() static const char* StopReasonName(Platform::StopReason reason)
{ {
Log(LogLevel::Info, "Stopping: shutdown\n"); switch (reason)
{
case Platform::StopReason::External:
return "External";
case Platform::StopReason::PowerOff:
return "PowerOff";
case Platform::StopReason::GBAModeNotSupported:
return "GBAModeNotSupported";
case Platform::StopReason::BadExceptionRegion:
return "BadExceptionRegion";
default:
return "Unknown";
}
}
void Stop(Platform::StopReason reason)
{
Platform::LogLevel level;
switch (reason)
{
case Platform::StopReason::External:
case Platform::StopReason::PowerOff:
level = LogLevel::Info;
break;
case Platform::StopReason::GBAModeNotSupported:
case Platform::StopReason::BadExceptionRegion:
level = LogLevel::Error;
break;
default:
level = LogLevel::Warn;
break;
}
Log(level, "Stopping emulated console (Reason: %s)\n", StopReasonName(reason));
Running = false; Running = false;
Platform::StopEmu(); Platform::SignalStop(reason);
GPU::Stop(); GPU::Stop();
SPU::Stop(); SPU::Stop();
@ -2105,7 +2137,7 @@ u8 ARM9Read8(u32 addr)
return GBACart::SRAMRead(addr); return GBACart::SRAMRead(addr);
} }
Log(LogLevel::Warn, "unknown arm9 read8 %08X\n", addr); Log(LogLevel::Debug, "unknown arm9 read8 %08X\n", addr);
return 0; return 0;
} }
@ -2272,7 +2304,7 @@ void ARM9Write8(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "unknown arm9 write8 %08X %02X\n", addr, val); Log(LogLevel::Debug, "unknown arm9 write8 %08X %02X\n", addr, val);
} }
void ARM9Write16(u32 addr, u16 val) void ARM9Write16(u32 addr, u16 val)
@ -2504,7 +2536,7 @@ u8 ARM7Read8(u32 addr)
return GBACart::SRAMRead(addr); return GBACart::SRAMRead(addr);
} }
Log(LogLevel::Warn, "unknown arm7 read8 %08X %08X %08X/%08X\n", addr, ARM7->R[15], ARM7->R[0], ARM7->R[1]); Log(LogLevel::Debug, "unknown arm7 read8 %08X %08X %08X/%08X\n", addr, ARM7->R[15], ARM7->R[0], ARM7->R[1]);
return 0; return 0;
} }
@ -2570,7 +2602,7 @@ u16 ARM7Read16(u32 addr)
(GBACart::SRAMRead(addr+1) << 8); (GBACart::SRAMRead(addr+1) << 8);
} }
Log(LogLevel::Warn, "unknown arm7 read16 %08X %08X\n", addr, ARM7->R[15]); Log(LogLevel::Debug, "unknown arm7 read16 %08X %08X\n", addr, ARM7->R[15]);
return 0; return 0;
} }
@ -2707,7 +2739,7 @@ void ARM7Write8(u32 addr, u8 val)
//if (ARM7->R[15] > 0x00002F30) // ARM7 BIOS bug //if (ARM7->R[15] > 0x00002F30) // ARM7 BIOS bug
if (addr >= 0x01000000) if (addr >= 0x01000000)
Log(LogLevel::Warn, "unknown arm7 write8 %08X %02X @ %08X\n", addr, val, ARM7->R[15]); Log(LogLevel::Debug, "unknown arm7 write8 %08X %02X @ %08X\n", addr, val, ARM7->R[15]);
} }
void ARM7Write16(u32 addr, u16 val) void ARM7Write16(u32 addr, u16 val)
@ -2787,7 +2819,7 @@ void ARM7Write16(u32 addr, u16 val)
} }
if (addr >= 0x01000000) if (addr >= 0x01000000)
Log(LogLevel::Warn, "unknown arm7 write16 %08X %04X @ %08X\n", addr, val, ARM7->R[15]); Log(LogLevel::Debug, "unknown arm7 write16 %08X %04X @ %08X\n", addr, val, ARM7->R[15]);
} }
void ARM7Write32(u32 addr, u32 val) void ARM7Write32(u32 addr, u32 val)
@ -2871,7 +2903,7 @@ void ARM7Write32(u32 addr, u32 val)
} }
if (addr >= 0x01000000) if (addr >= 0x01000000)
Log(LogLevel::Warn, "unknown arm7 write32 %08X %08X @ %08X\n", addr, val, ARM7->R[15]); Log(LogLevel::Debug, "unknown arm7 write32 %08X %08X @ %08X\n", addr, val, ARM7->R[15]);
} }
bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region) bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
@ -3032,7 +3064,7 @@ u8 ARM9IORead8(u32 addr)
} }
if ((addr & 0xFFFFF000) != 0x04004000) if ((addr & 0xFFFFF000) != 0x04004000)
Log(LogLevel::Warn, "unknown ARM9 IO read8 %08X %08X\n", addr, ARM9->R[15]); Log(LogLevel::Debug, "unknown ARM9 IO read8 %08X %08X\n", addr, ARM9->R[15]);
return 0; return 0;
} }
@ -3179,7 +3211,7 @@ u16 ARM9IORead16(u32 addr)
} }
if ((addr & 0xFFFFF000) != 0x04004000) if ((addr & 0xFFFFF000) != 0x04004000)
Log(LogLevel::Warn, "unknown ARM9 IO read16 %08X %08X\n", addr, ARM9->R[15]); Log(LogLevel::Debug, "unknown ARM9 IO read16 %08X %08X\n", addr, ARM9->R[15]);
return 0; return 0;
} }
@ -3323,7 +3355,7 @@ u32 ARM9IORead32(u32 addr)
} }
if ((addr & 0xFFFFF000) != 0x04004000) if ((addr & 0xFFFFF000) != 0x04004000)
Log(LogLevel::Warn, "unknown ARM9 IO read32 %08X %08X\n", addr, ARM9->R[15]); Log(LogLevel::Debug, "unknown ARM9 IO read32 %08X %08X\n", addr, ARM9->R[15]);
return 0; return 0;
} }
@ -3404,7 +3436,7 @@ void ARM9IOWrite8(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "unknown ARM9 IO write8 %08X %02X %08X\n", addr, val, ARM9->R[15]); Log(LogLevel::Debug, "unknown ARM9 IO write8 %08X %02X %08X\n", addr, val, ARM9->R[15]);
} }
void ARM9IOWrite16(u32 addr, u16 val) void ARM9IOWrite16(u32 addr, u16 val)
@ -3588,7 +3620,7 @@ void ARM9IOWrite16(u32 addr, u16 val)
return; return;
} }
Log(LogLevel::Warn, "unknown ARM9 IO write16 %08X %04X %08X\n", addr, val, ARM9->R[15]); Log(LogLevel::Debug, "unknown ARM9 IO write16 %08X %04X %08X\n", addr, val, ARM9->R[15]);
} }
void ARM9IOWrite32(u32 addr, u32 val) void ARM9IOWrite32(u32 addr, u32 val)
@ -3786,7 +3818,7 @@ void ARM9IOWrite32(u32 addr, u32 val)
return; return;
} }
Log(LogLevel::Warn, "unknown ARM9 IO write32 %08X %08X %08X\n", addr, val, ARM9->R[15]); Log(LogLevel::Debug, "unknown ARM9 IO write32 %08X %08X %08X\n", addr, val, ARM9->R[15]);
} }
@ -3860,7 +3892,7 @@ u8 ARM7IORead8(u32 addr)
} }
if ((addr & 0xFFFFF000) != 0x04004000) if ((addr & 0xFFFFF000) != 0x04004000)
Log(LogLevel::Warn, "unknown ARM7 IO read8 %08X %08X\n", addr, ARM7->R[15]); Log(LogLevel::Debug, "unknown ARM7 IO read8 %08X %08X\n", addr, ARM7->R[15]);
return 0; return 0;
} }
@ -3954,7 +3986,7 @@ u16 ARM7IORead16(u32 addr)
} }
if ((addr & 0xFFFFF000) != 0x04004000) if ((addr & 0xFFFFF000) != 0x04004000)
Log(LogLevel::Warn, "unknown ARM7 IO read16 %08X %08X\n", addr, ARM7->R[15]); Log(LogLevel::Debug, "unknown ARM7 IO read16 %08X %08X\n", addr, ARM7->R[15]);
return 0; return 0;
} }
@ -4055,7 +4087,7 @@ u32 ARM7IORead32(u32 addr)
} }
if ((addr & 0xFFFFF000) != 0x04004000) if ((addr & 0xFFFFF000) != 0x04004000)
Log(LogLevel::Warn, "unknown ARM7 IO read32 %08X %08X\n", addr, ARM7->R[15]); Log(LogLevel::Debug, "unknown ARM7 IO read32 %08X %08X\n", addr, ARM7->R[15]);
return 0; return 0;
} }
@ -4121,7 +4153,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
case 0x04000301: case 0x04000301:
val &= 0xC0; val &= 0xC0;
if (val == 0x40) Log(LogLevel::Warn, "!! GBA MODE NOT SUPPORTED\n"); if (val == 0x40) Stop(StopReason::GBAModeNotSupported);
else if (val == 0x80) ARM7->Halt(1); else if (val == 0x80) ARM7->Halt(1);
else if (val == 0xC0) EnterSleepMode(); else if (val == 0xC0) EnterSleepMode();
return; return;
@ -4133,7 +4165,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
return; return;
} }
Log(LogLevel::Warn, "unknown ARM7 IO write8 %08X %02X %08X\n", addr, val, ARM7->R[15]); Log(LogLevel::Debug, "unknown ARM7 IO write8 %08X %02X %08X\n", addr, val, ARM7->R[15]);
} }
void ARM7IOWrite16(u32 addr, u16 val) void ARM7IOWrite16(u32 addr, u16 val)
@ -4288,7 +4320,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
return; return;
} }
Log(LogLevel::Warn, "unknown ARM7 IO write16 %08X %04X %08X\n", addr, val, ARM7->R[15]); Log(LogLevel::Debug, "unknown ARM7 IO write16 %08X %04X %08X\n", addr, val, ARM7->R[15]);
} }
void ARM7IOWrite32(u32 addr, u32 val) void ARM7IOWrite32(u32 addr, u32 val)
@ -4422,7 +4454,7 @@ void ARM7IOWrite32(u32 addr, u32 val)
return; return;
} }
Log(LogLevel::Warn, "unknown ARM7 IO write32 %08X %08X %08X\n", addr, val, ARM7->R[15]); Log(LogLevel::Debug, "unknown ARM7 IO write32 %08X %08X %08X\n", addr, val, ARM7->R[15]);
} }
} }

View File

@ -21,6 +21,7 @@
#include <string> #include <string>
#include "Platform.h"
#include "Savestate.h" #include "Savestate.h"
#include "types.h" #include "types.h"
@ -226,7 +227,9 @@ bool Init();
void DeInit(); void DeInit();
void Reset(); void Reset();
void Start(); void Start();
void Stop();
/// Stop the emulator.
void Stop(Platform::StopReason reason = Platform::StopReason::External);
bool DoSavestate(Savestate* file); bool DoSavestate(Savestate* file);

View File

@ -28,12 +28,64 @@ namespace Platform
{ {
void Init(int argc, char** argv); void Init(int argc, char** argv);
/**
* Frees all resources that were allocated in \c Init
* or by any other \c Platform function.
*/
void DeInit(); void DeInit();
void StopEmu(); enum StopReason {
/**
* The emulator stopped for some unspecified reason.
* Not necessarily an error.
*/
Unknown,
// instance ID, for local multiplayer /**
* The emulator stopped due to an external call to \c NDS::Stop,
* most likely because the user stopped the game manually.
*/
External,
/**
* The emulator stopped because it tried to enter GBA mode,
* which melonDS does not support.
*/
GBAModeNotSupported,
/**
* The emulator stopped because of an error in the emulated console,
* not necessarily because of an error in melonDS.
*/
BadExceptionRegion,
/**
* The emulated console shut itself down normally,
* likely because its system settings were adjusted
* or its "battery" ran out.
*/
PowerOff,
};
/**
* Signals to the frontend that no more frames should be requested.
* Frontends should not call this directly;
* use \c NDS::Stop instead.
*/
void SignalStop(StopReason reason);
/**
* @returns The ID of the running melonDS instance if running in local multiplayer mode,
* or 0 if not.
*/
int InstanceID(); int InstanceID();
/**
* @returns A suffix that should be appended to all instance-specific paths
* if running in local multiplayer mode,
* or the empty string if not.
*/
std::string InstanceFileSuffix(); std::string InstanceFileSuffix();
// configuration values // configuration values
@ -82,6 +134,8 @@ enum ConfigEntry
Firm_Message, Firm_Message,
Firm_MAC, Firm_MAC,
WifiSettingsPath,
AudioBitDepth, AudioBitDepth,
DSi_FullBIOSBoot DSi_FullBIOSBoot
@ -92,43 +146,154 @@ bool GetConfigBool(ConfigEntry entry);
std::string GetConfigString(ConfigEntry entry); std::string GetConfigString(ConfigEntry entry);
bool GetConfigArray(ConfigEntry entry, void* data); bool GetConfigArray(ConfigEntry entry, void* data);
// fopen() wrappers /**
// * OpenFile(): * Denotes how a file will be opened and accessed.
// simple fopen() wrapper that supports UTF8. * Flags may or may not correspond to the operating system's file API.
// can be optionally restricted to only opening a file that already exists. */
// * OpenLocalFile(): enum FileMode : unsigned {
// opens files local to the emulator (melonDS.ini, BIOS, firmware, ...) None = 0,
// For Windows builds, or portable UNIX builds it checks, by order of priority:
// * current working directory
// * emulator directory (essentially where the melonDS executable is) if supported
// * any platform-specific application data directories
// in create mode, if the file doesn't exist, it will be created in the emulator
// directory if supported, or in the current directory otherwise
// For regular UNIX builds, the user's configuration directory is always used.
// * OpenDataFile():
// Opens a file that was installed alongside melonDS on UNIX systems in /usr/share, etc.
// Looks in the user's data directory first, then the system's.
// If on Windows or a portable UNIX build, this simply calls OpenLocalFile().
FILE* OpenFile(const std::string& path, const std::string& mode, bool mustexist=false); /**
FILE* OpenLocalFile(const std::string& path, const std::string& mode); * Opens a file for reading.
FILE* OpenDataFile(const std::string& path); * Either this or \c Write must be set.
* Similar to \c "r" in \c fopen.
*/
Read = 0b00'00'01,
inline bool FileExists(const std::string& name) /**
* Opens a file for writing, creating it if it doesn't exist.
* Will truncate existing files unless \c Preserve is set.
* Either this or \c Read must be set.
* Similar to <tt>fopen</tt>'s \c "w" flag.
*/
Write = 0b00'00'10,
/**
* Opens an existing file as-is without truncating it.
* The file may still be created unless \c NoCreate is set.
* @note This flag has no effect if \c Write is not set.
*/
Preserve = 0b00'01'00,
/**
* Do not create the file if it doesn't exist.
* @note This flag has no effect if \c Write is not set.
*/
NoCreate = 0b00'10'00,
/**
* Opens a file in text mode,
* rather than the default binary mode.
* Text-mode files may have their line endings converted
* to match the operating system,
* and may also be line-buffered.
*/
Text = 0b01'00'00,
/**
* Opens a file for reading and writing.
* Equivalent to <tt>Read | Write</tt>.
*/
ReadWrite = Read | Write,
/**
* Opens a file for reading and writing
* without truncating it or creating a new one.
* Equivalent to <tt>Read | Write | Preserve | NoCreate</tt>.
*/
ReadWriteExisting = Read | Write | Preserve | NoCreate,
/**
* Opens a file for reading in text mode.
* Equivalent to <tt>Read | Text</tt>.
*/
ReadText = Read | Text,
/**
* Opens a file for writing in text mode,
* creating it if it doesn't exist.
* Equivalent to <tt>Write | Text</tt>.
*/
WriteText = Write | Text,
};
/**
* Denotes the origin of a seek operation.
* Similar to \c fseek's \c SEEK_* constants.
*/
enum class FileSeekOrigin
{ {
FILE* f = OpenFile(name, "rb"); Start,
if (!f) return false; Current,
fclose(f); End,
return true; };
}
inline bool LocalFileExists(const std::string& name) /**
{ * Opaque handle for a file object.
FILE* f = OpenLocalFile(name, "rb"); * This can be implemented as a struct defined by the frontend,
if (!f) return false; * or as a simple pointer cast.
fclose(f); * The core will never look inside this struct,
return true; * but frontends may do so freely.
} */
struct FileHandle;
// Simple fopen() wrapper that supports UTF8.
// Can be optionally restricted to only opening a file that already exists.
FileHandle* OpenFile(const std::string& path, FileMode mode);
// opens files local to the emulator (melonDS.ini, BIOS, firmware, ...)
// For Windows builds, or portable UNIX builds it checks, by order of priority:
// * current working directory
// * emulator directory (essentially where the melonDS executable is) if supported
// * any platform-specific application data directories
// in create mode, if the file doesn't exist, it will be created in the emulator
// directory if supported, or in the current directory otherwise
// For regular UNIX builds, the user's configuration directory is always used.
FileHandle* OpenLocalFile(const std::string& path, FileMode mode);
/// Returns true if the given file exists.
bool FileExists(const std::string& name);
bool LocalFileExists(const std::string& name);
/** Close a file opened with \c OpenFile.
* @returns \c true if the file was closed successfully, false otherwise.
* @post \c file is no longer valid and should not be used.
* The underlying object may still be allocated (e.g. if the frontend refcounts files),
* but that's an implementation detail.
* @see fclose
*/
bool CloseFile(FileHandle* file);
/// @returns \c true if there is no more data left to read in this file,
/// \c false if there is still data left to read or if there was an error.
/// @see feof
bool IsEndOfFile(FileHandle* file);
/// @see fgets
bool FileReadLine(char* str, int count, FileHandle* file);
/// @see fseek
bool FileSeek(FileHandle* file, s64 offset, FileSeekOrigin origin);
/// @see rewind
void FileRewind(FileHandle* file);
/// @see fread
u64 FileRead(void* data, u64 size, u64 count, FileHandle* file);
/// @see fflush
bool FileFlush(FileHandle* file);
/// @see fwrite
u64 FileWrite(const void* data, u64 size, u64 count, FileHandle* file);
/// @see fprintf
u64 FileWriteFormatted(FileHandle* file, const char* fmt, ...);
/// @returns The length of the file in bytes, or 0 if there was an error.
/// @note If this function checks the length by using \c fseek and \c ftell
/// (or local equivalents), it must leave the stream position as it was found.
u64 FileLength(FileHandle* file);
enum LogLevel enum LogLevel
{ {
@ -201,6 +366,28 @@ void Camera_Start(int num);
void Camera_Stop(int num); void Camera_Stop(int num);
void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv); void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv);
struct DynamicLibrary;
/**
* @param lib The name of the library to load.
* @return A handle to the loaded library, or \c nullptr if the library could not be loaded.
*/
DynamicLibrary* DynamicLibrary_Load(const char* lib);
/**
* Releases a loaded library.
* Pointers to functions in the library will be invalidated.
* @param lib The library to unload.
*/
void DynamicLibrary_Unload(DynamicLibrary* lib);
/**
* Loads a function from a library.
* @param lib The library to load the function from.
* @param name The name of the function to load.
* @return A pointer to the loaded function, or \c nullptr if the function could not be loaded.
*/
void* DynamicLibrary_LoadFunction(DynamicLibrary* lib, const char* name);
} }
#endif // PLATFORM_H #endif // PLATFORM_H

View File

@ -29,8 +29,7 @@
#include "DSi_SPI_TSC.h" #include "DSi_SPI_TSC.h"
#include "Platform.h" #include "Platform.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
namespace SPI_Firmware namespace SPI_Firmware
{ {
@ -223,13 +222,15 @@ void LoadDefaultFirmware()
// wifi access points // wifi access points
// TODO: WFC ID?? // TODO: WFC ID??
FILE* f = Platform::OpenLocalFile("wfcsettings.bin"+Platform::InstanceFileSuffix(), "rb"); std::string wfcsettings = Platform::GetConfigString(ConfigEntry::WifiSettingsPath);
if (!f) f = Platform::OpenLocalFile("wfcsettings.bin", "rb");
FileHandle* f = Platform::OpenLocalFile(wfcsettings + Platform::InstanceFileSuffix(), FileMode::Read);
if (!f) f = Platform::OpenLocalFile(wfcsettings, FileMode::Read);
if (f) if (f)
{ {
u32 apdata = userdata - 0xA00; u32 apdata = userdata - 0xA00;
fread(&Firmware[apdata], 0x900, 1, f); FileRead(&Firmware[apdata], 0x900, 1, f);
fclose(f); CloseFile(f);
} }
else else
{ {
@ -268,29 +269,27 @@ void LoadDefaultFirmware()
} }
} }
void LoadFirmwareFromFile(FILE* f, bool makecopy) void LoadFirmwareFromFile(FileHandle* f, bool makecopy)
{ {
fseek(f, 0, SEEK_END); FirmwareLength = FixFirmwareLength(FileLength(f));
FirmwareLength = FixFirmwareLength((u32)ftell(f));
Firmware = new u8[FirmwareLength]; Firmware = new u8[FirmwareLength];
fseek(f, 0, SEEK_SET); FileRewind(f);
fread(Firmware, 1, FirmwareLength, f); FileRead(Firmware, 1, FirmwareLength, f);
// take a backup // take a backup
std::string fwBackupPath; std::string fwBackupPath;
if (!makecopy) fwBackupPath = FirmwarePath + ".bak"; if (!makecopy) fwBackupPath = FirmwarePath + ".bak";
else fwBackupPath = FirmwarePath; else fwBackupPath = FirmwarePath;
FILE* bf = Platform::OpenLocalFile(fwBackupPath, "rb"); FileHandle* bf = Platform::OpenLocalFile(fwBackupPath, FileMode::Read);
if (!bf) if (!bf)
{ {
bf = Platform::OpenLocalFile(fwBackupPath, "wb"); bf = Platform::OpenLocalFile(fwBackupPath, FileMode::Write);
if (bf) if (bf)
{ {
fwrite(Firmware, 1, FirmwareLength, bf); FileWrite(Firmware, 1, FirmwareLength, bf);
fclose(bf); CloseFile(bf);
} }
else else
{ {
@ -299,7 +298,7 @@ void LoadFirmwareFromFile(FILE* f, bool makecopy)
} }
else else
{ {
fclose(bf); CloseFile(bf);
} }
} }
@ -350,10 +349,10 @@ void Reset()
std::string origpath = FirmwarePath; std::string origpath = FirmwarePath;
FirmwarePath += Platform::InstanceFileSuffix(); FirmwarePath += Platform::InstanceFileSuffix();
FILE* f = Platform::OpenLocalFile(FirmwarePath, "rb"); FileHandle* f = Platform::OpenLocalFile(FirmwarePath, FileMode::Read);
if (!f) if (!f)
{ {
f = Platform::OpenLocalFile(origpath, "rb"); f = Platform::OpenLocalFile(origpath, FileMode::Read);
makecopy = true; makecopy = true;
} }
if (!f) if (!f)
@ -364,7 +363,7 @@ void Reset()
else else
{ {
LoadFirmwareFromFile(f, makecopy); LoadFirmwareFromFile(f, makecopy);
fclose(f); CloseFile(f);
} }
} }
@ -604,28 +603,26 @@ void Write(u8 val, u32 hold)
{ {
if (!FirmwarePath.empty()) if (!FirmwarePath.empty())
{ {
FILE* f = Platform::OpenLocalFile(FirmwarePath, "r+b"); FileHandle* f = Platform::OpenLocalFile(FirmwarePath, FileMode::ReadWriteExisting);
if (f) if (f)
{ {
u32 cutoff = ((NDS::ConsoleType==1) ? 0x7F400 : 0x7FA00) & FirmwareMask; u32 cutoff = ((NDS::ConsoleType==1) ? 0x7F400 : 0x7FA00) & FirmwareMask;
fseek(f, cutoff, SEEK_SET); FileSeek(f, cutoff, FileSeekOrigin::Start);
fwrite(&Firmware[cutoff], FirmwareLength-cutoff, 1, f); FileWrite(&Firmware[cutoff], FirmwareLength-cutoff, 1, f);
fclose(f); CloseFile(f);
} }
} }
else else
{ {
char wfcfile[50] = {0}; std::string wfcfile = Platform::GetConfigString(ConfigEntry::WifiSettingsPath);
int inst = Platform::InstanceID(); if (Platform::InstanceID() > 0) wfcfile += Platform::InstanceFileSuffix();
if (inst > 0) snprintf(wfcfile, 49, "wfcsettings.bin", Platform::InstanceID());
else strncpy(wfcfile, "wfcsettings.bin", 49);
FILE* f = Platform::OpenLocalFile(wfcfile, "wb"); FileHandle* f = Platform::OpenLocalFile(wfcfile, FileMode::Write);
if (f) if (f)
{ {
u32 cutoff = 0x7F400 & FirmwareMask; u32 cutoff = 0x7F400 & FirmwareMask;
fwrite(&Firmware[cutoff], 0x900, 1, f); FileWrite(&Firmware[cutoff], 0x900, 1, f);
fclose(f); CloseFile(f);
} }
} }
} }
@ -725,7 +722,7 @@ void Write(u8 val, u32 hold)
switch (regid) switch (regid)
{ {
case 0: case 0:
if (val & 0x40) NDS::Stop(); // shutdown if (val & 0x40) NDS::Stop(StopReason::PowerOff); // shutdown
//printf("power %02X\n", val); //printf("power %02X\n", val);
break; break;
case 4: case 4:

View File

@ -385,7 +385,7 @@ void UpdatePowerOn()
PowerOn = on; PowerOn = on;
if (on) if (on)
{ {
Log(LogLevel::Info, "WIFI: ON\n"); Log(LogLevel::Debug, "WIFI: ON\n");
ScheduleTimer(true); ScheduleTimer(true);
@ -393,7 +393,7 @@ void UpdatePowerOn()
} }
else else
{ {
Log(LogLevel::Info, "WIFI: OFF\n"); Log(LogLevel::Debug, "WIFI: OFF\n");
NDS::CancelEvent(NDS::Event_Wifi); NDS::CancelEvent(NDS::Event_Wifi);

View File

@ -163,7 +163,7 @@ int HandleManagementFrame(u8* data, int len)
} }
ClientStatus = 2; ClientStatus = 2;
Log(LogLevel::Info, "wifiAP: client associated\n"); Log(LogLevel::Debug, "wifiAP: client associated\n");
PWRITE_16(p, 0x0010); PWRITE_16(p, 0x0010);
PWRITE_16(p, 0x0000); // duration?? PWRITE_16(p, 0x0000); // duration??
@ -213,7 +213,7 @@ int HandleManagementFrame(u8* data, int len)
return 0; return 0;
ClientStatus = 1; ClientStatus = 1;
Log(LogLevel::Info, "wifiAP: client deassociated\n"); Log(LogLevel::Debug, "wifiAP: client deassociated\n");
PWRITE_16(p, 0x00A0); PWRITE_16(p, 0x00A0);
PWRITE_16(p, 0x0000); // duration?? PWRITE_16(p, 0x0000); // duration??
@ -235,7 +235,7 @@ int HandleManagementFrame(u8* data, int len)
return 0; return 0;
ClientStatus = 1; ClientStatus = 1;
Log(LogLevel::Info, "wifiAP: client authenticated\n"); Log(LogLevel::Debug, "wifiAP: client authenticated\n");
PWRITE_16(p, 0x00B0); PWRITE_16(p, 0x00B0);
PWRITE_16(p, 0x0000); // duration?? PWRITE_16(p, 0x0000); // duration??
@ -259,7 +259,7 @@ int HandleManagementFrame(u8* data, int len)
return 0; return 0;
ClientStatus = 0; ClientStatus = 0;
Log(LogLevel::Info, "wifiAP: client deauthenticated\n"); Log(LogLevel::Debug, "wifiAP: client deauthenticated\n");
PWRITE_16(p, 0x00C0); PWRITE_16(p, 0x00C0);
PWRITE_16(p, 0x0000); // duration?? PWRITE_16(p, 0x0000); // duration??

View File

@ -29,7 +29,8 @@ std::string LastStrerrorString()
// We check defines in order to figure out variant is in use, and we store the returned value // We check defines in order to figure out variant is in use, and we store the returned value
// to a variable so that we'll get a compile-time check that our assumption was correct. // to a variable so that we'll get a compile-time check that our assumption was correct.
#if defined(__GLIBC__) && (_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600)) #if (defined(__GLIBC__) || __ANDROID_API__ >= 23) && \
(_GNU_SOURCE || (_POSIX_C_SOURCE < 200112L && _XOPEN_SOURCE < 600))
const char* str = strerror_r(errno, error_message, BUFFER_SIZE); const char* str = strerror_r(errno, error_message, BUFFER_SIZE);
return std::string(str); return std::string(str);
#else #else

View File

@ -106,6 +106,7 @@ int FirmwareBirthdayDay;
int FirmwareFavouriteColour; int FirmwareFavouriteColour;
std::string FirmwareMessage; std::string FirmwareMessage;
std::string FirmwareMAC; std::string FirmwareMAC;
std::string WifiSettingsPath = "wfcsettings.bin"; // Should this be configurable?
int MPAudioMode; int MPAudioMode;
int MPRecvTimeout; int MPRecvTimeout;
@ -353,24 +354,24 @@ ConfigEntry ConfigFile[] =
void LoadFile(int inst) void LoadFile(int inst)
{ {
FILE* f; Platform::FileHandle* f;
if (inst > 0) if (inst > 0)
{ {
char name[100] = {0}; char name[100] = {0};
snprintf(name, 99, kUniqueConfigFile, inst+1); snprintf(name, 99, kUniqueConfigFile, inst+1);
f = Platform::OpenLocalFile(name, "r"); f = Platform::OpenLocalFile(name, Platform::FileMode::ReadText);
} }
else else
f = Platform::OpenLocalFile(kConfigFile, "r"); f = Platform::OpenLocalFile(kConfigFile, Platform::FileMode::ReadText);
if (!f) return; if (!f) return;
char linebuf[1024]; char linebuf[1024];
char entryname[32]; char entryname[32];
char entryval[1024]; char entryval[1024];
while (!feof(f)) while (!Platform::IsEndOfFile(f))
{ {
if (fgets(linebuf, 1024, f) == nullptr) if (!Platform::FileReadLine(linebuf, 1024, f))
break; break;
int ret = sscanf(linebuf, "%31[A-Za-z_0-9]=%[^\t\r\n]", entryname, entryval); int ret = sscanf(linebuf, "%31[A-Za-z_0-9]=%[^\t\r\n]", entryname, entryval);
@ -396,7 +397,7 @@ void LoadFile(int inst)
} }
} }
fclose(f); CloseFile(f);
} }
void Load() void Load()
@ -423,15 +424,15 @@ void Save()
{ {
int inst = Platform::InstanceID(); int inst = Platform::InstanceID();
FILE* f; Platform::FileHandle* f;
if (inst > 0) if (inst > 0)
{ {
char name[100] = {0}; char name[100] = {0};
snprintf(name, 99, kUniqueConfigFile, inst+1); snprintf(name, 99, kUniqueConfigFile, inst+1);
f = Platform::OpenLocalFile(name, "w"); f = Platform::OpenLocalFile(name, Platform::FileMode::WriteText);
} }
else else
f = Platform::OpenLocalFile(kConfigFile, "w"); f = Platform::OpenLocalFile(kConfigFile, Platform::FileMode::WriteText);
if (!f) return; if (!f) return;
@ -442,13 +443,13 @@ void Save()
switch (entry->Type) switch (entry->Type)
{ {
case 0: fprintf(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value); break; case 0: Platform::FileWriteFormatted(f, "%s=%d\r\n", entry->Name, *(int*)entry->Value); break;
case 1: fprintf(f, "%s=%d\r\n", entry->Name, *(bool*)entry->Value ? 1:0); break; case 1: Platform::FileWriteFormatted(f, "%s=%d\r\n", entry->Name, *(bool*)entry->Value ? 1:0); break;
case 2: fprintf(f, "%s=%s\r\n", entry->Name, (*(std::string*)entry->Value).c_str()); break; case 2: Platform::FileWriteFormatted(f, "%s=%s\r\n", entry->Name, (*(std::string*)entry->Value).c_str()); break;
} }
} }
fclose(f); CloseFile(f);
} }
} }

View File

@ -152,6 +152,7 @@ extern int FirmwareBirthdayDay;
extern int FirmwareFavouriteColour; extern int FirmwareFavouriteColour;
extern std::string FirmwareMessage; extern std::string FirmwareMessage;
extern std::string FirmwareMAC; extern std::string FirmwareMAC;
extern std::string WifiSettingsPath;
extern int MPAudioMode; extern int MPAudioMode;
extern int MPRecvTimeout; extern int MPRecvTimeout;

View File

@ -29,6 +29,7 @@
#include "EmuSettingsDialog.h" #include "EmuSettingsDialog.h"
#include "ui_EmuSettingsDialog.h" #include "ui_EmuSettingsDialog.h"
using namespace Platform;
EmuSettingsDialog* EmuSettingsDialog::currentDlg = nullptr; EmuSettingsDialog* EmuSettingsDialog::currentDlg = nullptr;
@ -156,19 +157,19 @@ void EmuSettingsDialog::verifyFirmware()
// bytes 0x0C-0x14 are different. // bytes 0x0C-0x14 are different.
std::string filename = ui->txtFirmwarePath->text().toStdString(); std::string filename = ui->txtFirmwarePath->text().toStdString();
FILE* f = Platform::OpenLocalFile(filename, "rb"); FileHandle* f = Platform::OpenLocalFile(filename, FileMode::Read);
if (!f) return; if (!f) return;
u8 chk1[0x180], chk2[0x180]; u8 chk1[0x180], chk2[0x180];
fseek(f, 0, SEEK_SET); FileRewind(f);
fread(chk1, 1, 0x180, f); FileRead(chk1, 1, 0x180, f);
fseek(f, -0x380, SEEK_END); FileSeek(f, -0x380, FileSeekOrigin::End);
fread(chk2, 1, 0x180, f); FileRead(chk2, 1, 0x180, f);
memset(&chk1[0x0C], 0, 8); memset(&chk1[0x0C], 0, 8);
memset(&chk2[0x0C], 0, 8); memset(&chk2[0x0C], 0, 8);
fclose(f); CloseFile(f);
if (!memcmp(chk1, chk2, 0x180)) if (!memcmp(chk1, chk2, 0x180))
{ {

View File

@ -21,9 +21,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <SDL2/SDL.h>
#include <pcap/pcap.h> #include <pcap/pcap.h>
#include "../Wifi.h" #include "Wifi.h"
#include "LAN_PCap.h" #include "LAN_PCap.h"
#include "Config.h" #include "Config.h"
#include "Platform.h" #include "Platform.h"
@ -88,7 +87,7 @@ const char* PCapLibNames[] =
AdapterData* Adapters = NULL; AdapterData* Adapters = NULL;
int NumAdapters = 0; int NumAdapters = 0;
void* PCapLib = NULL; Platform::DynamicLibrary* PCapLib = NULL;
pcap_t* PCapAdapter = NULL; pcap_t* PCapAdapter = NULL;
AdapterData* PCapAdapterData; AdapterData* PCapAdapterData;
@ -98,10 +97,10 @@ volatile int RXNum;
#define LOAD_PCAP_FUNC(sym) \ #define LOAD_PCAP_FUNC(sym) \
ptr_##sym = (type_##sym)SDL_LoadFunction(lib, #sym); \ ptr_##sym = (type_##sym)DynamicLibrary_LoadFunction(lib, #sym); \
if (!ptr_##sym) return false; if (!ptr_##sym) return false;
bool TryLoadPCap(void* lib) bool TryLoadPCap(Platform::DynamicLibrary *lib)
{ {
LOAD_PCAP_FUNC(pcap_findalldevs) LOAD_PCAP_FUNC(pcap_findalldevs)
LOAD_PCAP_FUNC(pcap_freealldevs) LOAD_PCAP_FUNC(pcap_freealldevs)
@ -130,12 +129,12 @@ bool Init(bool open_adapter)
for (int i = 0; PCapLibNames[i]; i++) for (int i = 0; PCapLibNames[i]; i++)
{ {
void* lib = SDL_LoadObject(PCapLibNames[i]); Platform::DynamicLibrary* lib = Platform::DynamicLibrary_Load(PCapLibNames[i]);
if (!lib) continue; if (!lib) continue;
if (!TryLoadPCap(lib)) if (!TryLoadPCap(lib))
{ {
SDL_UnloadObject(lib); Platform::DynamicLibrary_Unload(lib);
continue; continue;
} }
@ -355,7 +354,7 @@ void DeInit()
PCapAdapter = NULL; PCapAdapter = NULL;
} }
SDL_UnloadObject(PCapLib); Platform::DynamicLibrary_Unload(PCapLib);
PCapLib = NULL; PCapLib = NULL;
} }
} }

View File

@ -19,7 +19,7 @@
#ifndef LAN_PCAP_H #ifndef LAN_PCAP_H
#define LAN_PCAP_H #define LAN_PCAP_H
#include "../types.h" #include "types.h"
namespace LAN_PCap namespace LAN_PCap
{ {

View File

@ -24,6 +24,7 @@
#include "Wifi.h" #include "Wifi.h"
#include "LAN_Socket.h" #include "LAN_Socket.h"
#include "FIFO.h" #include "FIFO.h"
#include "Platform.h"
#include <slirp/libslirp.h> #include <slirp/libslirp.h>
@ -40,6 +41,9 @@
namespace LAN_Socket namespace LAN_Socket
{ {
using Platform::Log;
using Platform::LogLevel;
const u32 kSubnet = 0x0A400000; const u32 kSubnet = 0x0A400000;
const u32 kServerIP = kSubnet | 0x01; const u32 kServerIP = kSubnet | 0x01;
const u32 kDNSIP = kSubnet | 0x02; const u32 kDNSIP = kSubnet | 0x02;
@ -87,7 +91,7 @@ void RXEnqueue(const void* buf, int len)
if (!RXBuffer.CanFit(totallen >> 2)) if (!RXBuffer.CanFit(totallen >> 2))
{ {
printf("slirp: !! NOT ENOUGH SPACE IN RX BUFFER\n"); Log(LogLevel::Warn, "slirp: !! NOT ENOUGH SPACE IN RX BUFFER\n");
return; return;
} }
@ -101,11 +105,11 @@ ssize_t SlirpCbSendPacket(const void* buf, size_t len, void* opaque)
{ {
if (len > 2048) if (len > 2048)
{ {
printf("slirp: packet too big (%zu)\n", len); Log(LogLevel::Warn, "slirp: packet too big (%zu)\n", len);
return 0; return 0;
} }
printf("slirp: response packet of %zu bytes, type %04X\n", len, ntohs(((u16*)buf)[6])); Log(LogLevel::Debug, "slirp: response packet of %zu bytes, type %04X\n", len, ntohs(((u16*)buf)[6]));
RXEnqueue(buf, len); RXEnqueue(buf, len);
@ -114,7 +118,7 @@ ssize_t SlirpCbSendPacket(const void* buf, size_t len, void* opaque)
void SlirpCbGuestError(const char* msg, void* opaque) void SlirpCbGuestError(const char* msg, void* opaque)
{ {
printf("SLIRP: error: %s\n", msg); Log(LogLevel::Error, "SLIRP: error: %s\n", msg);
} }
int64_t SlirpCbClockGetNS(void* opaque) int64_t SlirpCbClockGetNS(void* opaque)
@ -139,7 +143,7 @@ void SlirpCbTimerMod(void* timer, int64_t expire_time, void* opaque)
void SlirpCbRegisterPollFD(int fd, void* opaque) void SlirpCbRegisterPollFD(int fd, void* opaque)
{ {
printf("Slirp: register poll FD %d\n", fd); Log(LogLevel::Debug, "Slirp: register poll FD %d\n", fd);
/*if (FDListSize >= FDListMax) /*if (FDListSize >= FDListMax)
{ {
@ -158,7 +162,7 @@ void SlirpCbRegisterPollFD(int fd, void* opaque)
void SlirpCbUnregisterPollFD(int fd, void* opaque) void SlirpCbUnregisterPollFD(int fd, void* opaque)
{ {
printf("Slirp: unregister poll FD %d\n", fd); Log(LogLevel::Debug, "Slirp: unregister poll FD %d\n", fd);
/*if (FDListSize < 1) /*if (FDListSize < 1)
{ {
@ -178,7 +182,7 @@ void SlirpCbUnregisterPollFD(int fd, void* opaque)
void SlirpCbNotify(void* opaque) void SlirpCbNotify(void* opaque)
{ {
printf("Slirp: notify???\n"); Log(LogLevel::Debug, "Slirp: notify???\n");
} }
SlirpCb cb = SlirpCb cb =
@ -283,7 +287,7 @@ void HandleDNSFrame(u8* data, int len)
u16 numauth = ntohs(*(u16*)&dnsbody[8]); u16 numauth = ntohs(*(u16*)&dnsbody[8]);
u16 numadd = ntohs(*(u16*)&dnsbody[10]); u16 numadd = ntohs(*(u16*)&dnsbody[10]);
printf("DNS: ID=%04X, flags=%04X, Q=%d, A=%d, auth=%d, add=%d\n", Log(LogLevel::Debug, "DNS: ID=%04X, flags=%04X, Q=%d, A=%d, auth=%d, add=%d\n",
id, flags, numquestions, numanswers, numauth, numadd); id, flags, numquestions, numanswers, numauth, numadd);
// for now we only take 'simple' DNS requests // for now we only take 'simple' DNS requests
@ -429,7 +433,7 @@ int SendPacket(u8* data, int len)
if (len > 2048) if (len > 2048)
{ {
printf("LAN_SendPacket: error: packet too long (%d)\n", len); Log(LogLevel::Error, "LAN_SendPacket: error: packet too long (%d)\n", len);
return 0; return 0;
} }
@ -461,7 +465,7 @@ int SlirpCbAddPoll(int fd, int events, void* opaque)
{ {
if (PollListSize >= PollListMax) if (PollListSize >= PollListMax)
{ {
printf("slirp: POLL LIST FULL\n"); Log(LogLevel::Error, "slirp: POLL LIST FULL\n");
return -1; return -1;
} }

View File

@ -19,7 +19,7 @@
#ifndef LAN_SOCKET_H #ifndef LAN_SOCKET_H
#define LAN_SOCKET_H #define LAN_SOCKET_H
#include "../types.h" #include "types.h"
namespace LAN_Socket namespace LAN_Socket
{ {

View File

@ -29,6 +29,7 @@
#include <QMutex> #include <QMutex>
#include <QOpenGLContext> #include <QOpenGLContext>
#include <QSharedMemory> #include <QSharedMemory>
#include <SDL_loadso.h>
#include "Platform.h" #include "Platform.h"
#include "Config.h" #include "Config.h"
@ -37,7 +38,12 @@
#include "LAN_Socket.h" #include "LAN_Socket.h"
#include "LAN_PCap.h" #include "LAN_PCap.h"
#include "LocalMP.h" #include "LocalMP.h"
#include "OSD.h"
#ifdef __WIN32__
#define fseek _fseeki64
#define ftell _ftelli64
#endif // __WIN32__
std::string EmuDirectory; std::string EmuDirectory;
@ -149,10 +155,24 @@ void DeInit()
IPCDeInit(); IPCDeInit();
} }
void SignalStop(StopReason reason)
void StopEmu()
{ {
emuStop(); emuStop();
switch (reason)
{
case StopReason::GBAModeNotSupported:
Log(LogLevel::Error, "!! GBA MODE NOT SUPPORTED\n");
OSD::AddMessage(0xFFA0A0, "GBA mode not supported.");
break;
case StopReason::BadExceptionRegion:
OSD::AddMessage(0xFFA0A0, "Internal error.");
break;
case StopReason::PowerOff:
case StopReason::External:
OSD::AddMessage(0xFFC040, "Shutdown");
default:
break;
}
} }
@ -246,6 +266,7 @@ std::string GetConfigString(ConfigEntry entry)
case Firm_Username: return Config::FirmwareUsername; case Firm_Username: return Config::FirmwareUsername;
case Firm_Message: return Config::FirmwareMessage; case Firm_Message: return Config::FirmwareMessage;
case WifiSettingsPath: return Config::WifiSettingsPath;
} }
return ""; return "";
@ -288,45 +309,72 @@ bool GetConfigArray(ConfigEntry entry, void* data)
return false; return false;
} }
constexpr char AccessMode(FileMode mode, bool file_exists)
FILE* OpenFile(const std::string& path, const std::string& mode, bool mustexist)
{ {
QFile f(QString::fromStdString(path)); if (!(mode & FileMode::Write))
// If we're only opening the file for reading...
return 'r';
if (mustexist && !f.exists()) if (mode & (FileMode::NoCreate))
{ // If we're not allowed to create a new file...
return 'r'; // Open in "r+" mode (IsExtended will add the "+")
if ((mode & FileMode::Preserve) && file_exists)
// If we're not allowed to overwrite a file that already exists...
return 'r'; // Open in "r+" mode (IsExtended will add the "+")
return 'w';
}
constexpr bool IsExtended(FileMode mode)
{
// fopen's "+" flag always opens the file for read/write
return (mode & FileMode::ReadWrite) == FileMode::ReadWrite;
}
static std::string GetModeString(FileMode mode, bool file_exists)
{
std::string modeString;
modeString += AccessMode(mode, file_exists);
if (IsExtended(mode))
modeString += '+';
if (!(mode & FileMode::Text))
modeString += 'b';
return modeString;
}
FileHandle* OpenFile(const std::string& path, FileMode mode)
{
if ((mode & FileMode::ReadWrite) == FileMode::None)
{ // If we aren't reading or writing, then we can't open the file
Log(LogLevel::Error, "Attempted to open \"%s\" in neither read nor write mode (FileMode 0x%x)\n", path.c_str(), mode);
return nullptr; return nullptr;
} }
QIODevice::OpenMode qmode; bool file_exists = QFile::exists(QString::fromStdString(path));
if (mode.length() > 1 && mode[0] == 'r' && mode[1] == '+') std::string modeString = GetModeString(mode, file_exists);
FILE* file = fopen(path.c_str(), modeString.c_str());
if (file)
{ {
qmode = QIODevice::OpenModeFlag::ReadWrite; Log(LogLevel::Debug, "Opened \"%s\" with FileMode 0x%x (effective mode \"%s\")\n", path.c_str(), mode, modeString.c_str());
} return reinterpret_cast<FileHandle *>(file);
else if (mode.length() > 1 && mode[0] == 'w' && mode[1] == '+')
{
qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::ReadWrite;
}
else if (mode[0] == 'w')
{
qmode = QIODevice::OpenModeFlag::Truncate | QIODevice::OpenModeFlag::WriteOnly;
} }
else else
{ {
qmode = QIODevice::OpenModeFlag::ReadOnly; Log(LogLevel::Warn, "Failed to open \"%s\" with FileMode 0x%x (effective mode \"%s\")\n", path.c_str(), mode, modeString.c_str());
return nullptr;
} }
f.open(qmode);
FILE* file = fdopen(dup(f.handle()), mode.c_str());
f.close();
return file;
} }
FILE* OpenLocalFile(const std::string& path, const std::string& mode) FileHandle* OpenLocalFile(const std::string& path, FileMode mode)
{ {
QString qpath = QString::fromStdString(path); QString qpath = QString::fromStdString(path);
QDir dir(qpath); QDir dir(qpath);
QString fullpath; QString fullpath;
if (dir.isAbsolute()) if (dir.isAbsolute())
@ -347,7 +395,93 @@ FILE* OpenLocalFile(const std::string& path, const std::string& mode)
#endif #endif
} }
return OpenFile(fullpath.toStdString(), mode, mode[0] != 'w'); return OpenFile(fullpath.toStdString(), mode);
}
bool CloseFile(FileHandle* file)
{
return fclose(reinterpret_cast<FILE *>(file)) == 0;
}
bool IsEndOfFile(FileHandle* file)
{
return feof(reinterpret_cast<FILE *>(file)) != 0;
}
bool FileReadLine(char* str, int count, FileHandle* file)
{
return fgets(str, count, reinterpret_cast<FILE *>(file)) != nullptr;
}
bool FileExists(const std::string& name)
{
FileHandle* f = OpenFile(name, FileMode::Read);
if (!f) return false;
CloseFile(f);
return true;
}
bool LocalFileExists(const std::string& name)
{
FileHandle* f = OpenLocalFile(name, FileMode::Read);
if (!f) return false;
CloseFile(f);
return true;
}
bool FileSeek(FileHandle* file, s64 offset, FileSeekOrigin origin)
{
int stdorigin;
switch (origin)
{
case FileSeekOrigin::Start: stdorigin = SEEK_SET; break;
case FileSeekOrigin::Current: stdorigin = SEEK_CUR; break;
case FileSeekOrigin::End: stdorigin = SEEK_END; break;
}
return fseek(reinterpret_cast<FILE *>(file), offset, stdorigin) == 0;
}
void FileRewind(FileHandle* file)
{
rewind(reinterpret_cast<FILE *>(file));
}
u64 FileRead(void* data, u64 size, u64 count, FileHandle* file)
{
return fread(data, size, count, reinterpret_cast<FILE *>(file));
}
bool FileFlush(FileHandle* file)
{
return fflush(reinterpret_cast<FILE *>(file)) == 0;
}
u64 FileWrite(const void* data, u64 size, u64 count, FileHandle* file)
{
return fwrite(data, size, count, reinterpret_cast<FILE *>(file));
}
u64 FileWriteFormatted(FileHandle* file, const char* fmt, ...)
{
if (fmt == nullptr)
return 0;
va_list args;
va_start(args, fmt);
u64 ret = vfprintf(reinterpret_cast<FILE *>(file), fmt, args);
va_end(args);
return ret;
}
u64 FileLength(FileHandle* file)
{
FILE* stdfile = reinterpret_cast<FILE *>(file);
long pos = ftell(stdfile);
fseek(stdfile, 0, SEEK_END);
long len = ftell(stdfile);
fseek(stdfile, pos, SEEK_SET);
return len;
} }
void Log(LogLevel level, const char* fmt, ...) void Log(LogLevel level, const char* fmt, ...)
@ -566,4 +700,19 @@ void Camera_CaptureFrame(int num, u32* frame, int width, int height, bool yuv)
return camManager[num]->captureFrame(frame, width, height, yuv); return camManager[num]->captureFrame(frame, width, height, yuv);
} }
DynamicLibrary* DynamicLibrary_Load(const char* lib)
{
return (DynamicLibrary*) SDL_LoadObject(lib);
}
void DynamicLibrary_Unload(DynamicLibrary* lib)
{
SDL_UnloadObject(lib);
}
void* DynamicLibrary_LoadFunction(DynamicLibrary* lib, const char* name)
{
return SDL_LoadFunction(lib, name);
}
} }

View File

@ -36,6 +36,7 @@
#include "SPI.h" #include "SPI.h"
#include "DSi_I2C.h" #include "DSi_I2C.h"
using namespace Platform;
namespace ROMManager namespace ROMManager
{ {
@ -119,137 +120,131 @@ std::string GetAssetPath(bool gba, const std::string& configpath, const std::str
QString VerifyDSBIOS() QString VerifyDSBIOS()
{ {
FILE* f; FileHandle* f;
long len; long len;
f = Platform::OpenLocalFile(Config::BIOS9Path, "rb"); f = Platform::OpenLocalFile(Config::BIOS9Path, FileMode::Read);
if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings."; if (!f) return "DS ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END); len = FileLength(f);
len = ftell(f);
if (len != 0x1000) if (len != 0x1000)
{ {
fclose(f); CloseFile(f);
return "DS ARM9 BIOS is not a valid BIOS dump."; return "DS ARM9 BIOS is not a valid BIOS dump.";
} }
fclose(f); CloseFile(f);
f = Platform::OpenLocalFile(Config::BIOS7Path, "rb"); f = Platform::OpenLocalFile(Config::BIOS7Path, FileMode::Read);
if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings."; if (!f) return "DS ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END); len = FileLength(f);
len = ftell(f);
if (len != 0x4000) if (len != 0x4000)
{ {
fclose(f); CloseFile(f);
return "DS ARM7 BIOS is not a valid BIOS dump."; return "DS ARM7 BIOS is not a valid BIOS dump.";
} }
fclose(f); CloseFile(f);
return ""; return "";
} }
QString VerifyDSiBIOS() QString VerifyDSiBIOS()
{ {
FILE* f; FileHandle* f;
long len; long len;
// TODO: check the first 32 bytes // TODO: check the first 32 bytes
f = Platform::OpenLocalFile(Config::DSiBIOS9Path, "rb"); f = Platform::OpenLocalFile(Config::DSiBIOS9Path, FileMode::Read);
if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings."; if (!f) return "DSi ARM9 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END); len = FileLength(f);
len = ftell(f);
if (len != 0x10000) if (len != 0x10000)
{ {
fclose(f); CloseFile(f);
return "DSi ARM9 BIOS is not a valid BIOS dump."; return "DSi ARM9 BIOS is not a valid BIOS dump.";
} }
fclose(f); CloseFile(f);
f = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb"); f = Platform::OpenLocalFile(Config::DSiBIOS7Path, FileMode::Read);
if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings."; if (!f) return "DSi ARM7 BIOS was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END); len = FileLength(f);
len = ftell(f);
if (len != 0x10000) if (len != 0x10000)
{ {
fclose(f); CloseFile(f);
return "DSi ARM7 BIOS is not a valid BIOS dump."; return "DSi ARM7 BIOS is not a valid BIOS dump.";
} }
fclose(f); CloseFile(f);
return ""; return "";
} }
QString VerifyDSFirmware() QString VerifyDSFirmware()
{ {
FILE* f; FileHandle* f;
long len; long len;
f = Platform::OpenLocalFile(Config::FirmwarePath, "rb"); f = Platform::OpenLocalFile(Config::FirmwarePath, FileMode::Read);
if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings."; if (!f) return "DS firmware was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END); len = FileLength(f);
len = ftell(f);
if (len == 0x20000) if (len == 0x20000)
{ {
// 128KB firmware, not bootable // 128KB firmware, not bootable
fclose(f); CloseFile(f);
// TODO report it somehow? detect in core? // TODO report it somehow? detect in core?
return ""; return "";
} }
else if (len != 0x40000 && len != 0x80000) else if (len != 0x40000 && len != 0x80000)
{ {
fclose(f); CloseFile(f);
return "DS firmware is not a valid firmware dump."; return "DS firmware is not a valid firmware dump.";
} }
fclose(f); CloseFile(f);
return ""; return "";
} }
QString VerifyDSiFirmware() QString VerifyDSiFirmware()
{ {
FILE* f; FileHandle* f;
long len; long len;
f = Platform::OpenLocalFile(Config::DSiFirmwarePath, "rb"); f = Platform::OpenLocalFile(Config::DSiFirmwarePath, FileMode::Read);
if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings."; if (!f) return "DSi firmware was not found or could not be accessed. Check your emu settings.";
fseek(f, 0, SEEK_END); len = FileLength(f);
len = ftell(f);
if (len != 0x20000) if (len != 0x20000)
{ {
// not 128KB // not 128KB
// TODO: check whether those work // TODO: check whether those work
fclose(f); CloseFile(f);
return "DSi firmware is not a valid firmware dump."; return "DSi firmware is not a valid firmware dump.";
} }
fclose(f); CloseFile(f);
return ""; return "";
} }
QString VerifyDSiNAND() QString VerifyDSiNAND()
{ {
FILE* f; FileHandle* f;
long len; long len;
f = Platform::OpenLocalFile(Config::DSiNANDPath, "r+b"); f = Platform::OpenLocalFile(Config::DSiNANDPath, FileMode::ReadWriteExisting);
if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings."; if (!f) return "DSi NAND was not found or could not be accessed. Check your emu settings.";
// TODO: some basic checks // TODO: some basic checks
// check that it has the nocash footer, and all // check that it has the nocash footer, and all
fclose(f); CloseFile(f);
return ""; return "";
} }
@ -659,29 +654,28 @@ bool LoadROM(QStringList filepath, bool reset)
// regular file // regular file
std::string filename = filepath.at(0).toStdString(); std::string filename = filepath.at(0).toStdString();
FILE* f = Platform::OpenFile(filename, "rb", true); Platform::FileHandle* f = Platform::OpenFile(filename, FileMode::Read);
if (!f) return false; if (!f) return false;
fseek(f, 0, SEEK_END); long len = Platform::FileLength(f);
long len = ftell(f);
if (len > 0x40000000) if (len > 0x40000000)
{ {
fclose(f); Platform::CloseFile(f);
delete[] filedata; delete[] filedata;
return false; return false;
} }
fseek(f, 0, SEEK_SET); Platform::FileRewind(f);
filedata = new u8[len]; filedata = new u8[len];
size_t nread = fread(filedata, (size_t)len, 1, f); size_t nread = Platform::FileRead(filedata, (size_t)len, 1, f);
if (nread != 1) if (nread != 1)
{ {
fclose(f); Platform::CloseFile(f);
delete[] filedata; delete[] filedata;
return false; return false;
} }
fclose(f); Platform::CloseFile(f);
filelen = (u32)len; filelen = (u32)len;
if (filename.length() > 4 && filename.substr(filename.length() - 4) == ".zst") if (filename.length() > 4 && filename.substr(filename.length() - 4) == ".zst")
@ -754,17 +748,16 @@ bool LoadROM(QStringList filepath, bool reset)
std::string origsav = savname; std::string origsav = savname;
savname += Platform::InstanceFileSuffix(); savname += Platform::InstanceFileSuffix();
FILE* sav = Platform::OpenFile(savname, "rb", true); FileHandle* sav = Platform::OpenFile(savname, FileMode::Read);
if (!sav) sav = Platform::OpenFile(origsav, "rb", true); if (!sav) sav = Platform::OpenFile(origsav, FileMode::Read);
if (sav) if (sav)
{ {
fseek(sav, 0, SEEK_END); savelen = (u32)Platform::FileLength(sav);
savelen = (u32)ftell(sav);
fseek(sav, 0, SEEK_SET); FileRewind(sav);
savedata = new u8[savelen]; savedata = new u8[savelen];
fread(savedata, savelen, 1, sav); FileRead(savedata, savelen, 1, sav);
fclose(sav); CloseFile(sav);
} }
bool res = NDS::LoadCart(filedata, filelen, savedata, savelen); bool res = NDS::LoadCart(filedata, filelen, savedata, savelen);
@ -841,28 +834,27 @@ bool LoadGBAROM(QStringList filepath)
// regular file // regular file
std::string filename = filepath.at(0).toStdString(); std::string filename = filepath.at(0).toStdString();
FILE* f = Platform::OpenFile(filename, "rb", true); FileHandle* f = Platform::OpenFile(filename, FileMode::Read);
if (!f) return false; if (!f) return false;
fseek(f, 0, SEEK_END); long len = FileLength(f);
long len = ftell(f);
if (len > 0x40000000) if (len > 0x40000000)
{ {
fclose(f); CloseFile(f);
return false; return false;
} }
fseek(f, 0, SEEK_SET); FileRewind(f);
filedata = new u8[len]; filedata = new u8[len];
size_t nread = fread(filedata, (size_t)len, 1, f); size_t nread = FileRead(filedata, (size_t)len, 1, f);
if (nread != 1) if (nread != 1)
{ {
fclose(f); CloseFile(f);
delete[] filedata; delete[] filedata;
return false; return false;
} }
fclose(f); CloseFile(f);
filelen = (u32)len; filelen = (u32)len;
if (filename.length() > 4 && filename.substr(filename.length() - 4) == ".zst") if (filename.length() > 4 && filename.substr(filename.length() - 4) == ".zst")
@ -926,17 +918,16 @@ bool LoadGBAROM(QStringList filepath)
std::string origsav = savname; std::string origsav = savname;
savname += Platform::InstanceFileSuffix(); savname += Platform::InstanceFileSuffix();
FILE* sav = Platform::OpenFile(savname, "rb", true); FileHandle* sav = Platform::OpenFile(savname, FileMode::Read);
if (!sav) sav = Platform::OpenFile(origsav, "rb", true); if (!sav) sav = Platform::OpenFile(origsav, FileMode::Read);
if (sav) if (sav)
{ {
fseek(sav, 0, SEEK_END); savelen = (u32)FileLength(sav);
savelen = (u32)ftell(sav);
fseek(sav, 0, SEEK_SET); FileRewind(sav);
savedata = new u8[savelen]; savedata = new u8[savelen];
fread(savedata, savelen, 1, sav); FileRead(savedata, savelen, 1, sav);
fclose(sav); CloseFile(sav);
} }
bool res = NDS::LoadGBACart(filedata, filelen, savedata, savelen); bool res = NDS::LoadGBACart(filedata, filelen, savedata, savelen);

View File

@ -22,8 +22,7 @@
#include "SaveManager.h" #include "SaveManager.h"
#include "Platform.h" #include "Platform.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
SaveManager::SaveManager(const std::string& path) : QThread() SaveManager::SaveManager(const std::string& path) : QThread()
{ {
@ -77,11 +76,11 @@ void SaveManager::SetPath(const std::string& path, bool reload)
if (reload) if (reload)
{ {
FILE* f = Platform::OpenFile(Path, "rb", true); FileHandle* f = Platform::OpenFile(Path, FileMode::Read);
if (f) if (f)
{ {
fread(Buffer, 1, Length, f); FileRead(Buffer, 1, Length, f);
fclose(f); CloseFile(f);
} }
} }
else else
@ -177,12 +176,12 @@ void SaveManager::FlushSecondaryBuffer(u8* dst, u32 dstLength)
} }
else else
{ {
FILE* f = Platform::OpenFile(Path, "wb"); FileHandle* f = Platform::OpenFile(Path, FileMode::Write);
if (f) if (f)
{ {
Log(LogLevel::Info, "SaveManager: Written\n"); Log(LogLevel::Info, "SaveManager: Written\n");
fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f); FileWrite(SecondaryBuffer, SecondaryBufferLength, 1, f);
fclose(f); CloseFile(f);
} }
} }
PreviousFlushVersion = FlushVersion; PreviousFlushVersion = FlushVersion;

View File

@ -30,8 +30,7 @@
#include "ui_TitleManagerDialog.h" #include "ui_TitleManagerDialog.h"
#include "ui_TitleImportDialog.h" #include "ui_TitleImportDialog.h"
using Platform::Log; using namespace Platform;
using Platform::LogLevel;
bool TitleManagerDialog::NANDInited = false; bool TitleManagerDialog::NANDInited = false;
TitleManagerDialog* TitleManagerDialog::currentDlg = nullptr; TitleManagerDialog* TitleManagerDialog::currentDlg = nullptr;
@ -140,14 +139,14 @@ bool TitleManagerDialog::openNAND()
{ {
NANDInited = false; NANDInited = false;
FILE* bios7i = Platform::OpenLocalFile(Config::DSiBIOS7Path, "rb"); FileHandle* bios7i = Platform::OpenLocalFile(Config::DSiBIOS7Path, FileMode::Read);
if (!bios7i) if (!bios7i)
return false; return false;
u8 es_keyY[16]; u8 es_keyY[16];
fseek(bios7i, 0x8308, SEEK_SET); FileSeek(bios7i, 0x8308, FileSeekOrigin::Start);
fread(es_keyY, 16, 1, bios7i); FileRead(es_keyY, 16, 1, bios7i);
fclose(bios7i); CloseFile(bios7i);
if (!DSi_NAND::Init(es_keyY)) if (!DSi_NAND::Init(es_keyY))
{ {

View File

@ -2639,7 +2639,7 @@ void MainWindow::onImportSavefile()
return; return;
} }
FILE* f = Platform::OpenFile(path.toStdString(), "rb", true); Platform::FileHandle* f = Platform::OpenFile(path.toStdString(), Platform::FileMode::Read);
if (!f) if (!f)
{ {
QMessageBox::critical(this, "melonDS", "Could not open the given savefile."); QMessageBox::critical(this, "melonDS", "Could not open the given savefile.");
@ -2661,18 +2661,16 @@ void MainWindow::onImportSavefile()
ROMManager::Reset(); ROMManager::Reset();
} }
u32 len; u32 len = FileLength(f);
fseek(f, 0, SEEK_END);
len = (u32)ftell(f);
u8* data = new u8[len]; u8* data = new u8[len];
fseek(f, 0, SEEK_SET); Platform::FileRewind(f);
fread(data, len, 1, f); Platform::FileRead(data, len, 1, f);
NDS::LoadSave(data, len); NDS::LoadSave(data, len);
delete[] data; delete[] data;
fclose(f); CloseFile(f);
emuThread->emuUnpause(); emuThread->emuUnpause();
} }
@ -3196,8 +3194,6 @@ void emuStop()
RunningSomething = false; RunningSomething = false;
emit emuThread->windowEmuStop(); emit emuThread->windowEmuStop();
OSD::AddMessage(0xFFC040, "Shutdown");
} }
MelonApplication::MelonApplication(int& argc, char** argv) MelonApplication::MelonApplication(int& argc, char** argv)