You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1327 lines
37 KiB
1327 lines
37 KiB
/*
|
|
* w32dll-emu.c -- Win32 emulation routines to support DLLs
|
|
* Written by Andrew Church <achurch@achurch.org>
|
|
*
|
|
* This file is part of transcode, a video stream processing tool.
|
|
* transcode is free software, distributable under the terms of the GNU
|
|
* General Public License (version 2 or later). See the file COPYING
|
|
* for details.
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
# include "config.h"
|
|
#endif
|
|
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <limits.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/time.h>
|
|
#include <wchar.h>
|
|
|
|
#if !defined(HAVE_MMAP)
|
|
# error Sorry, mmap() support is required.
|
|
#endif
|
|
|
|
#if defined(HAVE_ENDIAN_H)
|
|
# include <endian.h>
|
|
# if __BYTE_ORDER != __LITTLE_ENDIAN
|
|
# error Sorry, only little-endian architectures are supported.
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(HAVE_SYSCONF_WITH_SC_PAGESIZE)
|
|
# define GETPAGESIZE() (sysconf(_SC_PAGESIZE))
|
|
#elif defined(HAVE_GETPAGESIZE)
|
|
# define GETPAGESIZE() (getpagesize())
|
|
#elif defined(PAGESIZE)
|
|
# define GETPAGESIZE() (PAGESIZE)
|
|
#elif defined(PAGE_SIZE)
|
|
# define GETPAGESIZE() (PAGE_SIZE)
|
|
#else
|
|
# error System page size is not available!
|
|
#endif
|
|
|
|
#include "w32dll.h"
|
|
#include "w32dll-local.h"
|
|
#include "w32dll-emu.h"
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Define this to enable creation of stubs for unemulated functions that
|
|
* print a warning to stderr and return -1 when the function is called.
|
|
* Note that this leaks one page of mmap() memory plus string memory per
|
|
* stub created. (Note, however, that for WINAPI functions the debug stub
|
|
* cannot know how many arguments to pop, so the program will probably
|
|
* crash on return.)
|
|
* Defining this also enables some debugging messages to stderr.
|
|
*/
|
|
|
|
//#define W32DLL_EMU_DEBUG
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Array of known modules and associated handles (see w32dll-emu.h),
|
|
* terminated with name==NULL. */
|
|
|
|
#define MOD(modname) {.name = #modname ".dll", .handle = HANDLE_##modname}
|
|
|
|
static const struct {
|
|
const char *name;
|
|
uint32_t handle;
|
|
} emumods[] = {
|
|
MOD(KERNEL32),
|
|
MOD(USER32),
|
|
{ .name = NULL }
|
|
};
|
|
|
|
#undef MOD
|
|
|
|
|
|
/* Array of emulated functions, terminated with module==0. */
|
|
|
|
#define FUNC(mod,func) \
|
|
{.module = HANDLE_##mod, .ordinal = 0, .name = #func, .funcptr = func}
|
|
|
|
static const struct {
|
|
uint32_t module; /* handle */
|
|
uint32_t ordinal;
|
|
const char *name;
|
|
void *funcptr;
|
|
} emufuncs[] = {
|
|
FUNC(KERNEL32, CloseHandle),
|
|
FUNC(KERNEL32, CreateSemaphoreA),
|
|
FUNC(KERNEL32, CreateSemaphoreW),
|
|
FUNC(KERNEL32, DeleteCriticalSection),
|
|
FUNC(KERNEL32, EnterCriticalSection),
|
|
FUNC(KERNEL32, ExitProcess),
|
|
FUNC(KERNEL32, FreeEnvironmentStringsA),
|
|
FUNC(KERNEL32, FreeEnvironmentStringsW),
|
|
FUNC(KERNEL32, GetACP),
|
|
FUNC(KERNEL32, GetCPInfo),
|
|
FUNC(KERNEL32, GetCommandLineA),
|
|
FUNC(KERNEL32, GetConsoleMode),
|
|
FUNC(KERNEL32, GetCurrentProcessId),
|
|
FUNC(KERNEL32, GetCurrentThreadId),
|
|
FUNC(KERNEL32, GetEnvironmentStringsA),
|
|
FUNC(KERNEL32, GetEnvironmentStringsW),
|
|
FUNC(KERNEL32, GetFileType),
|
|
FUNC(KERNEL32, GetLastError),
|
|
FUNC(KERNEL32, GetModuleFileNameA),
|
|
FUNC(KERNEL32, GetModuleHandleA),
|
|
FUNC(KERNEL32, GetProcAddress),
|
|
FUNC(KERNEL32, GetProcessHeap),
|
|
FUNC(KERNEL32, GetStartupInfoA),
|
|
FUNC(KERNEL32, GetStdHandle),
|
|
FUNC(KERNEL32, GetStringTypeW),
|
|
FUNC(KERNEL32, GetSystemTimeAsFileTime),
|
|
FUNC(KERNEL32, GetTickCount),
|
|
FUNC(KERNEL32, GetVersionExA),
|
|
FUNC(KERNEL32, HeapAlloc),
|
|
FUNC(KERNEL32, HeapCreate),
|
|
FUNC(KERNEL32, HeapDestroy),
|
|
FUNC(KERNEL32, HeapFree),
|
|
FUNC(KERNEL32, HeapReAlloc),
|
|
FUNC(KERNEL32, HeapSize),
|
|
FUNC(KERNEL32, InitializeCriticalSection),
|
|
FUNC(KERNEL32, InterlockedCompareExchange),
|
|
FUNC(KERNEL32, InterlockedCompareExchangePointer),
|
|
FUNC(KERNEL32, InterlockedDecrement),
|
|
FUNC(KERNEL32, InterlockedExchange),
|
|
FUNC(KERNEL32, InterlockedExchangeAdd),
|
|
FUNC(KERNEL32, InterlockedExchangePointer),
|
|
FUNC(KERNEL32, InterlockedIncrement),
|
|
FUNC(KERNEL32, InterlockedTestExchange),
|
|
FUNC(KERNEL32, LCMapStringA),
|
|
FUNC(KERNEL32, LCMapStringW),
|
|
FUNC(KERNEL32, LeaveCriticalSection),
|
|
FUNC(KERNEL32, LoadLibraryA),
|
|
FUNC(KERNEL32, MultiByteToWideChar),
|
|
FUNC(KERNEL32, QueryPerformanceCounter),
|
|
FUNC(KERNEL32, ReleaseSemaphore),
|
|
FUNC(KERNEL32, SetHandleCount),
|
|
FUNC(KERNEL32, SetLastError),
|
|
FUNC(KERNEL32, TlsAlloc),
|
|
FUNC(KERNEL32, TlsFree),
|
|
FUNC(KERNEL32, TlsGetValue),
|
|
FUNC(KERNEL32, TlsSetValue),
|
|
FUNC(KERNEL32, WaitForSingleObject),
|
|
FUNC(KERNEL32, WideCharToMultiByte),
|
|
FUNC(KERNEL32, WriteFile),
|
|
|
|
FUNC(USER32, GetActiveWindow),
|
|
FUNC(USER32, MessageBoxA),
|
|
FUNC(USER32, MessageBoxW),
|
|
|
|
{ .module = 0 }
|
|
};
|
|
|
|
#undef FUNC
|
|
|
|
|
|
/* Debugging functions. */
|
|
|
|
#if defined(W32DLL_EMU_DEBUG)
|
|
# if !defined(MAP_ANONYMOUS)
|
|
# warn MAP_ANONYMOUS not defined, disabling W32DLL_EMU_DEBUG
|
|
# undef W32DLL_EMU_DEBUG
|
|
# else
|
|
static int32_t debug_stub(const char *module, const char *name,
|
|
uint32_t ordinal);
|
|
static void *create_debug_stub(const char *module, const char *name,
|
|
uint32_t ordinal);
|
|
# endif
|
|
#endif
|
|
|
|
#if defined(W32DLL_EMU_DEBUG)
|
|
# define D(x) x
|
|
#else
|
|
# define D(x) /*nothing*/
|
|
#endif
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* External interface. */
|
|
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* w32dll_emu_import_by_name, w32dll_emu_import_by_ordinal: Return the
|
|
* address of the emulated function corresponding to the given import,
|
|
* selected by either name or ordinal.
|
|
*
|
|
* Parameters:
|
|
* module: Name of the module from which to import.
|
|
* name: Import name descriptor (w32dll_emu_import_by_name() only).
|
|
* ordinal: Import ordinal (w32dll_emu_import_by_ordinal() only).
|
|
* Return value:
|
|
* The address corresponding to the import, or NULL if no emulation
|
|
* is available for the import.
|
|
*/
|
|
|
|
void *w32dll_emu_import_by_name(const char *module,
|
|
const struct import_name_entry *name)
|
|
{
|
|
int i;
|
|
uint32_t handle = 0;
|
|
|
|
for (i = 0; emumods[i].name != NULL; i++) {
|
|
if (strcasecmp(emumods[i].name, module) == 0) {
|
|
handle = emumods[i].handle;
|
|
break;
|
|
}
|
|
}
|
|
if (handle) {
|
|
for (i = 0; emufuncs[i].module != 0; i++) {
|
|
if (emufuncs[i].module == handle
|
|
&& strcasecmp(emufuncs[i].name, name->name) == 0)
|
|
return emufuncs[i].funcptr;
|
|
}
|
|
}
|
|
#if defined(W32DLL_EMU_DEBUG)
|
|
return create_debug_stub(module, name->name, 0);
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
/************************************/
|
|
|
|
void *w32dll_emu_import_by_ordinal(const char *module, uint32_t ordinal)
|
|
{
|
|
/* Not supported yet. */
|
|
#if defined(W32DLL_EMU_DEBUG)
|
|
return create_debug_stub(module, NULL, ordinal);
|
|
#else
|
|
return NULL;
|
|
#endif
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* The remainder of the file consists of emulation functions. */
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* Emulation debugging functions. */
|
|
|
|
#if defined(W32DLL_EMU_DEBUG)
|
|
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* debug_stub: Stub function which prints an error message. Called by
|
|
* machine code generated by create_debug_stub().
|
|
*
|
|
* Parameters:
|
|
* module: Module name for which the stub is being called.
|
|
* name: Function name for which the stub is being called, or NULL
|
|
* if not applicable.
|
|
* ordinal: Function ordinal for which the stub is being called, if
|
|
* applicable.
|
|
* Return value:
|
|
* Always returns -1.
|
|
*/
|
|
|
|
static int32_t debug_stub(const char *module, const char *name,
|
|
uint32_t ordinal)
|
|
{
|
|
char numbuf[16];
|
|
snprintf(numbuf, sizeof(numbuf), "0x%08X", ordinal);
|
|
fprintf(stderr, "[w32dll-emu] Unsupported function: %s/%s\n",
|
|
module, name ? name : numbuf);
|
|
return -1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
/**
|
|
* create_debug_stub: Create a function which calls debug_stub().
|
|
*
|
|
* Parameters:
|
|
* module: Module name for which the stub is being created.
|
|
* name: Function name for which the stub is being created, or NULL
|
|
* if not applicable.
|
|
* ordinal: Function ordinal for which the stub is being created, if
|
|
* applicable.
|
|
* Return value:
|
|
* A pointer to the newly-created debug stub, or NULL on error.
|
|
*/
|
|
|
|
static void *create_debug_stub(const char *module, const char *name,
|
|
uint32_t ordinal)
|
|
{
|
|
char *funcpage, *s;
|
|
int32_t offset;
|
|
|
|
funcpage = mmap(NULL, GETPAGESIZE(), PROT_READ | PROT_WRITE | PROT_EXEC,
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (funcpage == MAP_FAILED)
|
|
return NULL;
|
|
|
|
if (module)
|
|
module = strdup(module);
|
|
if (!module)
|
|
module = "(null)";
|
|
if (name) {
|
|
name = strdup(name);
|
|
if (!name)
|
|
name = "(null)";
|
|
}
|
|
|
|
/* Create the function. The code below is the equivalent of the
|
|
* following assembly:
|
|
* pop %eax
|
|
* pushl ordinal
|
|
* pushl name
|
|
* pushl module
|
|
* push %eax
|
|
* jmp debug_stub
|
|
*/
|
|
strcpy(funcpage, "\x58"
|
|
"\x68\x11\x11\x11\x11"
|
|
"\x68\x22\x22\x22\x22"
|
|
"\x68\x33\x33\x33\x33"
|
|
"\x50"
|
|
"\xE9\x44\x44\x44\x44");
|
|
/* Fill in the various values. Do them in reverse order to avoid
|
|
* strstr() getting confused by intermediate nulls! */
|
|
s = strstr(funcpage,"\x44\x44\x44\x44");
|
|
offset = (int32_t)debug_stub - (int32_t)(s+4);
|
|
memcpy(s, &offset, 4);
|
|
memcpy(strstr(funcpage,"\x33\x33\x33\x33"), &module, 4);
|
|
memcpy(strstr(funcpage,"\x22\x22\x22\x22"), &name, 4);
|
|
memcpy(strstr(funcpage,"\x11\x11\x11\x11"), &ordinal, 4);
|
|
|
|
/* Return the new page. */
|
|
return funcpage;
|
|
}
|
|
|
|
#endif /* W32DLL_EMU_DEBUG */
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* Emulated functions in alphabetical order. See the Windows documentation
|
|
* for details about each function. */
|
|
|
|
/*************************************************************************/
|
|
|
|
/* Various data. */
|
|
|
|
static uint32_t w32_errno = 0; /* for GetLastError() */
|
|
static int tls_alloced[TLS_MINIMUM_AVAILABLE];
|
|
static void *tls_data[TLS_MINIMUM_AVAILABLE];
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* KERNEL32 functions */
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int CloseHandle(uint32_t handle)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t CreateSemaphoreA(void *attr, uint32_t initial,
|
|
uint32_t max, const char *name)
|
|
{
|
|
return HANDLE_SEMAPHORE;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t CreateSemaphoreW(void *attr, uint32_t initial,
|
|
uint32_t max, const uint16_t *name)
|
|
{
|
|
return HANDLE_SEMAPHORE;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void DeleteCriticalSection(void *lock)
|
|
{
|
|
/* Win32 "critical sections" are basically locks shared between threads.
|
|
* We only deal with one thread at the moment, so we ignore all these. */
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void EnterCriticalSection(void *lock)
|
|
{
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void ExitProcess(unsigned int exitcode)
|
|
{
|
|
D((fprintf(stderr, "ExitProcess(%u) called, exiting...\n", exitcode)));
|
|
exit(exitcode);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int FreeEnvironmentStringsA(void *env)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int FreeEnvironmentStringsW(void *env)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI unsigned int GetACP(void)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int GetCPInfo(unsigned int codepage, CPINFO *result)
|
|
{
|
|
if (!result) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
result->maxbytes = 1;
|
|
result->defchar[0] = '?';
|
|
result->defchar[1] = 0;
|
|
memset(result->leadbytes, 0, sizeof(result->leadbytes));
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI char *GetCommandLineA(void)
|
|
{
|
|
static char dummy_cmdline[] = "dummy.exe";
|
|
return dummy_cmdline;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int GetConsoleMode(uint32_t file, uint16_t *result)
|
|
{
|
|
if (file == HANDLE_STDIN) {
|
|
*result = 0x0007; /* PROCESSED_INPUT | LINE_INPUT | ECHO_INPUT */
|
|
} else if (file == HANDLE_STDOUT) {
|
|
*result = 0x0001; /* PROCESSED_OUTPUT -- but not really! oh well */
|
|
} else if (file == HANDLE_STDERR) {
|
|
*result = 0x0000;
|
|
} else {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetCurrentProcessId(void)
|
|
{
|
|
return getpid();
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetCurrentThreadId(void)
|
|
{
|
|
return getpid();
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void *GetEnvironmentStringsA(void)
|
|
{
|
|
static char dummy_environ[2] = "\0\0";
|
|
return dummy_environ;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void *GetEnvironmentStringsW(void)
|
|
{
|
|
static uint16_t dummy_environ[2] = {0,0};
|
|
return dummy_environ;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetFileType(uint32_t file)
|
|
{
|
|
SetLastError(NO_ERROR);
|
|
if (file==HANDLE_STDIN || file==HANDLE_STDOUT || file==HANDLE_STDERR)
|
|
return 2; /* FILE_TYPE_CHAR */
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return 0; /* FILE_TYPE_UNKNOWN */
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetLastError(void)
|
|
{
|
|
return w32_errno;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetModuleFileNameA(uint32_t module, char *buf,
|
|
uint32_t size)
|
|
{
|
|
int n = -1;
|
|
|
|
if (module == 0 && module == HANDLE_DEFAULT) {
|
|
n = snprintf(buf, size, "%s", "dummy.exe");
|
|
} else {
|
|
int i;
|
|
for (i = 0; emumods[i].name != NULL; i++) {
|
|
if (emumods[i].handle == module) {
|
|
n = snprintf(buf, size, "%s", emumods[i].name);
|
|
break;
|
|
}
|
|
}
|
|
if (!emumods[i].name) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
}
|
|
if (n < 0 || n >= size) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return 0;
|
|
}
|
|
return n;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetModuleHandleA(const char *name)
|
|
{
|
|
int i;
|
|
|
|
if (!name)
|
|
return HANDLE_DEFAULT;
|
|
for (i = 0; emumods[i].name != NULL; i++) {
|
|
if (strcasecmp(emumods[i].name, name) == 0)
|
|
return emumods[i].handle;
|
|
}
|
|
D((fprintf(stderr, "GetModuleHandleA(%s) -> 0\n", name)));
|
|
SetLastError(ERROR_FILE_NOT_FOUND);
|
|
return 0;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI FARPROC GetProcAddress(uint32_t module, const char *name)
|
|
{
|
|
int i;
|
|
|
|
if (!name) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
if (module == 0 && module == HANDLE_DEFAULT) {
|
|
D((fprintf(stderr, "GetProcAddress(DEFAULT, %s) -> NULL\n", name)));
|
|
SetLastError(ERROR_INVALID_FUNCTION);
|
|
return NULL;
|
|
}
|
|
for (i = 0; emufuncs[i].module != 0; i++) {
|
|
if (emufuncs[i].module==module && strcasecmp(emufuncs[i].name,name)==0)
|
|
return emufuncs[i].funcptr;
|
|
}
|
|
D((fprintf(stderr, "GetProcAddress(%d, %s) -> NULL\n", module, name)));
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return NULL;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetProcessHeap(void)
|
|
{
|
|
return HANDLE_HEAP;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void GetStartupInfoA(STARTUPINFO *result)
|
|
{
|
|
result->size = sizeof(*result);
|
|
result->reserved = NULL;
|
|
result->desktop = NULL;
|
|
result->title = "dummy";
|
|
result->x = 0;
|
|
result->y = 0;
|
|
result->w = 640;
|
|
result->h = 480;
|
|
result->wchars = 80;
|
|
result->hchars = 30;
|
|
result->fill = 0;
|
|
result->flags = 0;
|
|
result->show = 1;
|
|
result->reserved2 = 0;
|
|
result->reserved3 = NULL;
|
|
result->h_stdin = HANDLE_STDIN;
|
|
result->h_stdout = HANDLE_STDOUT;
|
|
result->h_stderr = HANDLE_STDERR;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetStdHandle(uint32_t index)
|
|
{
|
|
if (index == (uint32_t)-10)
|
|
return HANDLE_STDIN;
|
|
if (index == (uint32_t)-11)
|
|
return HANDLE_STDOUT;
|
|
if (index == (uint32_t)-12)
|
|
return HANDLE_STDERR;
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int GetStringTypeW(uint32_t type, const uint16_t *str,
|
|
int len, uint16_t *typebuf)
|
|
{
|
|
int i;
|
|
|
|
if (!str || len <= 0 || !typebuf) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
for (i = 0; i < len; i++) {
|
|
switch (type) {
|
|
case 1:
|
|
typebuf[i] = 0;
|
|
if (str[i] <= 0x7F) {
|
|
if (isupper((char)str[i]))
|
|
typebuf[i] |= 0x0001;
|
|
if (islower((char)str[i]))
|
|
typebuf[i] |= 0x0002;
|
|
if (isdigit((char)str[i]))
|
|
typebuf[i] |= 0x0004;
|
|
if (isspace((char)str[i]))
|
|
typebuf[i] |= 0x0008;
|
|
if (ispunct((char)str[i]))
|
|
typebuf[i] |= 0x0010;
|
|
if (iscntrl((char)str[i]))
|
|
typebuf[i] |= 0x0020;
|
|
if (isxdigit((char)str[i]))
|
|
typebuf[i] |= 0x0080;
|
|
if (isalpha((char)str[i]))
|
|
typebuf[i] |= 0x0100;
|
|
} // if (str[i] <= 0x7F)
|
|
break;
|
|
case 2:
|
|
if (str[i] >= 0x20 && str[i] <= 0x7E) {
|
|
typebuf[i] = 1;
|
|
} else {
|
|
typebuf[i] = 0;
|
|
}
|
|
break;
|
|
case 3:
|
|
if (isalpha((char)str[i])) {
|
|
typebuf[i] = 0x8040; /* ALPHA | HALFWIDTH */
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void GetSystemTimeAsFileTime(uint64_t *result)
|
|
{
|
|
/* Time is in 100-nanosecond units since 1601/1/1 0:00 UTC */
|
|
/* Difference from 1601/1/1 to 1970/1/1 = 369 years, incl. 89 leap years */
|
|
*result = ((uint64_t)time(NULL) + (uint64_t)(369*365+89)*86400) * 10000000;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetTickCount(void)
|
|
{
|
|
struct timeval tv;
|
|
#if defined(HAVE_GETTIMEOFDAY)
|
|
gettimeofday(&tv, NULL);
|
|
#else
|
|
tv.tv_sec = time(NULL);
|
|
tv.tv_usec = 0;
|
|
#endif
|
|
return tv.tv_sec*1000 + tv.tv_usec/1000; // as good as anything else
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int GetVersionExA(OSVERSIONINFOEX *result)
|
|
{
|
|
if (!result || result->size < 148) { // 148: sizeof(OSVERSIONINFO)
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
/* Emulate Windows 2000 */
|
|
result->major = 5;
|
|
result->minor = 0;
|
|
result->build = 31337;
|
|
result->platform = 2;
|
|
memset(result->extra, 0, sizeof(result->extra));
|
|
if (result->size >= sizeof(*result)) {
|
|
result->sp_major = 4;
|
|
result->sp_minor = 0;
|
|
result->suite = 0x0000;
|
|
result->type = 0x01;
|
|
result->reserved = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
#define HEAPALLOC_MAGIC 0x9D1A9DA1
|
|
#define HEAPFREE_MAGIC (~HEAPALLOC_MAGIC)
|
|
|
|
static WINAPI void *HeapAlloc(uint32_t heap, uint32_t flags, size_t size)
|
|
{
|
|
void *ptr = malloc(size+8);
|
|
D((fprintf(stderr, "HeapAlloc(%u) -> %p%s", size, ptr, ptr ? "" : "\n")));
|
|
if (!ptr) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
ptr = (uint32_t *)ptr+2;
|
|
((uint32_t *)ptr)[-2] = HEAPALLOC_MAGIC;
|
|
((uint32_t *)ptr)[-1] = size;
|
|
D((fprintf(stderr, " -> %p\n", ptr)));
|
|
if (flags & 0x00000008) /* HEAP_ZERO_MEMORY */
|
|
memset(ptr, 0, size);
|
|
return ptr;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t HeapCreate(uint32_t flags, size_t initial, size_t max)
|
|
{
|
|
/* Just share the same "heap" */
|
|
return HANDLE_HEAP;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int HeapDestroy(uint32_t heap)
|
|
{
|
|
return 1; /* Ignore */
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int HeapFree(uint32_t heap, uint32_t flags, void *ptr)
|
|
{
|
|
D((fprintf(stderr, "HeapFree(%p) [%08X %u]\n", ptr,
|
|
ptr ? ((uint32_t *)ptr)[-2] : 0,
|
|
ptr ? ((uint32_t *)ptr)[-1] : 0)));
|
|
if (ptr) {
|
|
if (((uint32_t *)ptr)[-2] != HEAPALLOC_MAGIC) {
|
|
D((fprintf(stderr, "HeapFree() on %s pointer %p!\n",
|
|
((uint32_t *)ptr)[-2]==HEAPFREE_MAGIC ? "freed" : "bad",
|
|
ptr)));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
((uint32_t *)ptr)[-1] = HEAPFREE_MAGIC;
|
|
free((uint32_t *)ptr-2);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void *HeapReAlloc(uint32_t heap, uint32_t flags, void *ptr,
|
|
size_t size)
|
|
{
|
|
size_t oldsize;
|
|
|
|
D((fprintf(stderr, "HeapReAlloc(%p,%u) -> ", ptr, size)));
|
|
if (!ptr)
|
|
return HeapAlloc(heap, flags, size);
|
|
if (((uint32_t *)ptr)[-2] != HEAPALLOC_MAGIC) {
|
|
D((fprintf(stderr, "HeapReAlloc() on %s pointer %p!\n",
|
|
((uint32_t *)ptr)[-2]==HEAPFREE_MAGIC ? "freed" : "bad",
|
|
ptr)));
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
oldsize = ((uint32_t *)ptr)[-1];
|
|
ptr = realloc((uint32_t *)ptr-2, size+8);
|
|
D((fprintf(stderr, "oldsize %u -> %p%s", oldsize, ptr, ptr ? "" : "\n")));
|
|
if (!ptr) {
|
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
|
return NULL;
|
|
}
|
|
ptr = (uint32_t *)ptr+2;
|
|
((uint32_t *)ptr)[-2] = HEAPALLOC_MAGIC;
|
|
((uint32_t *)ptr)[-1] = size;
|
|
D((fprintf(stderr, " -> %p\n", ptr)));
|
|
if (size > oldsize && (flags & 0x00000008)) /* HEAP_ZERO_MEMORY */
|
|
memset((uint8_t *)ptr + oldsize, 0, size - oldsize);
|
|
return ptr;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t HeapSize(uint32_t heap, uint32_t flags, const void *ptr)
|
|
{
|
|
D((fprintf(stderr, "HeapSize(%p) -> %u\n", ptr,
|
|
(uint32_t) (((const uint64_t *)ptr)[-1]))));
|
|
return (uint32_t) (((const uint64_t *)ptr)[-1]);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void InitializeCriticalSection(void *lock)
|
|
{
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int32_t InterlockedCompareExchange
|
|
(int32_t *var, int32_t testval, int32_t newval)
|
|
{
|
|
int32_t oldval = *var;
|
|
if (oldval == testval)
|
|
*var = newval;
|
|
return oldval;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void *InterlockedCompareExchangePointer
|
|
(void ***var, void *testval, void *newval)
|
|
{
|
|
void *oldval = *var;
|
|
if (oldval == testval)
|
|
*var = newval;
|
|
return oldval;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int32_t InterlockedDecrement(int32_t *var)
|
|
{
|
|
return --*var;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int32_t InterlockedExchange(int32_t *var, int32_t newval)
|
|
{
|
|
int32_t oldval = *var;
|
|
*var = newval;
|
|
return oldval;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int32_t InterlockedExchangeAdd(int32_t *var, int32_t addval)
|
|
{
|
|
int32_t oldval = *var;
|
|
*var += addval;
|
|
return oldval;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void *InterlockedExchangePointer(void **var, void *newval)
|
|
{
|
|
void *oldval = *var;
|
|
*var = newval;
|
|
return oldval;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int32_t InterlockedIncrement(int32_t *var)
|
|
{
|
|
return ++*var;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int32_t InterlockedTestExchange(int32_t *var, int32_t testval,
|
|
int32_t newval)
|
|
{
|
|
int32_t oldval = *var;
|
|
if (oldval == testval)
|
|
*var = newval;
|
|
return oldval;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int LCMapStringA
|
|
(uint32_t locale, uint32_t flags, const char *in, int inlen,
|
|
char *out, int outsize)
|
|
{
|
|
if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (inlen < 0)
|
|
inlen = strlen(in) + 1; // include terminating null
|
|
if (outsize == 0)
|
|
return inlen;
|
|
if (outsize < inlen) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return 0;
|
|
}
|
|
memcpy(out, in, inlen);
|
|
return inlen;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int LCMapStringW
|
|
(uint32_t locale, uint32_t flags, const uint16_t *in, int inlen,
|
|
uint16_t *out, int outsize)
|
|
{
|
|
if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (inlen < 0) {
|
|
inlen = 0;
|
|
while (in[inlen])
|
|
inlen++;
|
|
inlen++; // include null terminator
|
|
}
|
|
if (outsize == 0)
|
|
return inlen;
|
|
if (outsize < inlen) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return 0;
|
|
}
|
|
memcpy(out, in, inlen*2);
|
|
return inlen;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void LeaveCriticalSection(void *lock)
|
|
{
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t LoadLibraryA(char *filename)
|
|
{
|
|
return GetModuleHandleA(filename);
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int MultiByteToWideChar
|
|
(unsigned int codepage, uint32_t flags, const unsigned char *in,
|
|
int inlen, uint16_t *out, int outsize)
|
|
{
|
|
int i, outlen;
|
|
|
|
if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (inlen < 0) {
|
|
inlen = 0;
|
|
while (in[inlen])
|
|
inlen++;
|
|
inlen++; // include null terminator
|
|
}
|
|
outlen = 0;
|
|
|
|
for (i = 0; i < inlen; i++) {
|
|
if (out) {
|
|
if (outlen >= outsize) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return 0;
|
|
}
|
|
*out++ = in[i];
|
|
}
|
|
outlen++;
|
|
}
|
|
|
|
return outlen;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t QueryPerformanceCounter(int64_t *result)
|
|
{
|
|
struct timeval tv;
|
|
gettimeofday(&tv, NULL);
|
|
if (!result) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
*result = (int64_t)tv.tv_sec*1000000 + tv.tv_usec; // sure, why not?
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int ReleaseSemaphore(uint32_t sem, int32_t release_count,
|
|
int32_t *previous)
|
|
{
|
|
if (sem != HANDLE_SEMAPHORE) {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
if (previous)
|
|
*previous = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void SetHandleCount(uint32_t count)
|
|
{
|
|
/* obsolete Win16 function, does nothing */
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void SetLastError(uint32_t error)
|
|
{
|
|
w32_errno = error;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t TlsAlloc(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < TLS_MINIMUM_AVAILABLE; i++) {
|
|
if (!tls_alloced[i]) {
|
|
tls_alloced[i] = 1;
|
|
D((fprintf(stderr, "TlsAlloc() succeeded with %d\n", i)));
|
|
return i;
|
|
}
|
|
}
|
|
D((fprintf(stderr, "TlsAlloc() failed\n")));
|
|
return ~0;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int TlsFree(uint32_t index)
|
|
{
|
|
if (index >= TLS_MINIMUM_AVAILABLE) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
tls_alloced[index] = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI void *TlsGetValue(uint32_t index)
|
|
{
|
|
if (index >= TLS_MINIMUM_AVAILABLE) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return NULL;
|
|
}
|
|
SetLastError(NO_ERROR);
|
|
return tls_data[index];
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int TlsSetValue(uint32_t index, void *value)
|
|
{
|
|
if (index >= TLS_MINIMUM_AVAILABLE) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
tls_data[index] = value;
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t WaitForSingleObject(uint32_t handle, uint32_t msec)
|
|
{
|
|
return 0; /* or WAIT_TIMEOUT == 0x102 */
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int WideCharToMultiByte
|
|
(unsigned int codepage, uint32_t flags, const uint16_t *in, int inlen,
|
|
char *out, int outsize, const char *defchar, int *defchar_used)
|
|
{
|
|
int i, outlen;
|
|
|
|
if (!in || !inlen || outsize < 0 || (outsize > 0 && !out)) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (inlen < 0) {
|
|
inlen = 0;
|
|
while (in[inlen])
|
|
inlen++;
|
|
inlen++; // include null terminator
|
|
}
|
|
if (!defchar)
|
|
defchar = "?";
|
|
outlen = 0;
|
|
|
|
/* Simple implementation (FIXME look into glibc's conversion functions?) */
|
|
for (i = 0; i < inlen; i++) {
|
|
if (in[i] <= 0x7F) {
|
|
if (out) {
|
|
if (outlen >= outsize) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return 0;
|
|
}
|
|
*out++ = (char)in[i];
|
|
}
|
|
outlen++;
|
|
} else {
|
|
if (out) {
|
|
const char *s;
|
|
if (outlen + strlen(defchar) > outsize) {
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return 0;
|
|
}
|
|
s = defchar;
|
|
while (*s)
|
|
*out++ = *s++;
|
|
}
|
|
outlen += strlen(defchar);
|
|
if (defchar_used)
|
|
*defchar_used = 1;
|
|
}
|
|
}
|
|
|
|
return outlen;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int WriteFile(uint32_t file, const void *buf, uint32_t len,
|
|
uint32_t *written, void *overlapped)
|
|
{
|
|
int fd = -1, nwritten;
|
|
|
|
if (!buf) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
if (file == HANDLE_STDIN) {
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
return 0;
|
|
} else if (file == HANDLE_STDOUT) {
|
|
D((fd = 1));
|
|
} else if (file == HANDLE_STDERR) {
|
|
D((fd = 2));
|
|
} else {
|
|
SetLastError(ERROR_INVALID_HANDLE);
|
|
return 0;
|
|
}
|
|
if (len == 0) {
|
|
if (written)
|
|
*written = 0;
|
|
return 1;
|
|
}
|
|
if (fd < 0) {
|
|
/* Suppress stdout/stderr output in non-debug mode */
|
|
if (written)
|
|
*written = len;
|
|
return 1;
|
|
}
|
|
|
|
do {
|
|
errno = 0;
|
|
nwritten = write(fd, buf, len);
|
|
} while (nwritten <= 0 && errno == EINTR);
|
|
if (nwritten <= 0) {
|
|
if (errno == EBADF || errno == EINVAL)
|
|
SetLastError(ERROR_ACCESS_DENIED);
|
|
else if (errno == EFAULT)
|
|
SetLastError(ERROR_INVALID_ACCESS);
|
|
else if (errno == EPIPE)
|
|
SetLastError(ERROR_BROKEN_PIPE);
|
|
else if (errno == EAGAIN)
|
|
SetLastError(ERROR_IO_PENDING);
|
|
else if (errno == ENOSPC || errno == EFBIG)
|
|
SetLastError(ERROR_DISK_FULL);
|
|
else if (errno == EIO)
|
|
SetLastError(ERROR_WRITE_FAULT);
|
|
else
|
|
SetLastError(ERROR_UNKNOWN);
|
|
return 0;
|
|
}
|
|
|
|
if (written)
|
|
*written = (uint32_t)nwritten;
|
|
return 1;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/* USER32 functions. */
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI uint32_t GetActiveWindow(void)
|
|
{
|
|
return HANDLE_WINDOW;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
|
|
#define OUT(str) do { \
|
|
const char *__s = str; \
|
|
do { \
|
|
int __len, __lpad, __rpad; \
|
|
const char *__t = __s + strlen(__s); \
|
|
if (__t - __s > maxline) \
|
|
__t = __s + maxline; \
|
|
__len = __t - __s; \
|
|
__lpad = (maxline - __len) / 2; \
|
|
__rpad = maxline - __len - __lpad; \
|
|
fprintf(stderr, "|%*s%.*s%*s|\n", __lpad, "", __len, __s, __rpad, "");\
|
|
__s = __t; \
|
|
} while (*__s); \
|
|
} while (0)
|
|
#define MAXLINEWIDTH 77
|
|
|
|
static WINAPI int MessageBoxA(uint32_t window, const char *text,
|
|
const char *title, unsigned int type)
|
|
{
|
|
char *mytext, *s;
|
|
int maxline, i;
|
|
char dashbuf[MAXLINEWIDTH+1];
|
|
|
|
if (!text || !title) {
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
mytext = strdup(text); // make sure we can strtok() it
|
|
if (!mytext) {
|
|
SetLastError(ERROR_OUTOFMEMORY);
|
|
return 0;
|
|
}
|
|
|
|
maxline = strlen(title);
|
|
for (s = mytext; *s; s += strspn(s, "\r\n")) {
|
|
char *t = s + strcspn(s, "\r\n");
|
|
if (t-s > maxline)
|
|
maxline = t-s;
|
|
s = t;
|
|
}
|
|
if (maxline > MAXLINEWIDTH)
|
|
maxline = MAXLINEWIDTH;
|
|
for (i = 0; i < maxline; i++)
|
|
dashbuf[i] = '-';
|
|
dashbuf[maxline] = 0;
|
|
|
|
fprintf(stderr, "+%s+\n", dashbuf);
|
|
OUT(title);
|
|
fprintf(stderr, "+%s+\n", dashbuf);
|
|
for (s = strtok(mytext,"\r\n"); s; s = strtok(NULL,"\r\n"))
|
|
OUT(s);
|
|
fprintf(stderr, "+%s+\n", dashbuf);
|
|
|
|
free(mytext);
|
|
return 1;
|
|
}
|
|
|
|
#undef OUT
|
|
#undef MAXLINEWIDTH
|
|
|
|
/*************************************************************************/
|
|
|
|
static WINAPI int MessageBoxW(uint32_t window, const uint16_t *text,
|
|
const uint16_t *title, unsigned int type)
|
|
{
|
|
char textbuf[10000], titlebuf[1000];
|
|
if (!WideCharToMultiByte(0, 0, text, 0, textbuf, sizeof(textbuf), 0, 0))
|
|
strcpy(textbuf, "<<buffer overflow>>");
|
|
if (!WideCharToMultiByte(0, 0, title, 0, titlebuf, sizeof(titlebuf), 0, 0))
|
|
strcpy(titlebuf, "<<buffer overflow>>");
|
|
return MessageBoxA(window, textbuf, titlebuf, type);;
|
|
}
|
|
|
|
/*************************************************************************/
|
|
/*************************************************************************/
|
|
|
|
/*
|
|
* Local variables:
|
|
* c-file-style: "stroustrup"
|
|
* c-file-offsets: ((case-label . *) (statement-case-intro . *))
|
|
* indent-tabs-mode: nil
|
|
* End:
|
|
*
|
|
* vim: expandtab shiftwidth=4:
|
|
*/
|