Files
dusklight/src/dusk/dvd_emu.cpp
T
2026-02-20 21:13:50 +01:00

218 lines
5.0 KiB
C++

#include "dusk/dvd_emu.h"
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <unordered_map>
#include "dolphin/os.h"
#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#define PATH_SEP '\\'
#else
#include <sys/stat.h>
#include <unistd.h>
#define PATH_SEP '/'
#endif
namespace {
s32 g_nextEntryNum = 1;
// Lazy-init to avoid crash during DLL static initialization
std::string& g_basePath() {
static std::string instance = "data";
return instance;
}
std::unordered_map<s32, std::string>& getEntryPaths() {
static std::unordered_map<s32, std::string> instance;
return instance;
}
} // namespace
namespace DvdEmu {
void setBasePath(const char* path) {
#ifdef _WIN32
char exePath[MAX_PATH];
GetModuleFileNameA(NULL, exePath, MAX_PATH);
// Get the directory of the .exe
char* lastSlash = strrchr(exePath, '\\');
if (lastSlash) {
*lastSlash = '\0';
}
// exeDir + "/" + path
g_basePath() = exePath;
g_basePath() += PATH_SEP;
g_basePath() += path;
#else
g_basePath() = path;
#endif
printf("[DvdEmu] Base path set to: %s\n", g_basePath().c_str()); fflush(stdout);
}
const char* getBasePath() {
return g_basePath().c_str();
}
std::string convertPath(const char* gcPath) {
std::string result = g_basePath();
// Skip leading slashes
const char* p = gcPath;
while (*p == '/' || *p == '\\')
p++;
result += PATH_SEP;
// Append path, converting slashes
while (*p) {
if (*p == '/' || *p == '\\') {
result += PATH_SEP;
} else {
result += *p;
}
p++;
}
return result;
}
bool fileExists(const char* gcPath) {
std::string fullPath = convertPath(gcPath);
#ifdef _WIN32
DWORD attrib = GetFileAttributesA(fullPath.c_str());
bool exists = (attrib != INVALID_FILE_ATTRIBUTES && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
#else
struct stat st;
bool exists = (stat(fullPath.c_str(), &st) == 0 && S_ISREG(st.st_mode));
#endif
if (exists) {
printf("[DvdEmu] FOUND: %s\n", gcPath); fflush(stdout);
} else {
printf("[DvdEmu] MISSING: %s\n", gcPath); fflush(stdout);
}
return exists;
}
u32 getFileSize(const char* gcPath) {
std::string fullPath = convertPath(gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f)
return 0;
fseek(f, 0, SEEK_END);
u32 size = (u32)ftell(f);
fclose(f);
return size;
}
void* loadFile(const char* gcPath, u32* outSize, void* heap) {
std::string fullPath = convertPath(gcPath);
printf("[DvdEmu] Loading request: '%s'\n", gcPath); fflush(stdout);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
printf("[DvdEmu] ERROR: Failed to open file at physical path: %s\n", fullPath.c_str()); fflush(stdout);
if (outSize)
*outSize = 0;
return nullptr;
}
fseek(f, 0, SEEK_END);
u32 size = (u32)ftell(f);
fseek(f, 0, SEEK_SET);
// Allocate with 32-byte alignment (matching GameCube)
void* data;
#ifdef _WIN32
data = _aligned_malloc(size, 32);
#else
data = aligned_alloc(32, (size + 31) & ~31);
#endif
if (!data) {
printf("[DvdEmu] FATAL: Failed to allocate %u bytes for %s\n", size, gcPath); fflush(stdout);
fclose(f);
if (outSize)
*outSize = 0;
return nullptr;
}
u32 bytesRead = (u32)fread(data, 1, size, f);
fclose(f);
if (bytesRead != size) {
printf("[DvdEmu] WARNING: Read error: expected %u, got %u for %s\n", size, bytesRead,
gcPath); fflush(stdout);
}
if (outSize)
*outSize = bytesRead;
printf("[DvdEmu] SUCCESS: Loaded %s (%u bytes)\n", gcPath, bytesRead); fflush(stdout);
return data;
}
u32 loadFileToBuffer(const char* gcPath, void* buffer, u32 bufferSize, u32 offset) {
std::string fullPath = convertPath(gcPath);
FILE* f = fopen(fullPath.c_str(), "rb");
if (!f) {
printf("[DvdEmu] Failed to open file for buffer load: %s\n", fullPath.c_str()); fflush(stdout);
return 0;
}
if (offset > 0) {
fseek(f, offset, SEEK_SET);
}
u32 bytesRead = (u32)fread(buffer, 1, bufferSize, f);
fclose(f);
return bytesRead;
}
} // namespace DvdEmu
// Entry-Number System (emulates DVD's entry system)
s32 DVDConvertPathToEntrynum_Emu(const char* path) {
if (!DvdEmu::fileExists(path)) {
printf("[DVD] Error: File not found for entrynum conversion: %s\n", path); fflush(stdout);
return -1;
}
// Check if already registered
for (const auto& pair : getEntryPaths()) {
if (pair.second == path) {
return pair.first;
}
}
// Assign new entry number
s32 entryNum = g_nextEntryNum++;
getEntryPaths()[entryNum] = path;
return entryNum;
}
void DVDRegisterPath(s32 entryNum, const char* path) {
getEntryPaths()[entryNum] = path;
}
const char* DVDGetPathForEntry(s32 entryNum) {
auto it = getEntryPaths().find(entryNum);
if (it != getEntryPaths().end()) {
return it->second.c_str();
}
return nullptr;
}