From 6cfe4faa56f4c7c34bf42cd600c66a2ed7966062 Mon Sep 17 00:00:00 2001 From: Nadia Holmquist Pedersen Date: Wed, 6 May 2020 02:36:47 +0200 Subject: [PATCH] Use Qt abstractions for file I/O and threading on both Windows and Linux. --- src/frontend/qt_sdl/CMakeLists.txt | 13 +- src/frontend/qt_sdl/Platform.cpp | 521 ++++++++++------------------- 2 files changed, 183 insertions(+), 351 deletions(-) diff --git a/src/frontend/qt_sdl/CMakeLists.txt b/src/frontend/qt_sdl/CMakeLists.txt index f03cad2d..0b39a1c3 100644 --- a/src/frontend/qt_sdl/CMakeLists.txt +++ b/src/frontend/qt_sdl/CMakeLists.txt @@ -17,6 +17,7 @@ endif() find_package(Qt5 COMPONENTS Core REQUIRED) find_package(Qt5 COMPONENTS Gui REQUIRED) find_package(Qt5 COMPONENTS Widgets REQUIRED) +find_package(Threads REQUIRED) set(CMAKE_AUTOMOC ON) @@ -27,22 +28,24 @@ add_executable(melonDS ${SOURCES_QT_SDL}) target_include_directories(melonDS PRIVATE ${SDL2_INCLUDE_DIRS}) target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..") target_include_directories(melonDS PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/../..") -target_link_libraries(melonDS core ${SDL2_LIBRARIES}) +target_link_libraries(melonDS core ${SDL2_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) if (UNIX) - option(UNIX_PORTABLE "Make a portable build that looks for its configuration in the current directory" OFF) - if (UNIX_PORTABLE) - add_definitions(-DUNIX_PORTABLE) - endif() + option(PORTABLE "Make a portable build that looks for its configuration in the current directory" OFF) if (CMAKE_SYSTEM_NAME STREQUAL "Linux") target_link_libraries(melonDS dl Qt5::Core Qt5::Gui Qt5::Widgets) endif () elseif (WIN32) + option(PORTABLE "Make a portable build that looks for its configuration in the current directory" ON) target_sources(melonDS PUBLIC "${CMAKE_SOURCE_DIR}/melon.rc") target_link_libraries(melonDS comctl32 d2d1 dwrite uxtheme ws2_32 iphlpapi gdi32 Qt5::Core Qt5::Gui Qt5::Widgets) endif () +if (PORTABLE) + add_definitions(-DPORTABLE) +endif() + install(FILES ../../net.kuribo64.melonDS.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) install(FILES ../../icon/melon_16x16.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/16x16/apps RENAME net.kuribo64.melonDS.png) install(FILES ../../icon/melon_32x32.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/icons/hicolor/32x32/apps RENAME net.kuribo64.melonDS.png) diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index de8db93a..ddf48e91 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -19,34 +19,36 @@ #include #include #include -#include +#include +#include +#include +#include +#include + #include "Platform.h" #include "PlatformConfig.h" //#include "LAN_Socket.h" //#include "LAN_PCap.h" -#include #ifdef __WIN32__ - #define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK - #include - //#include // FUCK THAT SHIT - extern "C" const GUID DECLSPEC_SELECTANY FOLDERID_RoamingAppData = {0x3eb685db, 0x65f9, 0x4cf6, {0xa0, 0x3a, 0xe3, 0xef, 0x65, 0x72, 0x9f, 0x3d}}; - #include - #include - #include - #define socket_t SOCKET - #define sockaddr_t SOCKADDR +#define NTDDI_VERSION 0x06000000 // GROSS FUCKING HACK +#include +//#include // FUCK THAT SHIT +#include +#include +#include +#define socket_t SOCKET +#define sockaddr_t SOCKADDR #else - #include - #include - #include - #include - #include - #include - #include - #define socket_t int - #define sockaddr_t struct sockaddr - #define closesocket close + +#include +#include +#include +#include + +#define socket_t int +#define sockaddr_t struct sockaddr +#define closesocket close #endif #ifndef INVALID_SOCKET @@ -62,22 +64,6 @@ void Stop(bool internal); namespace Platform { - -typedef struct -{ - SDL_Thread* ID; - void (*Func)(); - -} ThreadData; - -int ThreadEntry(void* data) -{ - ThreadData* thread = (ThreadData*)data; - thread->Func(); - return 0; -} - - socket_t MPSocket; sockaddr_t MPSendAddr; u8 PacketBuffer[2048]; @@ -87,307 +73,151 @@ u8 PacketBuffer[2048]; void StopEmu() { - //Stop(true); + //Stop(true); } - FILE* OpenFile(const char* path, const char* mode, bool mustexist) { - FILE* ret; + QFile f(path); -#ifdef __WIN32__ + if (!mustexist && !f.exists()) + return nullptr; - int len = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); - if (len < 1) return NULL; - WCHAR* fatpath = new WCHAR[len]; - int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, fatpath, len); - if (res != len) { delete[] fatpath; return NULL; } // checkme? + f.open(QIODevice::ReadOnly); + FILE* file = fdopen(dup(f.handle()), mode); + f.close(); - // this will be more than enough - WCHAR fatmode[4]; - fatmode[0] = mode[0]; - fatmode[1] = mode[1]; - fatmode[2] = mode[2]; - fatmode[3] = 0; - - if (mustexist) - { - ret = _wfopen(fatpath, L"rb"); - if (ret) ret = _wfreopen(fatpath, fatmode, ret); - } - else - ret = _wfopen(fatpath, fatmode); - - delete[] fatpath; - -#else - - if (mustexist) - { - ret = fopen(path, "rb"); - if (ret) ret = freopen(path, mode, ret); - } - else - ret = fopen(path, mode); - -#endif - - return ret; + return file; } -#if !defined(UNIX_PORTABLE) && !defined(__WIN32__) - FILE* OpenLocalFile(const char* path, const char* mode) { - std::string fullpath; + QString fullpath; - if (path[0] == '/') - { - // If it's an absolute path, just open that. - fullpath = std::string(path); - } - else - { - // Check user configuration directory - QString confpath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/melonDS/"; - confpath.append(path); + if (path[0] == '/') + { + // If it's an absolute path, just open that. + fullpath = path; + } + else + { +#ifdef PORTABLE + fullpath = QString("./") + path; +#else + // Check user configuration directory + fullpath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + "/melonDS/"; + fullpath.append(path); +#endif + } - fullpath = confpath.toStdString(); - } - - return OpenFile(fullpath.c_str(), mode, mode[0] != 'w'); + return OpenFile(fullpath.toUtf8(), mode, mode[0] != 'w'); } FILE* OpenDataFile(const char* path) { - QString melondir = "melonDS"; - QStringList sys_dirs = QStandardPaths::standardLocations(QStandardPaths::DataLocation); - QString sep = QDir::separator(); +#ifdef PORTABLE + return OpenLocalFile(path); +#else + QString melondir = "/melonDS/"; + QStringList sys_dirs = QStandardPaths::standardLocations(QStandardPaths::DataLocation); + QString found = nullptr; - const char* found = NULL; + for (int i = 0; i < sys_dirs.size(); i++) + { + QString f = sys_dirs.at(i) + melondir + path; - for (int i = 0; i < sys_dirs.size(); i++) { - QString f = sys_dirs.at(i) + sep + melondir + sep + QString(path); + if (QFile::exists(f)) + { + found = f; + break; + } + } - if (QFile::exists(f)) { - found = f.toStdString().c_str(); - break; - } - } + if (found == nullptr) + return nullptr; - if (found == NULL) - return NULL; + FILE* f = OpenFile(found.toUtf8(), "rb", false); + if (f) + return f; - FILE* f = fopen(found, "rb"); - if (f) - return f; - - return NULL; + return nullptr; +#endif } -#else - -FILE* OpenLocalFile(const char* path, const char* mode) +void* Thread_Create(void (* func)()) { - bool relpath = false; - int pathlen = strlen(path); - -#ifdef __WIN32__ - if (pathlen > 3) - { - if (path[1] == ':' && path[2] == '\\') - return OpenFile(path, mode); - } -#else - if (pathlen > 1) - { - if (path[0] == '/') - return OpenFile(path, mode); - } -#endif - - if (pathlen >= 3) - { - if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || path[2] == '\\')) - relpath = true; - } - - int emudirlen = strlen(EmuDirectory); - char* emudirpath; - if (emudirlen) - { - int len = emudirlen + 1 + pathlen + 1; - emudirpath = new char[len]; - strncpy(&emudirpath[0], EmuDirectory, emudirlen); - emudirpath[emudirlen] = '/'; - strncpy(&emudirpath[emudirlen+1], path, pathlen); - emudirpath[emudirlen+1+pathlen] = '\0'; - } - else - { - emudirpath = new char[pathlen+1]; - strncpy(&emudirpath[0], path, pathlen); - emudirpath[pathlen] = '\0'; - } - - // Locations are application directory, and AppData/melonDS on Windows or XDG_CONFIG_HOME/melonDS on Linux - - FILE* f; - - // First check current working directory - f = OpenFile(path, mode, true); - if (f) { delete[] emudirpath; return f; } - - // then emu directory - f = OpenFile(emudirpath, mode, true); - if (f) { delete[] emudirpath; return f; } - -#ifdef __WIN32__ - - // a path relative to AppData wouldn't make much sense - if (!relpath) - { - // Now check AppData - PWSTR appDataPath = NULL; - SHGetKnownFolderPath(FOLDERID_RoamingAppData, 0, NULL, &appDataPath); - if (!appDataPath) - { - delete[] emudirpath; - return NULL; - } - - // this will be more than enough - WCHAR fatperm[4]; - fatperm[0] = mode[0]; - fatperm[1] = mode[1]; - fatperm[2] = mode[2]; - fatperm[3] = 0; - - int fnlen = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0); - if (fnlen < 1) { delete[] emudirpath; return NULL; } - WCHAR* wfileName = new WCHAR[fnlen]; - int res = MultiByteToWideChar(CP_UTF8, 0, path, -1, wfileName, fnlen); - if (res != fnlen) { delete[] wfileName; delete[] emudirpath; return NULL; } // checkme? - - const WCHAR* appdir = L"\\melonDS\\"; - - int pos = wcslen(appDataPath); - void* ptr = CoTaskMemRealloc(appDataPath, (pos+wcslen(appdir)+fnlen+1)*sizeof(WCHAR)); - if (!ptr) { delete[] wfileName; delete[] emudirpath; return NULL; } // oh well - appDataPath = (PWSTR)ptr; - - wcscpy(&appDataPath[pos], appdir); pos += wcslen(appdir); - wcscpy(&appDataPath[pos], wfileName); - - f = _wfopen(appDataPath, L"rb"); - if (f) f = _wfreopen(appDataPath, fatperm, f); - CoTaskMemFree(appDataPath); - delete[] wfileName; - if (f) { delete[] emudirpath; return f; } - } - -#else - - if (!relpath) - { - // Now check XDG_CONFIG_HOME - // TODO: check for memory leak there - std::string fullpath = QStandardPaths::writableLocation(QStandardPaths::ConfigLocation).toStdString() + "/melonDS/" + path; - f = OpenFile(fullpath.c_str(), mode, true); - if (f) { delete[] emudirpath; return f; } - } - -#endif - - if (mode[0] != 'r') - { - f = OpenFile(emudirpath, mode); - if (f) { delete[] emudirpath; return f; } - } - - delete[] emudirpath; - return NULL; -} - -FILE* OpenDataFile(const char* path) -{ - return OpenLocalFile(path, "rb"); -} - -#endif - - -void* Thread_Create(void (*func)()) -{ - ThreadData* data = new ThreadData; - data->Func = func; - data->ID = SDL_CreateThread(ThreadEntry, "melonDS core thread", data); - return data; + QThread* t = QThread::create(func); + t->start(); + return (void*) t; } void Thread_Free(void* thread) { - delete (ThreadData*)thread; + QThread* t = (QThread*) thread; + t->terminate(); + delete t; } void Thread_Wait(void* thread) { - SDL_WaitThread((SDL_Thread*)((ThreadData*)thread)->ID, NULL); + ((QThread*) thread)->wait(); } void* Semaphore_Create() { - return SDL_CreateSemaphore(0); + return new QSemaphore(); } void Semaphore_Free(void* sema) { - SDL_DestroySemaphore((SDL_sem*)sema); + delete (QSemaphore*) sema; } void Semaphore_Reset(void* sema) { - while (SDL_SemTryWait((SDL_sem*)sema) == 0); + QSemaphore* s = (QSemaphore*) sema; + + s->acquire(s->available()); } void Semaphore_Wait(void* sema) { - SDL_SemWait((SDL_sem*)sema); + ((QSemaphore*) sema)->acquire(); } void Semaphore_Post(void* sema) { - SDL_SemPost((SDL_sem*)sema); + ((QSemaphore*) sema)->release(); } void* GL_GetProcAddress(const char* proc) { - return NULL;//uiGLGetProcAddress(proc); + return (void*) QOpenGLContext::globalShareContext()->getProcAddress(proc); } bool MP_Init() { - int opt_true = 1; - int res; + int opt_true = 1; + int res; #ifdef __WIN32__ - WSADATA wsadata; - if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) - { - return false; - } + WSADATA wsadata; + if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) + { + return false; + } #endif // __WIN32__ - MPSocket = socket(AF_INET, SOCK_DGRAM, 0); + MPSocket = socket(AF_INET, SOCK_DGRAM, 0); if (MPSocket < 0) { return false; } - res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt_true, sizeof(int)); + res = setsockopt(MPSocket, SOL_SOCKET, SO_REUSEADDR, (const char*) &opt_true, sizeof(int)); if (res < 0) { closesocket(MPSocket); @@ -397,8 +227,8 @@ bool MP_Init() sockaddr_t saddr; saddr.sa_family = AF_INET; - *(u32*)&saddr.sa_data[2] = htonl(Config::SocketBindAnyAddr ? INADDR_ANY : INADDR_LOOPBACK); - *(u16*)&saddr.sa_data[0] = htons(7064); + *(u32*) &saddr.sa_data[2] = htonl(Config::SocketBindAnyAddr ? INADDR_ANY : INADDR_LOOPBACK); + *(u16*) &saddr.sa_data[0] = htons(7064); res = bind(MPSocket, &saddr, sizeof(sockaddr_t)); if (res < 0) { @@ -407,7 +237,7 @@ bool MP_Init() return false; } - res = setsockopt(MPSocket, SOL_SOCKET, SO_BROADCAST, (const char*)&opt_true, sizeof(int)); + res = setsockopt(MPSocket, SOL_SOCKET, SO_BROADCAST, (const char*) &opt_true, sizeof(int)); if (res < 0) { closesocket(MPSocket); @@ -416,50 +246,50 @@ bool MP_Init() } MPSendAddr.sa_family = AF_INET; - *(u32*)&MPSendAddr.sa_data[2] = htonl(INADDR_BROADCAST); - *(u16*)&MPSendAddr.sa_data[0] = htons(7064); + *(u32*) &MPSendAddr.sa_data[2] = htonl(INADDR_BROADCAST); + *(u16*) &MPSendAddr.sa_data[0] = htons(7064); return true; } void MP_DeInit() { - if (MPSocket >= 0) - closesocket(MPSocket); + if (MPSocket >= 0) + closesocket(MPSocket); #ifdef __WIN32__ - WSACleanup(); + WSACleanup(); #endif // __WIN32__ } int MP_SendPacket(u8* data, int len) { - if (MPSocket < 0) - return 0; + if (MPSocket < 0) + return 0; - if (len > 2048-8) - { - printf("MP_SendPacket: error: packet too long (%d)\n", len); - return 0; - } + if (len > 2048 - 8) + { + printf("MP_SendPacket: error: packet too long (%d)\n", len); + return 0; + } - *(u32*)&PacketBuffer[0] = htonl(0x4946494E); // NIFI - PacketBuffer[4] = NIFI_VER; - PacketBuffer[5] = 0; - *(u16*)&PacketBuffer[6] = htons(len); - memcpy(&PacketBuffer[8], data, len); + *(u32*) &PacketBuffer[0] = htonl(0x4946494E); // NIFI + PacketBuffer[4] = NIFI_VER; + PacketBuffer[5] = 0; + *(u16*) &PacketBuffer[6] = htons(len); + memcpy(&PacketBuffer[8], data, len); - int slen = sendto(MPSocket, (const char*)PacketBuffer, len+8, 0, &MPSendAddr, sizeof(sockaddr_t)); - if (slen < 8) return 0; - return slen - 8; + int slen = sendto(MPSocket, (const char*) PacketBuffer, len + 8, 0, &MPSendAddr, sizeof(sockaddr_t)); + if (slen < 8) return 0; + return slen - 8; } int MP_RecvPacket(u8* data, bool block) { - if (MPSocket < 0) - return 0; + if (MPSocket < 0) + return 0; - fd_set fd; + fd_set fd; struct timeval tv; FD_ZERO(&fd); @@ -467,84 +297,83 @@ int MP_RecvPacket(u8* data, bool block) tv.tv_sec = 0; tv.tv_usec = block ? 5000 : 0; - if (!select(MPSocket+1, &fd, 0, 0, &tv)) - { - return 0; - } + if (!select(MPSocket + 1, &fd, 0, 0, &tv)) + { + return 0; + } - sockaddr_t fromAddr; - socklen_t fromLen = sizeof(sockaddr_t); - int rlen = recvfrom(MPSocket, (char*)PacketBuffer, 2048, 0, &fromAddr, &fromLen); - if (rlen < 8+24) - { - return 0; - } - rlen -= 8; + sockaddr_t fromAddr; + socklen_t fromLen = sizeof(sockaddr_t); + int rlen = recvfrom(MPSocket, (char*) PacketBuffer, 2048, 0, &fromAddr, &fromLen); + if (rlen < 8 + 24) + { + return 0; + } + rlen -= 8; - if (ntohl(*(u32*)&PacketBuffer[0]) != 0x4946494E) - { - return 0; - } + if (ntohl(*(u32*) &PacketBuffer[0]) != 0x4946494E) + { + return 0; + } - if (PacketBuffer[4] != NIFI_VER) - { - return 0; - } + if (PacketBuffer[4] != NIFI_VER) + { + return 0; + } - if (ntohs(*(u16*)&PacketBuffer[6]) != rlen) - { - return 0; - } + if (ntohs(*(u16*) &PacketBuffer[6]) != rlen) + { + return 0; + } - memcpy(data, &PacketBuffer[8], rlen); - return rlen; + memcpy(data, &PacketBuffer[8], rlen); + return rlen; } - bool LAN_Init() { - /*if (Config::DirectLAN) - { - if (!LAN_PCap::Init(true)) - return false; - } - else - { - if (!LAN_Socket::Init()) - return false; - }*/ + /*if (Config::DirectLAN) + { + if (!LAN_PCap::Init(true)) + return false; + } + else + { + if (!LAN_Socket::Init()) + return false; + }*/ - return true; + return true; } void LAN_DeInit() { - // checkme. blarg - //if (Config::DirectLAN) - // LAN_PCap::DeInit(); - //else - // LAN_Socket::DeInit(); - /*LAN_PCap::DeInit(); - LAN_Socket::DeInit();*/ + // checkme. blarg + //if (Config::DirectLAN) + // LAN_PCap::DeInit(); + //else + // LAN_Socket::DeInit(); + /*LAN_PCap::DeInit(); + LAN_Socket::DeInit();*/ } int LAN_SendPacket(u8* data, int len) { - /*if (Config::DirectLAN) - return LAN_PCap::SendPacket(data, len); - else - return LAN_Socket::SendPacket(data, len);*/ - return 0; + /*if (Config::DirectLAN) + return LAN_PCap::SendPacket(data, len); + else + return LAN_Socket::SendPacket(data, len);*/ + return 0; } int LAN_RecvPacket(u8* data) { - /*if (Config::DirectLAN) - return LAN_PCap::RecvPacket(data); - else - return LAN_Socket::RecvPacket(data);*/ - return 0; + /*if (Config::DirectLAN) + return LAN_PCap::RecvPacket(data); + else + return LAN_Socket::RecvPacket(data);*/ + return 0; }