mame/src/osd/modules/lib/osdlib_uwp.cpp
2016-11-10 13:13:51 +01:00

384 lines
10 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// sdlos_*.c - OS specific low level code
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <stdlib.h>
#ifndef _MSC_VER
#include <unistd.h>
#endif
#include <cstdio>
#include <memory>
// MAME headers
#include "osdlib.h"
#include "osdcomm.h"
#include "osdcore.h"
#include "strconv.h"
#include <windows.h>
#include <wrl\client.h>
#include "strconv.h"
using namespace Platform;
using namespace Windows::ApplicationModel::DataTransfer;
using namespace Windows::Foundation;
#include <map>
//============================================================
// MACROS
//============================================================
// presumed size of a page of memory
#define PAGE_SIZE 4096
// align allocations to start or end of the page?
#define GUARD_ALIGN_START 0
#if defined(__BIGGEST_ALIGNMENT__)
#define MAX_ALIGNMENT __BIGGEST_ALIGNMENT__
#elif defined(__AVX__)
#define MAX_ALIGNMENT 32
#elif defined(__SSE__) || defined(__x86_64__) || defined(_M_X64)
#define MAX_ALIGNMENT 16
#else
#define MAX_ALIGNMENT sizeof(int64_t)
#endif
//============================================================
// GLOBAL VARIABLES
//============================================================
std::map<const char *, std::unique_ptr<char>> g_runtime_environment;
//============================================================
// osd_getenv
//============================================================
const char *osd_getenv(const char *name)
{
for (auto iter = g_runtime_environment.begin(); iter != g_runtime_environment.end(); iter++)
{
if (stricmp(iter->first, name) == 0)
{
osd_printf_debug("ENVIRONMENT: Get %s = value: '%s'", name, iter->second.get());
return iter->second.get();
}
}
return nullptr;
}
//============================================================
// osd_setenv
//============================================================
int osd_setenv(const char *name, const char *value, int overwrite)
{
if (!overwrite)
{
if (osd_getenv(name) != nullptr)
return 0;
}
auto buf = std::make_unique<char>(strlen(name) + strlen(value) + 2);
sprintf(buf.get(), "%s=%s", name, value);
g_runtime_environment[name] = std::move(buf);
osd_printf_debug("ENVIRONMENT: Set %s to value: '%s'", name, buf.get());
return 0;
}
//============================================================
// osd_process_kill
//============================================================
void osd_process_kill()
{
std::fflush(stdout);
std::fflush(stderr);
TerminateProcess(GetCurrentProcess(), -1);
}
//============================================================
// osd_malloc
//============================================================
void *osd_malloc(size_t size)
{
#ifndef MALLOC_DEBUG
return malloc(size);
#else
// add in space for the size and offset
size += MAX_ALIGNMENT + sizeof(size_t) + 2;
size &= ~size_t(1);
// basic objects just come from the heap
uint8_t *const block = reinterpret_cast<uint8_t *>(HeapAlloc(GetProcessHeap(), 0, size));
if (block == nullptr)
return nullptr;
uint8_t *const result = reinterpret_cast<uint8_t *>(reinterpret_cast<uintptr_t>(block + sizeof(size_t) + MAX_ALIGNMENT) & ~(uintptr_t(MAX_ALIGNMENT) - 1));
// store the size and return and pointer to the data afterward
*reinterpret_cast<size_t *>(block) = size;
*(result - 1) = result - block;
return result;
#endif
}
//============================================================
// osd_malloc_array
//============================================================
void *osd_malloc_array(size_t size)
{
#ifndef MALLOC_DEBUG
return malloc(size);
#else
// add in space for the size and offset
size += MAX_ALIGNMENT + sizeof(size_t) + 2;
size &= ~size_t(1);
// round the size up to a page boundary
size_t const rounded_size = ((size + sizeof(void *) + PAGE_SIZE - 1) / PAGE_SIZE) * PAGE_SIZE;
// reserve that much memory, plus two guard pages
void *page_base = VirtualAlloc(nullptr, rounded_size + 2 * PAGE_SIZE, MEM_RESERVE, PAGE_NOACCESS);
if (page_base == nullptr)
return nullptr;
// now allow access to everything but the first and last pages
page_base = VirtualAlloc(reinterpret_cast<uint8_t *>(page_base) + PAGE_SIZE, rounded_size, MEM_COMMIT, PAGE_READWRITE);
if (page_base == nullptr)
return nullptr;
// work backwards from the page base to get to the block base
uint8_t *const block = GUARD_ALIGN_START ? reinterpret_cast<uint8_t *>(page_base) : (reinterpret_cast<uint8_t *>(page_base) + rounded_size - size);
uint8_t *const result = reinterpret_cast<uint8_t *>(reinterpret_cast<uintptr_t>(block + sizeof(size_t) + MAX_ALIGNMENT) & ~(uintptr_t(MAX_ALIGNMENT) - 1));
// store the size at the start with a flag indicating it has a guard page
*reinterpret_cast<size_t *>(block) = size | 1;
*(result - 1) = result - block;
return result;
#endif
}
//============================================================
// osd_free
//============================================================
void osd_free(void *ptr)
{
#ifndef MALLOC_DEBUG
free(ptr);
#else
uint8_t const offset = *(reinterpret_cast<uint8_t *>(ptr) - 1);
uint8_t *const block = reinterpret_cast<uint8_t *>(ptr) - offset;
size_t const size = *reinterpret_cast<size_t *>(block);
if ((size & 0x1) == 0)
{
// if no guard page, just free the pointer
HeapFree(GetProcessHeap(), 0, block);
}
else
{
// large items need more care
ULONG_PTR const page_base = reinterpret_cast<ULONG_PTR>(block) & ~(PAGE_SIZE - 1);
VirtualFree(reinterpret_cast<void *>(page_base - PAGE_SIZE), 0, MEM_RELEASE);
}
#endif
}
//============================================================
// osd_alloc_executable
//
// allocates "size" bytes of executable memory. this must take
// things like NX support into account.
//============================================================
void *osd_alloc_executable(size_t size)
{
return nullptr;
}
//============================================================
// osd_free_executable
//
// frees memory allocated with osd_alloc_executable
//============================================================
void osd_free_executable(void *ptr, size_t size)
{
}
//============================================================
// osd_break_into_debugger
//============================================================
void osd_break_into_debugger(const char *message)
{
#ifdef OSD_WINDOWS
if (IsDebuggerPresent())
{
win_output_debug_string_utf8(message);
DebugBreak();
}
else if (s_debugger_stack_crawler != nullptr)
(*s_debugger_stack_crawler)();
#else
if (IsDebuggerPresent())
{
OutputDebugStringA(message);
__debugbreak();
}
#endif
}
//============================================================
// get_clipboard_text_by_format
//============================================================
static char *get_clipboard_text_by_format(UINT format, std::string (*convert)(LPCVOID data))
{
/*DataPackageView^ dataPackageView;
IAsyncOperation<String^>^ getTextOp;
String^ clipboardText;
dataPackageView = Clipboard::GetContent();
getTextOp = dataPackageView->GetTextAsync();
clipboardText = getTextOp->GetResults();
return osd::text::from_wstring(clipboardText->Data()).c_str();*/
return nullptr;
}
//============================================================
// convert_wide
//============================================================
static std::string convert_wide(LPCVOID data)
{
return osd::text::from_wstring((LPCWSTR) data);
}
//============================================================
// convert_ansi
//============================================================
static std::string convert_ansi(LPCVOID data)
{
return osd::text::from_astring((LPCSTR) data);
}
//============================================================
// osd_get_clipboard_text
//============================================================
char *osd_get_clipboard_text(void)
{
// try to access unicode text
char *result = get_clipboard_text_by_format(CF_UNICODETEXT, convert_wide);
// try to access ANSI text
if (result == nullptr)
result = get_clipboard_text_by_format(CF_TEXT, convert_ansi);
return result;
}
//============================================================
// osd_dynamic_bind
//============================================================
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
// for classic desktop applications
#define load_library(filename) LoadLibrary(filename)
#else
// for Windows Store universal applications
#define load_library(filename) LoadPackagedLibrary(filename, 0)
#endif
namespace osd {
class dynamic_module_win32_impl : public dynamic_module
{
public:
dynamic_module_win32_impl(std::vector<std::string> &libraries)
: m_module(nullptr)
{
m_libraries = libraries;
}
virtual ~dynamic_module_win32_impl() override
{
if (m_module != nullptr)
FreeLibrary(m_module);
};
protected:
virtual generic_fptr_t get_symbol_address(char const *symbol) override
{
/*
* given a list of libraries, if a first symbol is successfully loaded from
* one of them, all additional symbols will be loaded from the same library
*/
if (m_module)
{
return reinterpret_cast<generic_fptr_t>(GetProcAddress(m_module, symbol));
}
for (auto const &library : m_libraries)
{
osd::text::tstring tempstr = osd::text::to_tstring(library);
HMODULE module = load_library(tempstr.c_str());
if (module != nullptr)
{
generic_fptr_t function = reinterpret_cast<generic_fptr_t>(GetProcAddress(module, symbol));
if (function != nullptr)
{
m_module = module;
return function;
}
else
{
FreeLibrary(module);
}
}
}
return nullptr;
}
private:
std::vector<std::string> m_libraries;
HMODULE m_module;
};
dynamic_module::ptr dynamic_module::open(std::vector<std::string> &&names)
{
return std::make_unique<dynamic_module_win32_impl>(names);
}
} // namespace osd