2021-11-25 10:20:56 +01:00
|
|
|
#include <cstdio>
|
|
|
|
|
|
|
|
|
|
#include <mutex>
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
|
|
#include <QDir>
|
|
|
|
|
#include <QFileInfo>
|
|
|
|
|
#include <QTemporaryFile>
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
|
|
|
|
|
#include <QLibrary>
|
|
|
|
|
#include <QElapsedTimer>
|
|
|
|
|
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
// static QByteArray buf;
|
|
|
|
|
extern QElapsedTimer elapsed_timer;
|
|
|
|
|
QElapsedTimer elapsed_timer;
|
|
|
|
|
static std::mutex blitmx;
|
|
|
|
|
|
|
|
|
|
class CharPointer {
|
|
|
|
|
public:
|
|
|
|
|
CharPointer(char* buf, int size) : b(buf), s(size) {}
|
|
|
|
|
CharPointer& operator=(const QByteArray &ba) {
|
|
|
|
|
if (s > 0) {
|
|
|
|
|
strncpy(b, ba.data(), s-1);
|
|
|
|
|
b[s] = 0;
|
|
|
|
|
} else {
|
|
|
|
|
// if we haven't been told the length of b, just assume enough
|
|
|
|
|
// because we didn't get it from emulator code
|
|
|
|
|
strcpy(b, ba.data());
|
|
|
|
|
b[ba.size()] = 0;
|
|
|
|
|
}
|
|
|
|
|
return *this;
|
|
|
|
|
}
|
|
|
|
|
private:
|
|
|
|
|
char* b;
|
|
|
|
|
int s;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
#include <86box/86box.h>
|
|
|
|
|
#include <86box/device.h>
|
|
|
|
|
#include <86box/gameport.h>
|
|
|
|
|
#include <86box/plat_dynld.h>
|
|
|
|
|
#include <86box/config.h>
|
|
|
|
|
#include <86box/ui.h>
|
|
|
|
|
|
|
|
|
|
#include "../cpu/cpu.h"
|
|
|
|
|
#include <86box/plat.h>
|
|
|
|
|
|
|
|
|
|
volatile int cpu_thread_run = 1;
|
|
|
|
|
int mouse_capture = 0;
|
|
|
|
|
int fixed_size_x = 640;
|
|
|
|
|
int fixed_size_y = 480;
|
|
|
|
|
int rctrl_is_lalt = 0;
|
|
|
|
|
int update_icons = 0;
|
|
|
|
|
int kbd_req_capture = 0;
|
|
|
|
|
int hide_status_bar = 0;
|
|
|
|
|
uint32_t lang_id = 0x0409, lang_sys = 0x0409; // Multilangual UI variables, for now all set to LCID of en-US
|
|
|
|
|
|
|
|
|
|
plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS];
|
|
|
|
|
joystick_t joystick_state[MAX_JOYSTICKS];
|
|
|
|
|
|
|
|
|
|
int stricmp(const char* s1, const char* s2)
|
|
|
|
|
{
|
|
|
|
|
return QByteArray(s1).compare(s2, Qt::CaseInsensitive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int strnicmp(const char *s1, const char *s2, size_t n)
|
|
|
|
|
{
|
|
|
|
|
QByteArray b1(s1, std::min(strlen(s1), n));
|
|
|
|
|
QByteArray b2(s2, std::min(strlen(s2), n));
|
|
|
|
|
return b1.compare(b2, Qt::CaseInsensitive);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
do_stop(void)
|
|
|
|
|
{
|
|
|
|
|
QCoreApplication::quit();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void plat_get_exe_name(char *s, int size)
|
|
|
|
|
{
|
|
|
|
|
CharPointer(s, size) = QCoreApplication::applicationFilePath().toUtf8();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t
|
|
|
|
|
plat_get_ticks(void)
|
|
|
|
|
{
|
|
|
|
|
return elapsed_timer.elapsed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t
|
|
|
|
|
plat_timer_read(void)
|
|
|
|
|
{
|
|
|
|
|
return elapsed_timer.elapsed();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FILE *
|
|
|
|
|
plat_fopen(const char *path, const char *mode)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
QString filepath(path);
|
|
|
|
|
if (filepath.isEmpty()) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qWarning() << "plat_fopen" << filepath;
|
|
|
|
|
bool ok = false;
|
|
|
|
|
QFile file(filepath);
|
|
|
|
|
auto mode_len = strlen(mode);
|
|
|
|
|
for (size_t i = 0; i < mode_len; ++i) {
|
|
|
|
|
switch (mode[i]) {
|
|
|
|
|
case 'r':
|
|
|
|
|
ok = file.open(QIODevice::ReadOnly);
|
|
|
|
|
break;
|
|
|
|
|
case 'w':
|
|
|
|
|
ok = file.open(QIODevice::ReadWrite);
|
|
|
|
|
break;
|
|
|
|
|
case 'b':
|
|
|
|
|
case 't':
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
qWarning() << "Unhandled open mode" << mode[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ok) {
|
|
|
|
|
qDebug() << "filehandle" << file.handle();
|
|
|
|
|
QFile returned;
|
|
|
|
|
qDebug() << "\t" << returned.open(file.handle(), file.openMode(), QFileDevice::FileHandleFlag::DontCloseHandle);
|
|
|
|
|
return fdopen(returned.handle(), mode);
|
|
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
#ifdef Q_OS_WINDOWS
|
|
|
|
|
wchar_t *pathw, *modew;
|
|
|
|
|
int len;
|
|
|
|
|
FILE *fp;
|
|
|
|
|
|
|
|
|
|
if (acp_utf8)
|
|
|
|
|
return fopen(path, mode);
|
|
|
|
|
else {
|
|
|
|
|
len = mbstoc16s(NULL, path, 0) + 1;
|
|
|
|
|
pathw = malloc(sizeof(wchar_t) * len);
|
|
|
|
|
mbstoc16s(pathw, path, len);
|
|
|
|
|
|
|
|
|
|
len = mbstoc16s(NULL, mode, 0) + 1;
|
|
|
|
|
modew = malloc(sizeof(wchar_t) * len);
|
|
|
|
|
mbstoc16s(modew, mode, len);
|
|
|
|
|
|
|
|
|
|
fp = _wfopen(pathw, modew);
|
|
|
|
|
|
|
|
|
|
free(pathw);
|
|
|
|
|
free(modew);
|
|
|
|
|
|
|
|
|
|
return fp;
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef Q_OS_UNIX
|
|
|
|
|
return fopen(path, mode);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
FILE *
|
|
|
|
|
plat_fopen64(const char *path, const char *mode)
|
|
|
|
|
{
|
|
|
|
|
return fopen(path, mode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plat_dir_create(char *path)
|
|
|
|
|
{
|
|
|
|
|
return QDir().mkdir(path) ? 0 : -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plat_dir_check(char *path)
|
|
|
|
|
{
|
|
|
|
|
QFileInfo fi(path);
|
|
|
|
|
return fi.isDir() ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plat_getcwd(char *bufp, int max)
|
|
|
|
|
{
|
|
|
|
|
CharPointer(bufp, max) = QDir::currentPath().toUtf8();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_get_dirname(char *dest, const char *path)
|
|
|
|
|
{
|
|
|
|
|
QFileInfo fi(path);
|
|
|
|
|
CharPointer(dest, -1) = fi.dir().path().toUtf8();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
plat_get_extension(char *s)
|
|
|
|
|
{
|
|
|
|
|
auto len = strlen(s);
|
|
|
|
|
auto idx = QByteArray::fromRawData(s, len).lastIndexOf('.');
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
return s+idx+1;
|
|
|
|
|
}
|
|
|
|
|
return s+len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
|
|
|
|
plat_get_filename(char *s)
|
|
|
|
|
{
|
|
|
|
|
auto idx = QByteArray::fromRawData(s, strlen(s)).lastIndexOf(QDir::separator().toLatin1());
|
|
|
|
|
if (idx >= 0) {
|
|
|
|
|
return s+idx+1;
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
plat_path_abs(char *path)
|
|
|
|
|
{
|
|
|
|
|
QFileInfo fi(path);
|
|
|
|
|
return fi.isAbsolute() ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_path_slash(char *path)
|
|
|
|
|
{
|
|
|
|
|
auto len = strlen(path);
|
|
|
|
|
auto separator = QDir::separator().toLatin1();
|
|
|
|
|
if (path[len-1] != separator) {
|
|
|
|
|
path[len] = separator;
|
|
|
|
|
path[len+1] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_append_filename(char *dest, const char *s1, const char *s2)
|
|
|
|
|
{
|
|
|
|
|
strcpy(dest, s1);
|
|
|
|
|
plat_path_slash(dest);
|
|
|
|
|
strcat(dest, s2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_tempfile(char *bufp, char *prefix, char *suffix)
|
|
|
|
|
{
|
|
|
|
|
QString name;
|
|
|
|
|
|
|
|
|
|
if (prefix != nullptr) {
|
|
|
|
|
name.append(QString("%1-").arg(prefix));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
name.append("XXXXXX");
|
|
|
|
|
|
|
|
|
|
if (suffix != nullptr) {
|
|
|
|
|
name.append(suffix);
|
|
|
|
|
}
|
|
|
|
|
QTemporaryFile temp(name);
|
|
|
|
|
QByteArray buf(bufp);
|
|
|
|
|
buf = temp.fileName().toUtf8();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void plat_remove(char* path)
|
|
|
|
|
{
|
|
|
|
|
QFile(path).remove();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *
|
|
|
|
|
plat_mmap(size_t size, uint8_t executable)
|
|
|
|
|
{
|
|
|
|
|
#if defined Q_OS_WINDOWS
|
|
|
|
|
return VirtualAlloc(NULL, size, MEM_COMMIT, executable ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
|
|
|
|
|
#elif defined Q_OS_UNIX
|
|
|
|
|
#if defined Q_OS_DARWIN && defined MAP_JIT
|
|
|
|
|
void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE | (executable ? MAP_JIT : 0), 0, 0);
|
|
|
|
|
#else
|
|
|
|
|
void *ret = mmap(0, size, PROT_READ | PROT_WRITE | (executable ? PROT_EXEC : 0), MAP_ANON | MAP_PRIVATE, 0, 0);
|
|
|
|
|
auto retval = *reinterpret_cast<int*>(ret);
|
|
|
|
|
return (retval < 0) ? nullptr : ret;
|
|
|
|
|
#endif
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_munmap(void *ptr, size_t size)
|
|
|
|
|
{
|
|
|
|
|
munmap(ptr, size);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_pause(int p)
|
|
|
|
|
{
|
|
|
|
|
static wchar_t oldtitle[512];
|
|
|
|
|
wchar_t title[512];
|
|
|
|
|
|
|
|
|
|
dopause = p;
|
|
|
|
|
if (p) {
|
|
|
|
|
wcsncpy(oldtitle, ui_window_title(NULL), sizeof_w(oldtitle) - 1);
|
|
|
|
|
wcscpy(title, oldtitle);
|
|
|
|
|
wcscat(title, L" - PAUSED -");
|
|
|
|
|
ui_window_title(title);
|
|
|
|
|
} else {
|
|
|
|
|
ui_window_title(oldtitle);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// because we can't include nvr.h because it's got fields named new
|
|
|
|
|
extern int nvr_save(void);
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
plat_power_off(void)
|
|
|
|
|
{
|
|
|
|
|
confirm_exit = 0;
|
|
|
|
|
nvr_save();
|
|
|
|
|
config_save();
|
|
|
|
|
|
|
|
|
|
/* Deduct a sufficiently large number of cycles that no instructions will
|
|
|
|
|
run before the main thread is terminated */
|
|
|
|
|
cycles -= 99999999;
|
|
|
|
|
|
|
|
|
|
cpu_thread_run = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void set_language(uint32_t id) {
|
|
|
|
|
lang_id = id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Sets up the program language before initialization. */
|
|
|
|
|
uint32_t plat_language_code(char* langcode) {
|
|
|
|
|
/* or maybe not */
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Converts back the language code to LCID */
|
|
|
|
|
void plat_language_code_r(uint32_t lcid, char* outbuf, int len) {
|
|
|
|
|
/* or maybe not */
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void* dynld_module(const char *name, dllimp_t *table)
|
|
|
|
|
{
|
2021-11-30 20:34:07 +01:00
|
|
|
QString libraryName = name;
|
|
|
|
|
QFileInfo fi(libraryName);
|
|
|
|
|
QStringList removeSuffixes = {"dll", "dylib", "so"};
|
|
|
|
|
if (removeSuffixes.contains(fi.suffix())) {
|
|
|
|
|
libraryName = fi.completeBaseName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto lib = std::unique_ptr<QLibrary>(new QLibrary(libraryName));
|
2021-11-25 10:20:56 +01:00
|
|
|
if (lib->load()) {
|
|
|
|
|
for (auto imp = table; imp->name != nullptr; imp++)
|
|
|
|
|
{
|
2021-11-30 20:34:07 +01:00
|
|
|
auto ptr = lib->resolve(imp->name);
|
|
|
|
|
if (ptr == nullptr) {
|
2021-11-25 10:20:56 +01:00
|
|
|
return nullptr;
|
|
|
|
|
}
|
2021-11-30 20:34:07 +01:00
|
|
|
auto imp_ptr = reinterpret_cast<void**>(imp->func);
|
|
|
|
|
*imp_ptr = reinterpret_cast<void*>(ptr);
|
2021-11-25 10:20:56 +01:00
|
|
|
}
|
2021-11-30 20:20:53 +01:00
|
|
|
} else {
|
|
|
|
|
return nullptr;
|
2021-11-25 10:20:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return lib.release();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void dynld_close(void *handle)
|
|
|
|
|
{
|
|
|
|
|
delete reinterpret_cast<QLibrary*>(handle);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void joystick_init(void) {}
|
|
|
|
|
void joystick_close(void) {}
|
|
|
|
|
void joystick_process(void) {}
|
|
|
|
|
void startblit()
|
|
|
|
|
{
|
|
|
|
|
blitmx.lock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void endblit()
|
|
|
|
|
{
|
|
|
|
|
blitmx.unlock();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|