/* * w32dll-emu.c -- Win32 emulation routines to support DLLs * Written by Andrew Church * * 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 #include #include #include #include #include #include #include #include #include #include #include #include #if !defined(HAVE_MMAP) # error Sorry, mmap() support is required. #endif #if defined(HAVE_ENDIAN_H) # include # 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, "<>"); if (!WideCharToMultiByte(0, 0, title, 0, titlebuf, sizeof(titlebuf), 0, 0)) strcpy(titlebuf, "<>"); 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: */