Browse Source

Miniwin: Port to Linux with stubs

pull/4/head
nomdenom 8 years ago
parent
commit
063fc04b1a
  1. 14
      Absolute/.clang-format
  2. 2224
      Absolute/absolute-decls.h
  3. 248
      Absolute/absolute-imports.h
  4. 47
      Absolute/absolute-stubs.h
  5. 55
      Absolute/absolute.cpp
  6. 6
      Absolute/absolute.h
  7. 230
      Absolute/default.ld
  8. 8500
      Absolute/harness.asm
  9. 32
      Absolute/hook.cpp
  10. 6
      Absolute/hook.h
  11. 4
      Absolute/sections.ld
  12. 22
      CMake/32bit.cmake
  13. 16
      CMake/SDL2_fixed.cmake
  14. 36
      CMake/absolute.cmake
  15. 3
      CMake/out_of_tree.cmake
  16. 18
      CMake/sanitize.cmake
  17. 220
      CMakeLists.txt
  18. 14
      Stub/.clang-format
  19. 66
      Stub/appfat.cpp
  20. 7
      Stub/capture.cpp
  21. 182
      Stub/diabloui.cpp
  22. 22
      Stub/dthread.cpp
  23. 375
      Stub/dx.cpp
  24. 10
      Stub/dx_stub.h
  25. 10
      Stub/fault.cpp
  26. 96
      Stub/init.cpp
  27. 22
      Stub/main.cpp
  28. 12
      Stub/main_harness.cpp
  29. 72
      Stub/main_test.cpp
  30. 294
      Stub/miniwin.cpp
  31. 557
      Stub/miniwin.h
  32. 196
      Stub/miniwin_ddraw.h
  33. 46
      Stub/miniwin_dsound.h
  34. 141
      Stub/miniwin_io.cpp
  35. 277
      Stub/miniwin_msg_sdl.cpp
  36. 20
      Stub/miniwin_rand.cpp
  37. 11
      Stub/miniwin_sdl.h
  38. 11
      Stub/movie.cpp
  39. 81
      Stub/nthread.cpp
  40. 14
      Stub/restrict.cpp
  41. 66
      Stub/sound.cpp
  42. 367
      Stub/storm.cpp
  43. 49
      Stub/storm_net.cpp
  44. 34
      Stub/stubs.h
  45. 6
      Stub/validate.cpp
  46. 9
      docker/arch/Dockerfile
  47. 10
      docker/build.sh
  48. 10
      docker/ubuntu/Dockerfile

14
Absolute/.clang-format

@ -0,0 +1,14 @@
---
IndentWidth: 4
TabWidth: 4
---
Language: Cpp
UseTab: ForIndentation
AlignTrailingComments: false
BreakBeforeBraces: Linux
ColumnLimit: 120
IncludeBlocks: Preserve
AlignEscapedNewlines: DontAlign
AlignOperands: true
AllowShortFunctionsOnASingleLine: Inline
Standard: Cpp11

2224
Absolute/absolute-decls.h

File diff suppressed because it is too large Load Diff

248
Absolute/absolute-imports.h

@ -0,0 +1,248 @@
LINK_IMPORT(imp_CloseHandle, CloseHandle)
LINK_IMPORT(imp_CopyFileA, CopyFileA)
LINK_IMPORT(imp_CreateEventA, CreateEventA)
LINK_IMPORT(imp_CreateFileA, CreateFileA)
LINK_IMPORT(imp_CreateFileMappingA, CreateFileMappingA)
LINK_IMPORT(imp_CreateProcessA, CreateProcessA)
LINK_IMPORT(imp_DeleteCriticalSection, DeleteCriticalSection)
LINK_IMPORT(imp_DeleteFileA, DeleteFileA)
LINK_IMPORT(imp_DestroyWindow, DestroyWindow)
LINK_IMPORT(imp_DispatchMessageA, DispatchMessageA)
LINK_IMPORT(imp_EnterCriticalSection, EnterCriticalSection)
LINK_IMPORT(imp_ExitProcess, ExitProcess)
LINK_IMPORT(imp_FindClose, FindClose)
LINK_IMPORT(imp_FindFirstFileA, FindFirstFileA)
LINK_IMPORT(imp_FindWindowA, FindWindowA)
LINK_IMPORT(imp_GetComputerNameA, GetComputerNameA)
LINK_IMPORT(imp_GetCurrentProcessId, GetCurrentProcessId)
LINK_IMPORT(imp_GetCurrentThread, GetCurrentThread)
LINK_IMPORT(imp_GetCurrentThreadId, GetCurrentThreadId)
LINK_IMPORT(imp_GetDC, GetDC)
LINK_IMPORT(imp_GetDeviceCaps, GetDeviceCaps)
LINK_IMPORT(imp_GetDiskFreeSpaceA, GetDiskFreeSpaceA)
LINK_IMPORT(imp_GetFileAttributesA, GetFileAttributesA)
LINK_IMPORT(imp_GetFileSize, GetFileSize)
LINK_IMPORT(imp_GetForegroundWindow, GetForegroundWindow)
LINK_IMPORT(imp_GetLastActivePopup, GetLastActivePopup)
LINK_IMPORT(imp_GetLastError, GetLastError)
LINK_IMPORT(imp_GetModuleFileNameA, GetModuleFileNameA)
LINK_IMPORT(imp_GetPrivateProfileStringA, GetPrivateProfileStringA)
LINK_IMPORT(imp_GetSystemInfo, GetSystemInfo)
LINK_IMPORT(imp_GetSystemPaletteEntries, GetSystemPaletteEntries)
LINK_IMPORT(imp_GetTickCount, GetTickCount)
LINK_IMPORT(imp_GetTopWindow, GetTopWindow)
LINK_IMPORT(imp_GetWindow, GetWindow)
LINK_IMPORT(imp_GetWindowThreadProcessId, GetWindowThreadProcessId)
LINK_IMPORT(imp_GetWindowsDirectoryA, GetWindowsDirectoryA)
LINK_IMPORT(imp_InitializeCriticalSection, InitializeCriticalSection)
LINK_IMPORT(imp_LeaveCriticalSection, LeaveCriticalSection)
LINK_IMPORT(imp_MapViewOfFile, MapViewOfFile)
LINK_IMPORT(imp_OpenFile, OpenFile)
LINK_IMPORT(imp_PeekMessageA, PeekMessageA)
LINK_IMPORT(imp_PostMessageA, PostMessageA)
LINK_IMPORT(imp_ReadFile, ReadFile)
LINK_IMPORT(imp_ReleaseCapture, ReleaseCapture)
LINK_IMPORT(imp_ReleaseDC, ReleaseDC)
LINK_IMPORT(imp_SDrawGetFrameWindow, SDrawGetFrameWindow)
LINK_IMPORT(imp_SDrawRealizePalette, SDrawRealizePalette)
LINK_IMPORT(imp_SDrawUpdatePalette, SDrawUpdatePalette)
LINK_IMPORT(imp_SErrGetErrorStr, SErrGetErrorStr)
LINK_IMPORT(imp_SErrGetLastError, SErrGetLastError)
LINK_IMPORT(imp_SErrSetLastError, SErrSetLastError)
LINK_IMPORT(imp_SFileCloseArchive, SFileCloseArchive)
LINK_IMPORT(imp_SFileCloseFile, SFileCloseFile)
LINK_IMPORT(imp_SFileDdaBeginEx, SFileDdaBeginEx)
LINK_IMPORT(imp_SFileDdaDestroy, SFileDdaDestroy)
LINK_IMPORT(imp_SFileDdaEnd, SFileDdaEnd)
LINK_IMPORT(imp_SFileDdaGetPos, SFileDdaGetPos)
LINK_IMPORT(imp_SFileDdaInitialize, SFileDdaInitialize)
LINK_IMPORT(imp_SFileDdaSetVolume, SFileDdaSetVolume)
LINK_IMPORT(imp_SFileGetFileArchive, SFileGetFileArchive)
LINK_IMPORT(imp_SFileGetFileSize, SFileGetFileSize)
LINK_IMPORT(imp_SFileOpenArchive, SFileOpenArchive)
LINK_IMPORT(imp_SFileOpenFile, SFileOpenFile)
LINK_IMPORT(imp_SFileOpenFileEx, SFileOpenFileEx)
LINK_IMPORT(imp_SFileReadFile, SFileReadFile)
LINK_IMPORT(imp_SFileSetFilePointer, SFileSetFilePointer)
LINK_IMPORT(imp_SMemAlloc, SMemAlloc)
LINK_IMPORT(imp_SMemFree, SMemFree)
LINK_IMPORT(imp_SNetCreateGame, SNetCreateGame)
LINK_IMPORT(imp_SNetDestroy, SNetDestroy)
LINK_IMPORT(imp_SNetDropPlayer, SNetDropPlayer)
LINK_IMPORT(imp_SNetGetGameInfo, SNetGetGameInfo)
LINK_IMPORT(imp_SNetGetOwnerTurnsWaiting, SNetGetOwnerTurnsWaiting)
LINK_IMPORT(imp_SNetGetProviderCaps, SNetGetProviderCaps)
LINK_IMPORT(imp_SNetGetTurnsInTransit, SNetGetTurnsInTransit)
LINK_IMPORT(imp_SNetInitializeProvider, SNetInitializeProvider)
LINK_IMPORT(imp_SNetLeaveGame, SNetLeaveGame)
LINK_IMPORT(imp_SNetPerformUpgrade, SNetPerformUpgrade)
LINK_IMPORT(imp_SNetReceiveMessage, SNetReceiveMessage)
LINK_IMPORT(imp_SNetReceiveTurns, SNetReceiveTurns)
LINK_IMPORT(imp_SNetRegisterEventHandler, SNetRegisterEventHandler)
LINK_IMPORT(imp_SNetSendMessage, SNetSendMessage)
LINK_IMPORT(imp_SNetSendServerChatCommand, SNetSendServerChatCommand)
LINK_IMPORT(imp_SNetSendTurn, SNetSendTurn)
LINK_IMPORT(imp_SNetSetBasePlayer, SNetSetBasePlayer)
LINK_IMPORT(imp_SNetUnregisterEventHandler, SNetUnregisterEventHandler)
LINK_IMPORT(imp_SRegLoadData, SRegLoadData)
LINK_IMPORT(imp_SRegLoadString, SRegLoadString)
LINK_IMPORT(imp_SRegLoadValue, SRegLoadValue)
LINK_IMPORT(imp_SRegSaveData, SRegSaveData)
LINK_IMPORT(imp_SRegSaveString, SRegSaveString)
LINK_IMPORT(imp_SRegSaveValue, SRegSaveValue)
LINK_IMPORT(imp_SStrCopy, SStrCopy)
LINK_IMPORT(imp_SetCapture, SetCapture)
LINK_IMPORT(imp_SetCursorPos, SetCursorPos)
LINK_IMPORT(imp_SetEndOfFile, SetEndOfFile)
LINK_IMPORT(imp_SetFileAttributesA, SetFileAttributesA)
LINK_IMPORT(imp_SetFilePointer, SetFilePointer)
LINK_IMPORT(imp_SetFocus, SetFocus)
LINK_IMPORT(imp_SetForegroundWindow, SetForegroundWindow)
LINK_IMPORT(imp_SetLastError, SetLastError)
LINK_IMPORT(imp_SetThreadPriority, SetThreadPriority)
LINK_IMPORT(imp_ShowCursor, ShowCursor)
LINK_IMPORT(imp_Sleep, Sleep)
LINK_IMPORT(imp_TranslateMessage, TranslateMessage)
LINK_IMPORT(imp_UiAppActivate, UiAppActivate)
LINK_IMPORT(imp_UiArtCallback, UiArtCallback)
LINK_IMPORT(imp_UiAuthCallback, UiAuthCallback)
LINK_IMPORT(imp_UiCategoryCallback, UiCategoryCallback)
LINK_IMPORT(imp_UiCopyProtError, UiCopyProtError)
LINK_IMPORT(imp_UiCreateGameCallback, UiCreateGameCallback)
LINK_IMPORT(imp_UiCreatePlayerDescription, UiCreatePlayerDescription)
LINK_IMPORT(imp_UiCreditsDialog, UiCreditsDialog)
LINK_IMPORT(imp_UiDestroy, UiDestroy)
LINK_IMPORT(imp_UiDrawDescCallback, UiDrawDescCallback)
LINK_IMPORT(imp_UiGetDataCallback, UiGetDataCallback)
LINK_IMPORT(imp_UiInitialize, UiInitialize)
LINK_IMPORT(imp_UiMainMenuDialog, UiMainMenuDialog)
LINK_IMPORT(imp_UiMessageBoxCallback, UiMessageBoxCallback)
LINK_IMPORT(imp_UiProfileCallback, UiProfileCallback)
LINK_IMPORT(imp_UiProfileDraw, UiProfileDraw)
LINK_IMPORT(imp_UiProfileGetString, UiProfileGetString)
LINK_IMPORT(imp_UiProgressDialog, UiProgressDialog)
LINK_IMPORT(imp_UiSelHeroMultDialog, UiSelHeroMultDialog)
LINK_IMPORT(imp_UiSelHeroSingDialog, UiSelHeroSingDialog)
LINK_IMPORT(imp_UiSelectGame, UiSelectGame)
LINK_IMPORT(imp_UiSelectProvider, UiSelectProvider)
LINK_IMPORT(imp_UiSetupPlayerInfo, UiSetupPlayerInfo)
LINK_IMPORT(imp_UiSoundCallback, UiSoundCallback)
LINK_IMPORT(imp_UiTitleDialog, UiTitleDialog)
LINK_IMPORT(imp_UiValidPlayerName, UiValidPlayerName)
LINK_IMPORT(imp_UnmapViewOfFile, UnmapViewOfFile)
LINK_IMPORT(imp_WaitForInputIdle, WaitForInputIdle)
LINK_IMPORT(imp_WaitForSingleObject, WaitForSingleObject)
LINK_IMPORT(imp_WriteFile, WriteFile)
LINK_IMPORT(imp_wsprintfA, wsprintfA)
MISSING_IMPORT(imp_CompareStringA, CompareStringA)
MISSING_IMPORT(imp_CompareStringW, CompareStringW)
MISSING_IMPORT(imp_CreateThread, CreateThread)
MISSING_IMPORT(imp_CreateWindowExA, CreateWindowExA)
MISSING_IMPORT(imp_DefWindowProcA, DefWindowProcA)
MISSING_IMPORT(imp_DialogBoxParamA, DialogBoxParamA)
MISSING_IMPORT(imp_EndDialog, EndDialog)
MISSING_IMPORT(imp_ExitThread, ExitThread)
MISSING_IMPORT(imp_FileTimeToLocalFileTime, FileTimeToLocalFileTime)
MISSING_IMPORT(imp_FileTimeToSystemTime, FileTimeToSystemTime)
MISSING_IMPORT(imp_FindNextFileA, FindNextFileA)
MISSING_IMPORT(imp_FlushFileBuffers, FlushFileBuffers)
MISSING_IMPORT(imp_FormatMessageA, FormatMessageA)
MISSING_IMPORT(imp_FreeEnvironmentStringsA, FreeEnvironmentStringsA)
MISSING_IMPORT(imp_FreeEnvironmentStringsW, FreeEnvironmentStringsW)
MISSING_IMPORT(imp_GdiSetBatchLimit, GdiSetBatchLimit)
MISSING_IMPORT(imp_GetACP, GetACP)
MISSING_IMPORT(imp_GetCPInfo, GetCPInfo)
MISSING_IMPORT(imp_GetClassNameA, GetClassNameA)
MISSING_IMPORT(imp_GetCommandLineA, GetCommandLineA)
MISSING_IMPORT(imp_GetCurrentDirectoryA, GetCurrentDirectoryA)
MISSING_IMPORT(imp_GetCurrentProcess, GetCurrentProcess)
MISSING_IMPORT(imp_GetDesktopWindow, GetDesktopWindow)
MISSING_IMPORT(imp_GetDriveTypeA, GetDriveTypeA)
MISSING_IMPORT(imp_GetEnvironmentStrings, GetEnvironmentStrings)
MISSING_IMPORT(imp_GetEnvironmentStringsW, GetEnvironmentStringsW)
MISSING_IMPORT(imp_GetFileType, GetFileType)
MISSING_IMPORT(imp_GetFileVersionInfoA, GetFileVersionInfoA)
MISSING_IMPORT(imp_GetFileVersionInfoSizeA, GetFileVersionInfoSizeA)
MISSING_IMPORT(imp_GetLocalTime, GetLocalTime)
MISSING_IMPORT(imp_GetLocaleInfoA, GetLocaleInfoA)
MISSING_IMPORT(imp_GetLocaleInfoW, GetLocaleInfoW)
MISSING_IMPORT(imp_GetLogicalDriveStringsA, GetLogicalDriveStringsA)
MISSING_IMPORT(imp_GetModuleHandleA, GetModuleHandleA)
MISSING_IMPORT(imp_GetOEMCP, GetOEMCP)
MISSING_IMPORT(imp_GetProcAddress, GetProcAddress)
MISSING_IMPORT(imp_GetStartupInfoA, GetStartupInfoA)
MISSING_IMPORT(imp_GetStdHandle, GetStdHandle)
MISSING_IMPORT(imp_GetStockObject, GetStockObject)
MISSING_IMPORT(imp_GetStringTypeA, GetStringTypeA)
MISSING_IMPORT(imp_GetStringTypeW, GetStringTypeW)
MISSING_IMPORT(imp_GetSystemMetrics, GetSystemMetrics)
MISSING_IMPORT(imp_GetSystemTime, GetSystemTime)
MISSING_IMPORT(imp_GetTimeZoneInformation, GetTimeZoneInformation)
MISSING_IMPORT(imp_GetUserNameA, GetUserNameA)
MISSING_IMPORT(imp_GetVersion, GetVersion)
MISSING_IMPORT(imp_GetVersionExA, GetVersionExA)
MISSING_IMPORT(imp_GetWindowLongA, GetWindowLongA)
MISSING_IMPORT(imp_GetWindowRect, GetWindowRect)
MISSING_IMPORT(imp_HeapAlloc, HeapAlloc)
MISSING_IMPORT(imp_HeapCreate, HeapCreate)
MISSING_IMPORT(imp_HeapDestroy, HeapDestroy)
MISSING_IMPORT(imp_HeapFree, HeapFree)
MISSING_IMPORT(imp_HeapReAlloc, HeapReAlloc)
MISSING_IMPORT(imp_HeapSize, HeapSize)
MISSING_IMPORT(imp_InterlockedDecrement, InterlockedDecrement)
MISSING_IMPORT(imp_InterlockedIncrement, InterlockedIncrement)
MISSING_IMPORT(imp_InvalidateRect, InvalidateRect)
MISSING_IMPORT(imp_IsBadReadPtr, IsBadReadPtr)
MISSING_IMPORT(imp_IsBadWritePtr, IsBadWritePtr)
MISSING_IMPORT(imp_LCMapStringA, LCMapStringA)
MISSING_IMPORT(imp_LCMapStringW, LCMapStringW)
MISSING_IMPORT(imp_LoadCursorA, LoadCursorA)
MISSING_IMPORT(imp_LoadIconA, LoadIconA)
MISSING_IMPORT(imp_LoadImageA, LoadImageA)
MISSING_IMPORT(imp_LoadLibraryA, LoadLibraryA)
MISSING_IMPORT(imp_MessageBoxA, MessageBoxA)
MISSING_IMPORT(imp_MultiByteToWideChar, MultiByteToWideChar)
MISSING_IMPORT(imp_PostQuitMessage, PostQuitMessage)
MISSING_IMPORT(imp_RaiseException, RaiseException)
MISSING_IMPORT(imp_RegCloseKey, RegCloseKey)
MISSING_IMPORT(imp_RegOpenKeyExA, RegOpenKeyExA)
MISSING_IMPORT(imp_RegQueryValueExA, RegQueryValueExA)
MISSING_IMPORT(imp_RegSetValueExA, RegSetValueExA)
MISSING_IMPORT(imp_RegisterClassExA, RegisterClassExA)
MISSING_IMPORT(imp_ResetEvent, ResetEvent)
MISSING_IMPORT(imp_RtlUnwind, RtlUnwind)
MISSING_IMPORT(imp_SDrawDestroy, SDrawDestroy)
MISSING_IMPORT(imp_SDrawManualInitialize, SDrawManualInitialize)
MISSING_IMPORT(imp_SDrawMessageBox, SDrawMessageBox)
MISSING_IMPORT(imp_SFileSetBasePath, SFileSetBasePath)
MISSING_IMPORT(imp_SHGetPathFromIDListA, SHGetPathFromIDListA)
MISSING_IMPORT(imp_SHGetSpecialFolderLocation, SHGetSpecialFolderLocation)
MISSING_IMPORT(imp_SVidDestroy, SVidDestroy)
MISSING_IMPORT(imp_SVidInitialize, SVidInitialize)
MISSING_IMPORT(imp_SVidPlayBegin, SVidPlayBegin)
MISSING_IMPORT(imp_SVidPlayContinue, SVidPlayContinue)
MISSING_IMPORT(imp_SVidPlayEnd, SVidPlayEnd)
MISSING_IMPORT(imp_SetDlgItemTextA, SetDlgItemTextA)
MISSING_IMPORT(imp_SetEnvironmentVariableA, SetEnvironmentVariableA)
MISSING_IMPORT(imp_SetEvent, SetEvent)
MISSING_IMPORT(imp_SetHandleCount, SetHandleCount)
MISSING_IMPORT(imp_SetStdHandle, SetStdHandle)
MISSING_IMPORT(imp_SetUnhandledExceptionFilter, SetUnhandledExceptionFilter)
MISSING_IMPORT(imp_SetWindowLongA, SetWindowLongA)
MISSING_IMPORT(imp_SetWindowPos, SetWindowPos)
MISSING_IMPORT(imp_ShellExecuteA, ShellExecuteA)
MISSING_IMPORT(imp_ShowWindow, ShowWindow)
MISSING_IMPORT(imp_StormDestroy, StormDestroy)
MISSING_IMPORT(imp_TerminateProcess, TerminateProcess)
MISSING_IMPORT(imp_TlsAlloc, TlsAlloc)
MISSING_IMPORT(imp_TlsGetValue, TlsGetValue)
MISSING_IMPORT(imp_TlsSetValue, TlsSetValue)
MISSING_IMPORT(imp_UnhandledExceptionFilter, UnhandledExceptionFilter)
MISSING_IMPORT(imp_UpdateWindow, UpdateWindow)
MISSING_IMPORT(imp_VerQueryValueA, VerQueryValueA)
MISSING_IMPORT(imp_VirtualAlloc, VirtualAlloc)
MISSING_IMPORT(imp_VirtualFree, VirtualFree)
MISSING_IMPORT(imp_VirtualQuery, VirtualQuery)
MISSING_IMPORT(imp_WideCharToMultiByte, WideCharToMultiByte)
MISSING_IMPORT(imp_lstrcpynA, lstrcpynA)
MISSING_IMPORT(imp_wvsprintfA, wvsprintfA)

47
Absolute/absolute-stubs.h

@ -0,0 +1,47 @@
LINK_STUB(d_CaptureScreen, CaptureScreen)
LINK_STUB(d_DDErrMsg, DDErrMsg)
LINK_STUB(d_DirErrorDlg, DirErrorDlg)
LINK_STUB(d_DiskFreeDlg, DiskFreeDlg)
LINK_STUB(d_DrawDlg, DrawDlg)
LINK_STUB(d_ErrDlg, ErrDlg)
LINK_STUB(d_ErrOkDlg, ErrOkDlg)
LINK_STUB(d_FileErrDlg, FileErrDlg)
LINK_STUB(d_InsertCDDlg, InsertCDDlg)
LINK_STUB(d_MainWndProc, MainWndProc)
LINK_STUB(d_ReadOnlyTest, ReadOnlyTest)
LINK_STUB(d_RestrictedTest, RestrictedTest)
LINK_STUB(d_SetWindowProc, SetWindowProc)
LINK_STUB(d_TermMsg, TermMsg)
LINK_STUB(d_TraceLastError, TraceLastError)
LINK_STUB(d_dthread_cleanup, dthread_cleanup)
LINK_STUB(d_dthread_remove_player, dthread_remove_player)
LINK_STUB(d_dthread_send_delta, dthread_send_delta)
LINK_STUB(d_dthread_start, dthread_start)
LINK_STUB(d_dx_init, dx_init)
LINK_STUB(d_dx_reinit, dx_reinit)
LINK_STUB(d_exception_get_filter, exception_get_filter)
LINK_STUB(d_init_archives, init_archives)
LINK_STUB(d_init_create_window, init_create_window)
LINK_STUB(d_init_get_file_info, init_get_file_info)
LINK_STUB(d_lock_buf_priv, lock_buf_priv)
LINK_STUB(d_music_start, music_start)
LINK_STUB(d_music_stop, music_stop)
LINK_STUB(d_nthread_cleanup, nthread_cleanup)
LINK_STUB(d_nthread_has_500ms_passed, nthread_has_500ms_passed)
LINK_STUB(d_nthread_ignore_mutex, nthread_ignore_mutex)
LINK_STUB(d_nthread_recv_turns, nthread_recv_turns)
LINK_STUB(d_nthread_send_and_recv_turn, nthread_send_and_recv_turn)
LINK_STUB(d_nthread_set_turn_upper_bit, nthread_set_turn_upper_bit)
LINK_STUB(d_nthread_start, nthread_start)
LINK_STUB(d_nthread_terminate_game, nthread_terminate_game)
LINK_STUB(d_play_movie, play_movie)
LINK_STUB(d_snd_init, snd_init)
LINK_STUB(d_snd_play_snd, snd_play_snd)
LINK_STUB(d_snd_playing, snd_playing)
LINK_STUB(d_snd_stop_snd, snd_stop_snd)
LINK_STUB(d_snd_update, snd_update)
LINK_STUB(d_sound_file_cleanup, sound_file_cleanup)
LINK_STUB(d_sound_file_load, sound_file_load)
LINK_STUB(d_sound_get_or_set_music_volume, sound_get_or_set_music_volume)
LINK_STUB(d_sound_get_or_set_sound_volume, sound_get_or_set_sound_volume)
LINK_STUB(d_unlock_buf_priv, unlock_buf_priv)

55
Absolute/absolute.cpp

@ -0,0 +1,55 @@
#include <assert.h>
#include <string.h>
#include <sys/mman.h>
#include "Stub/stubs.h"
#include "absolute.h"
#include "hook.h"
static void missing_import()
{
UNIMPLEMENTED();
}
static void link_imports()
{
#define LINK_IMPORT(imp_name, name) imp_name = (void *)name;
#define MISSING_IMPORT(imp_name, name) imp_name = (void *)missing_import;
#include "absolute-imports.h"
}
static void link_stubs()
{
#define LINK_STUB(orig, dest) hook((void *)orig, (void *)dest);
#include "absolute-stubs.h"
LINK_STUB(d_srand, srand_miniwin);
LINK_STUB(d_rand, rand_miniwin);
LINK_STUB(d_time, time);
LINK_STUB(d_sprintf, sprintf); // Calls into kernel
// These functions potentially access uninitialized memory
LINK_STUB(d_strcat, strcat);
LINK_STUB(d_strcpy, strcpy);
LINK_STUB(d_strlen, strlen);
// strchr() is overloaded in glibc C++ mode, pick right function....
char *(*strchr_overload)(char *, int) = strchr;
LINK_STUB(d_strchr, strchr_overload);
}
static void protect_rdata(int prot)
{
mprotect(&__start_rdata, &__end_rdata - &__start_rdata, prot);
}
void init_absolute()
{
protect_rdata(PROT_READ | PROT_WRITE);
link_imports();
protect_rdata(PROT_READ);
link_stubs();
}

6
Absolute/absolute.h

@ -0,0 +1,6 @@
#pragma once
#include "../types.h"
#include "absolute-decls.h"
void init_absolute();

230
Absolute/default.ld

@ -0,0 +1,230 @@
/* Script for -z combreloc -z separate-code: combine and sort reloc sections with separate code segment */
/* Copyright (C) 2014-2018 Free Software Foundation, Inc.
Copying and distribution of this script, with or without modification,
are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("=/usr/local/lib/i386-linux-gnu"); SEARCH_DIR("=/lib/i386-linux-gnu"); SEARCH_DIR("=/usr/lib/i386-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu32"); SEARCH_DIR("=/usr/local/lib32"); SEARCH_DIR("=/lib32"); SEARCH_DIR("=/usr/lib32"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/i386-linux-gnu/lib32"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib32"); SEARCH_DIR("=/usr/i386-linux-gnu/lib");
SECTIONS
{
INCLUDE "sections.ld"
/* Note: Start address of regular sections was adjusted for
there to be enough contiguous virtual address space for eg. Valgrind. */
/* Read-only sections, merged into text segment: */
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x0A00000));
. = SEGMENT_START("text-segment", 0x0A00000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rel.dyn :
{
*(.rel.init)
*(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
*(.rel.fini)
*(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
*(.rel.data.rel.ro .rel.data.rel.ro.* .rel.gnu.linkonce.d.rel.ro.*)
*(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
*(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
*(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
*(.rel.ctors)
*(.rel.dtors)
*(.rel.got)
*(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
*(.rel.ifunc)
}
.rel.plt :
{
*(.rel.plt)
PROVIDE_HIDDEN (__rel_iplt_start = .);
*(.rel.iplt)
PROVIDE_HIDDEN (__rel_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
.rodata1 : { *(.rodata1) }
.eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) }
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
.gcc_except_table.*) }
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) }
/* These sections are generated by the Sun/Oracle C++ compiler. */
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
.exception_ranges*) }
/* Adjust the address for the data segment. We want to adjust up to
the same address within the page on the next page up. */
. = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
/* Exception handling */
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) }
.gnu_extab : ONLY_IF_RW { *(.gnu_extab) }
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
/* Thread Local Storage sections */
.tdata :
{
PROVIDE_HIDDEN (__tdata_start = .);
*(.tdata .tdata.* .gnu.linkonce.td.*)
}
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
.preinit_array :
{
PROVIDE_HIDDEN (__preinit_array_start = .);
KEEP (*(.preinit_array))
PROVIDE_HIDDEN (__preinit_array_end = .);
}
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
.fini_array :
{
PROVIDE_HIDDEN (__fini_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
PROVIDE_HIDDEN (__fini_array_end = .);
}
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*crtbegin?.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
}
.jcr : { KEEP (*(.jcr)) }
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
.dynamic : { *(.dynamic) }
.got : { *(.got) *(.igot) }
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 12 ? 12 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss section occupies space up to
_end. Align after .bss to ensure correct alignment even if the
.bss section disappears because there are no input sections.
FIXME: Why do we need it? When there is no .bss section, we don't
pad the .data section. */
. = ALIGN(. != 0 ? 32 / 8 : 1);
}
. = ALIGN(32 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(32 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.comment 0 : { *(.comment) }
/* DWARF debug sections.
Symbols in the DWARF debugging sections are relative to the beginning
of the section so we begin them at 0. */
/* DWARF 1 */
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
/* GNU DWARF 1 extensions */
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
/* DWARF 1.1 and DWARF 2 */
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
/* DWARF 2 */
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
/* SGI/MIPS DWARF 2 extensions */
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* DWARF 3 */
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
/* DWARF Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
}

8500
Absolute/harness.asm

File diff suppressed because it is too large Load Diff

32
Absolute/hook.cpp

@ -0,0 +1,32 @@
#include <assert.h>
#include <sys/mman.h>
#include "hook.h"
#pragma pack(push, 1)
struct hook_jmp_rel32 {
uint8_t op;
int32_t offset;
};
#pragma pack(pop)
static void hook_assemble_jump(void *at, void *to)
{
hook_jmp_rel32 *jmp = (hook_jmp_rel32 *)at;
jmp->op = 0xE9;
jmp->offset = (intptr_t)to - ((intptr_t)at + sizeof(*jmp));
}
static int hook_unprotect(void *address, size_t size)
{
// Align to bottom of page
address = (void *)((uintptr_t)address & ~(4096 - 1));
return mprotect(address, size, PROT_READ | PROT_WRITE | PROT_EXEC);
}
void hook(void *at, void *to)
{
assert(hook_unprotect(at, sizeof(hook_jmp_rel32)) == 0);
hook_assemble_jump(at, to);
}

6
Absolute/hook.h

@ -0,0 +1,6 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
void hook(void *at, void *to);

4
Absolute/sections.ld

@ -0,0 +1,4 @@
. = 0x00401000; .d.text : { *(.d.text) }
. = 0x00479000; .d.rdata : { *(.d.rdata) }
. = 0x00483000; .d.data : { *(.d.data) }
. = 0x004B7930; .d.bss : { *(.d.bss) }

22
CMake/32bit.cmake

@ -0,0 +1,22 @@
message(STATUS "Using 32-bit toolchain")
set(CMAKE_CXX_FLAGS -m32 CACHE STRING "")
# Affects pkg-config
set_property(GLOBAL PROPERTY FIND_LIBRARY_USE_LIB32_PATHS TRUE)
# Used by pkg-config on Debian
set(CMAKE_LIBRARY_ARCHITECTURE i386-linux-gnu)
# Silly hack required to get the pkg-config path code to activate
list(APPEND CMAKE_PREFIX_PATH /usr)
# Find where 32-bit CMake modules are stored
find_path(DIR NAMES cmake PATHS /usr/lib32 /usr/lib/i386-linux-gnu NO_DEFAULT_PATH)
if(DIR)
message(STATUS "Using 32-bit libraries from ${DIR}")
# Read CMake modules from 32-bit packages
set(CMAKE_FIND_ROOT_PATH ${DIR})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
endif()

16
CMake/SDL2_fixed.cmake

@ -0,0 +1,16 @@
include(FindPkgConfig)
pkg_check_modules(SDL2 sdl2)
if(NOT SDL2_LIBRARIES)
find_package(SDL2 REQUIRED)
# WORKAROUND: Arch Linux SDL2 cmake config not setting this variable
if(NOT SDL2_LIBRARIES)
# Note: you will probably need to install multilib/lib32-dbus on Arch
set(SDL2_LIBRARIES SDL2::SDL2)
endif()
endif()
# WORKAROUND: Issue with Ubuntu 16.04 having whitespace (CMP0004)
string(STRIP "${SDL2_LIBRARIES}" SDL2_LIBRARIES)

36
CMake/absolute.cmake

@ -0,0 +1,36 @@
set(ORIGINAL_EXE "${CMAKE_SOURCE_DIR}/Diablo.exe")
if(EXISTS "${ORIGINAL_EXE}")
message(STATUS "Using EXE at ${ORIGINAL_EXE}")
file(MD5 ${ORIGINAL_EXE} MD5SUM)
if(NOT MD5SUM STREQUAL "da62d5cd8bd71a0b66e6d4ef7a111233")
message(FATAL_ERROR "MD5 of EXE is not correct (${MD5SUM})")
endif()
find_program(ASM NAMES nasm yasm)
set(HARNESS_OBJECT "${CMAKE_BINARY_DIR}/harness.o")
set(HARNESS_ASM "${CMAKE_SOURCE_DIR}/Absolute/harness.asm")
add_library(harness OBJECT ${HARNESS_OBJECT})
target_compile_options(harness PUBLIC -no-pie)
target_compile_definitions(harness INTERFACE -DNO_GLOBALS)
# For some reason, HARNESS_OBJECT needs to be added here even though it's in the sources above
target_link_libraries(harness INTERFACE
${HARNESS_OBJECT}
-L${CMAKE_SOURCE_DIR}/Absolute -Tdefault.ld
)
add_custom_command(
COMMENT Assembling
OUTPUT ${HARNESS_OBJECT}
MAIN_DEPENDENCY ${HARNESS_ASM}
COMMAND ${ASM}
-f elf -DEXE=\\"${ORIGINAL_EXE}\\"
-o ${HARNESS_OBJECT}
${HARNESS_ASM}
)
else()
message(STATUS "Original .exe not found at ${ORIGINAL_EXE}")
endif()

3
CMake/out_of_tree.cmake

@ -0,0 +1,3 @@
if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR})
message(WARNING [[In-source build detected, please eg. create a new directory and use `cmake ..`]])
endif()

18
CMake/sanitize.cmake

@ -0,0 +1,18 @@
include(CheckCXXCompilerFlag)
include(CMakePushCheckState)
set(SANITIZE_OPTIONS -fsanitize=null -fsanitize=return)
# TODO: use "-fsanitize=object-size"
# "-fsanitize=bounds" not enabled because the code often generates temporary pointers out-of-bounds of arrays
# Note: The compiler must always support recovery because the decompiled code is not ASAN-clean
set(SANITIZE_ADDRESS_FLAGS -fsanitize=address -fsanitize-recover=address)
cmake_push_check_state()
set(CMAKE_REQUIRED_LIBRARIES ${SANITIZE_ADDRESS_FLAGS})
check_cxx_compiler_flag("${SANITIZE_ADDRESS_FLAGS}" HAS_SANITIZE_ADDRESS)
cmake_pop_check_state()
if(HAS_SANITIZE_ADDRESS)
list(APPEND SANITIZE_OPTIONS ${SANITIZE_ADDRESS_FLAGS})
endif()

220
CMakeLists.txt

@ -0,0 +1,220 @@
cmake_minimum_required(VERSION 3.5)
# Turn on modern `try_compile()` policies.
if(POLICY CMP0066)
cmake_policy(SET CMP0066 NEW)
endif()
if(POLICY CMP0067)
cmake_policy(SET CMP0067 NEW)
endif()
include(CMake/out_of_tree.cmake)
# This *must* be included before calling `project()`, due to setting early compiler flags.
include(CMake/32bit.cmake)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
project(devil-miniwin
VERSION 0.0.1
LANGUAGES C CXX
)
if(NOT CMAKE_SIZEOF_VOID_P EQUAL 4)
message(WARNING "sizeof(void*) == ${CMAKE_SIZEOF_VOID_P}.")
message(FATAL_ERROR [[This project can only be compiled in 32-bit mode.]])
endif()
# Note: In Debug mode, GCC generates spurious memory references that upset Valgrind,
# these options fix that.
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-omit-frame-pointer")
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Clang/LLVM optimizations break everything
string(APPEND CMAKE_CXX_FLAGS_DEBUG " -Og")
endif()
set(SOURCES
Source/automap.cpp
Source/codec.cpp
Source/control.cpp
Source/cursor.cpp
Source/dead.cpp
Source/debug.cpp
Source/diablo.cpp
Source/doom.cpp
Source/drlg_l1.cpp
Source/drlg_l2.cpp
Source/drlg_l3.cpp
Source/drlg_l4.cpp
Source/effects.cpp
Source/encrypt.cpp
Source/engine.cpp
Source/error.cpp
Source/gamemenu.cpp
Source/gendung.cpp
Source/gmenu.cpp
Source/help.cpp
Source/interfac.cpp
Source/inv.cpp
Source/items.cpp
Source/lighting.cpp
Source/loadsave.cpp
Source/mainmenu.cpp
Source/minitext.cpp
Source/missiles.cpp
Source/monster.cpp
Source/mpqapi.cpp
Source/msgcmd.cpp
Source/msg.cpp
Source/multi.cpp
Source/objects.cpp
Source/pack.cpp
Source/palette.cpp
Source/path.cpp
Source/pfile.cpp
Source/player.cpp
Source/plrmsg.cpp
Source/portal.cpp
Source/quests.cpp
Source/render.cpp
Source/scrollrt.cpp
Source/setmaps.cpp
Source/sha.cpp
Source/spells.cpp
Source/stores.cpp
Source/sync.cpp
Source/textdat.cpp
Source/themes.cpp
Source/tmsg.cpp
Source/town.cpp
Source/towners.cpp
Source/track.cpp
Source/trigs.cpp
Source/wave.cpp
3rdParty/PKWare/explode.cpp
3rdParty/PKWare/implode.cpp
)
# Stubbed out sources, for reference
set(ORIGINAL_SOURCES
Source/capture.cpp
Source/appfat.cpp
Source/dthread.cpp
Source/dx.cpp
Source/fault.cpp
Source/init.cpp
Source/logging.cpp
Source/movie.cpp
Source/nthread.cpp
Source/restrict.cpp
Source/sound.cpp
)
set(STUB_SOURCES
Stub/miniwin.cpp
Stub/miniwin_rand.cpp
Stub/appfat.cpp
Stub/capture.cpp
Stub/dthread.cpp
Stub/dx.cpp
Stub/fault.cpp
Stub/init.cpp
Stub/movie.cpp
Stub/nthread.cpp
Stub/restrict.cpp
Stub/sound.cpp
Stub/storm.cpp
Stub/diabloui.cpp
Stub/miniwin_io.cpp
Stub/miniwin_msg_sdl.cpp
Stub/storm_net.cpp
Stub/validate.cpp
3rdParty/StormLib/src/FileStream.cpp
3rdParty/StormLib/src/SBaseCommon.cpp
3rdParty/StormLib/src/SBaseFileTable.cpp
3rdParty/StormLib/src/SBaseSubTypes.cpp
3rdParty/StormLib/src/SCompression.cpp
3rdParty/StormLib/src/SFileExtractFile.cpp
3rdParty/StormLib/src/SFileFindFile.cpp
3rdParty/StormLib/src/SFileGetFileInfo.cpp
3rdParty/StormLib/src/SFileOpenArchive.cpp
3rdParty/StormLib/src/SFileOpenFileEx.cpp
3rdParty/StormLib/src/SFileReadFile.cpp
)
include(CMake/SDL2_fixed.cmake)
include(CMake/sanitize.cmake)
include(CMake/absolute.cmake)
include_directories(${SDL2_INCLUDE_DIRS})
include_directories(. Stub)
# FUTURE: use add_compile_definitions()
add_definitions(
-D_DEBUG
-DMINIWIN
# Skip fades and other fluff
-DFASTER
)
# Ignore serious warnings due to "quality" of decompiled code
add_compile_options(-fpermissive -Wno-write-strings -Wno-multichar)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Style issues
add_compile_options(-Wno-parentheses -Wno-logical-op-parentheses -Wno-bitwise-op-parentheses)
# Silence warnings about __int64 alignment hack not always being applicable
add_compile_options(-Wno-ignored-attributes)
# Fix: error: cast from pointer to smaller type 'unsigned char' loses information
add_compile_options(-fms-extensions)
endif()
# Vanilla build
add_executable(devilution
${SOURCES}
${STUB_SOURCES}
Stub/main.cpp
)
target_link_libraries(devilution PUBLIC
m
${SDL2_LIBRARIES}
)
# Build with harness enabled (conflicts with sanitizers)
if(TARGET harness)
add_executable(devil-harness
${SOURCES}
${STUB_SOURCES}
Stub/main_harness.cpp
Absolute/absolute.cpp
Absolute/hook.cpp
)
target_link_libraries(devil-harness PUBLIC
m
harness
${SDL2_LIBRARIES}
)
endif()
# Build with sanitizers enabled
add_executable(devil-sanitize
${SOURCES}
${STUB_SOURCES}
Stub/main_test.cpp
)
target_compile_options(devil-sanitize PRIVATE
${SANITIZE_OPTIONS}
)
target_link_libraries(devil-sanitize PUBLIC
m
${SDL2_LIBRARIES}
${SANITIZE_OPTIONS}
)

14
Stub/.clang-format

@ -0,0 +1,14 @@
---
IndentWidth: 4
TabWidth: 4
---
Language: Cpp
UseTab: ForIndentation
AlignTrailingComments: false
BreakBeforeBraces: Linux
ColumnLimit: 120
IncludeBlocks: Preserve
AlignEscapedNewlines: DontAlign
AlignOperands: true
AllowShortFunctionsOnASingleLine: Inline
Standard: Cpp11

66
Stub/appfat.cpp

@ -0,0 +1,66 @@
#include <stdarg.h>
#include "../types.h"
#include "stubs.h"
char empty_string = 0;
void TermMsg(char *pszFmt, ...)
{
char buf[256];
va_list args;
va_start(args, pszFmt);
vsnprintf(buf, sizeof(buf), pszFmt, args);
eprintf("%s: %s\n", __FUNCTION__, buf);
abort();
}
void __fastcall ErrDlg(int template_id, int error_code, char *log_file_path, int log_line_nr)
{
UNIMPLEMENTED();
}
void __fastcall ErrOkDlg(int template_id, int error_code, char *log_file_path, int log_line_nr)
{
UNIMPLEMENTED();
}
void __fastcall DirErrorDlg(char *error)
{
UNIMPLEMENTED();
}
bool __cdecl InsertCDDlg()
{
UNIMPLEMENTED();
}
void __fastcall FileErrDlg(char *error)
{
UNIMPLEMENTED();
}
void __fastcall DDErrMsg(int error_code, int log_line_nr, char *log_file_path)
{
UNIMPLEMENTED();
}
void __fastcall DiskFreeDlg(char *error)
{
UNIMPLEMENTED();
}
void DrawDlg(char *pszFmt, ...)
{
UNIMPLEMENTED();
}
char *__cdecl TraceLastError()
{
DUMMY();
return NULL;
}

7
Stub/capture.cpp

@ -0,0 +1,7 @@
#include "../types.h"
#include "stubs.h"
void __cdecl CaptureScreen()
{
DUMMY();
}

182
Stub/diabloui.cpp

@ -0,0 +1,182 @@
#include <vector>
#include "../types.h"
#include "stubs.h"
void __cdecl UiDestroy()
{
DUMMY();
}
BOOL __stdcall UiTitleDialog(int a1)
{
DUMMY();
return TRUE;
}
void __cdecl UiInitialize()
{
DUMMY();
}
static std::vector<_uiheroinfo> hero_infos;
static BOOL __stdcall ui_add_hero_info(_uiheroinfo *info)
{
hero_infos.emplace_back(*info);
return TRUE;
}
BOOL __stdcall UiSelHeroSingDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)),
BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *),
BOOL(__stdcall *fnstats)(int, _uidefaultstats *), int *dlgresult, char *name,
int *difficulty)
{
DUMMY();
hero_infos.clear();
fninfo(&ui_add_hero_info);
// If a hero is available, load it, otherwise create a new one
if (!hero_infos.empty()) {
const char *hero_name = hero_infos[0].name;
DUMMY_PRINT("use hero: %s", hero_name);
strcpy(name, hero_name);
*dlgresult = 2;
} else {
const char *test_name = "tester";
DUMMY_PRINT("create hero: %s", test_name);
strcpy(name, test_name);
_uiheroinfo hero_info = {0};
strcpy(hero_info.name, test_name);
hero_info.heroclass = PC_SORCERER;
fncreate(&hero_info);
}
return TRUE;
}
BOOL __stdcall UiMainMenuDialog(char *name, int *pdwResult, void(__stdcall *fnSound)(char *file), int a4)
{
DUMMY();
// Pretend we selected Single Player from the main menu
*pdwResult = MAINMENU_SINGLE_PLAYER;
return TRUE;
}
int __cdecl UiProfileGetString()
{
DUMMY();
return 0;
}
void __stdcall UiSetupPlayerInfo(char *infostr, _uiheroinfo *pInfo, int type)
{
DUMMY_PRINT("chr: %s", infostr);
}
BOOL __stdcall UiCopyProtError(int *pdwResult)
{
UNIMPLEMENTED();
}
void __stdcall UiAppActivate(BOOL bActive)
{
UNIMPLEMENTED();
}
BOOL __fastcall UiValidPlayerName(char *name)
{
UNIMPLEMENTED();
}
int __stdcall UiProgressDialog(HWND window, char *msg, int a3, void *fnfunc, int a5)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiSelHeroMultDialog(BOOL(__stdcall *fninfo)(BOOL(__stdcall *fninfofunc)(_uiheroinfo *)),
BOOL(__stdcall *fncreate)(_uiheroinfo *), BOOL(__stdcall *fnremove)(_uiheroinfo *),
BOOL(__stdcall *fnstats)(int, _uidefaultstats *), int *dlgresult, int *a6,
char *name)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiCreditsDialog(int a1)
{
UNIMPLEMENTED();
}
void __cdecl UiProfileCallback()
{
UNIMPLEMENTED();
}
void __cdecl UiProfileDraw()
{
UNIMPLEMENTED();
}
BOOL __stdcall UiCategoryCallback(int a1, int a2, int a3, int a4, int a5, _DWORD *a6, _DWORD *a7)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiGetDataCallback(int game_type, int data_code, void *a3, int a4, int a5)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiAuthCallback(int a1, char *a2, char *a3, char a4, char *a5, LPSTR lpBuffer, int cchBufferMax)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiSoundCallback(int a1, int type, int a3)
{
UNIMPLEMENTED();
}
void __stdcall UiMessageBoxCallback(HWND hWnd, char *lpText, LPCSTR lpCaption, UINT uType)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiDrawDescCallback(int arg0, COLORREF color, LPCSTR lpString, char *a4, int a5, UINT align, time_t a7,
HDC *a8)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiCreateGameCallback(int a1, int a2, int a3, int a4, int a5, int a6)
{
UNIMPLEMENTED();
}
BOOL __stdcall UiArtCallback(int game_type, unsigned int art_code, PALETTEENTRY *pPalette, void *pBuffer,
DWORD dwBuffersize, DWORD *pdwWidth, DWORD *pdwHeight, DWORD *pdwBpp)
{
UNIMPLEMENTED();
}
int __stdcall UiSelectGame(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info,
_SNETVERSIONDATA *file_info, int *a6)
{
UNIMPLEMENTED();
}
int __stdcall UiSelectProvider(int a1, _SNETPROGRAMDATA *client_info, _SNETPLAYERDATA *user_info, _SNETUIDATA *ui_info,
_SNETVERSIONDATA *file_info, int *type)
{
UNIMPLEMENTED();
}
int __stdcall UiCreatePlayerDescription(_uiheroinfo *info, int mode, char *desc)
{
UNIMPLEMENTED();
}

22
Stub/dthread.cpp

@ -0,0 +1,22 @@
#include "../types.h"
#include "stubs.h"
void __cdecl dthread_start()
{
DUMMY();
}
void __cdecl dthread_cleanup()
{
DUMMY();
}
void __fastcall dthread_send_delta(int pnum, char cmd, void *pbSrc, int dwLen)
{
DUMMY();
}
void __fastcall dthread_remove_player(int pnum)
{
UNIMPLEMENTED();
}

375
Stub/dx.cpp

@ -0,0 +1,375 @@
#include "dx_stub.h"
#include "miniwin_sdl.h"
#include "../types.h"
#include "stubs.h"
#ifndef NO_GLOBALS
Screen *gpBuffer;
IDirectDraw *lpDDInterface;
IDirectDrawSurface *lpDDSPrimary;
IDirectDrawSurface *lpDDSBackBuf;
IDirectDrawPalette *lpDDPalette;
char gbBackBuf; // unread
char gbEmulate; // unread
#endif
SDL_Window *sdl_window;
SDL_Renderer *sdl_renderer;
SDL_Texture *sdl_render_texture;
/** 32-bit in-memory backbuffer surface */
SDL_Surface *sdl_surface;
/** 8-bit surface wrapper around #gpBuffer */
SDL_Surface *sdl_pal_surface;
/** Currently active palette */
SDL_Palette *sdl_palette;
/**
* Is #sdl_pal_surface dirty?
*
* This is required so the front buffer would not be updated twice per game loop in unlock_buf_priv()
* which causes the cursor to flicker.
*/
bool surface_dirty;
//
// DirectDraw COM interface stub implementations
//
#define METHOD virtual __stdcall
class StubSurface : public IDirectDrawSurface
{
METHOD HRESULT QueryInterface(REFIID refiid, LPVOID *lpvoid) { UNIMPLEMENTED(); };
METHOD ULONG AddRef() { UNIMPLEMENTED(); };
METHOD ULONG Release() { UNIMPLEMENTED(); };
METHOD HRESULT AddAttachedSurface(LPDIRECTDRAWSURFACE lpDDSAttachedSurface) { UNIMPLEMENTED(); }
METHOD HRESULT AddOverlayDirtyRect(LPRECT lpRect) { UNIMPLEMENTED(); }
METHOD HRESULT Blt(LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags,
LPDDBLTFX lpDDBltFx)
{
UNIMPLEMENTED();
}
METHOD HRESULT BltBatch(LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags) { UNIMPLEMENTED(); }
METHOD HRESULT BltFast(DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans)
{
DUMMY_ONCE();
assert(lpDDSrcSurface == lpDDSBackBuf);
int w = lpSrcRect->right - lpSrcRect->left + 1;
int h = lpSrcRect->bottom - lpSrcRect->top + 1;
SDL_Rect src_rect = {lpSrcRect->left, lpSrcRect->top, w, h};
SDL_Rect dst_rect = {(int)dwX, (int)dwY, w, h};
// Convert from 8-bit to 32-bit
SDL_CHECK(SDL_BlitSurface(sdl_pal_surface, &src_rect, sdl_surface, &dst_rect));
surface_dirty = true;
return S_OK;
}
METHOD HRESULT DeleteAttachedSurface(DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSAttachedSurface) { UNIMPLEMENTED(); }
METHOD HRESULT EnumAttachedSurfaces(LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback)
{
UNIMPLEMENTED();
}
METHOD HRESULT EnumOverlayZOrders(DWORD dwFlags, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpfnCallback)
{
UNIMPLEMENTED();
}
METHOD HRESULT Flip(LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DWORD dwFlags) { UNIMPLEMENTED(); }
METHOD HRESULT GetAttachedSurface(LPDDSCAPS lpDDSCaps, LPDIRECTDRAWSURFACE *lplpDDAttachedSurface)
{
UNIMPLEMENTED();
}
METHOD HRESULT GetBltStatus(DWORD dwFlags) { UNIMPLEMENTED(); }
METHOD HRESULT GetCaps(LPDDSCAPS lpDDSCaps) { UNIMPLEMENTED(); }
METHOD HRESULT GetClipper(LPDIRECTDRAWCLIPPER *lplpDDClipper) { UNIMPLEMENTED(); }
METHOD HRESULT GetColorKey(DWORD dwFlags, LPDDCOLORKEY lpDDColorKey) { UNIMPLEMENTED(); }
METHOD HRESULT GetDC(HDC *lphDC)
{
DUMMY_ONCE();
return S_OK;
}
METHOD HRESULT GetFlipStatus(DWORD dwFlags) { UNIMPLEMENTED(); }
METHOD HRESULT GetOverlayPosition(LPLONG lplX, LPLONG lplY) { UNIMPLEMENTED(); }
METHOD HRESULT GetPalette(LPDIRECTDRAWPALETTE *lplpDDPalette) { UNIMPLEMENTED(); }
METHOD HRESULT GetPixelFormat(LPDDPIXELFORMAT lpDDPixelFormat) { UNIMPLEMENTED(); }
METHOD HRESULT GetSurfaceDesc(LPDDSURFACEDESC lpDDSurfaceDesc) { UNIMPLEMENTED(); }
METHOD HRESULT Initialize(LPDIRECTDRAW lpDD, LPDDSURFACEDESC lpDDSurfaceDesc) { UNIMPLEMENTED(); }
METHOD HRESULT IsLost()
{
DUMMY_ONCE();
return S_OK;
}
METHOD HRESULT Lock(LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags, HANDLE hEvent)
{
UNIMPLEMENTED();
}
METHOD HRESULT ReleaseDC(HDC hDC)
{
DUMMY_ONCE();
return S_OK;
}
METHOD HRESULT Restore() { UNIMPLEMENTED(); }
METHOD HRESULT SetClipper(LPDIRECTDRAWCLIPPER lpDDClipper) { UNIMPLEMENTED(); }
METHOD HRESULT SetColorKey(DWORD dwFlags, LPDDCOLORKEY lpDDColorKey) { UNIMPLEMENTED(); }
METHOD HRESULT SetOverlayPosition(LONG lX, LONG lY) { UNIMPLEMENTED(); }
METHOD HRESULT SetPalette(LPDIRECTDRAWPALETTE lpDDPalette) { UNIMPLEMENTED(); }
METHOD HRESULT Unlock(LPVOID lpSurfaceData) { UNIMPLEMENTED(); }
METHOD HRESULT UpdateOverlay(LPRECT lpSrcRect, LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect,
DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx)
{
UNIMPLEMENTED();
}
METHOD HRESULT UpdateOverlayDisplay(DWORD dwFlags) { UNIMPLEMENTED(); }
METHOD HRESULT UpdateOverlayZOrder(DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSReference) { UNIMPLEMENTED(); }
};
class StubPalette : public IDirectDrawPalette
{
METHOD HRESULT QueryInterface(REFIID refiid, LPVOID *lpvoid) { UNIMPLEMENTED(); };
METHOD ULONG AddRef() { UNIMPLEMENTED(); };
METHOD ULONG Release() { UNIMPLEMENTED(); };
METHOD HRESULT GetCaps(LPDWORD lpdwCaps) { UNIMPLEMENTED(); };
METHOD HRESULT GetEntries(DWORD dwFlags, DWORD dwBase, DWORD dwNumEntries, LPPALETTEENTRY lpEntries)
{
UNIMPLEMENTED();
};
METHOD HRESULT Initialize(LPDIRECTDRAW lpDD, DWORD dwFlags, LPPALETTEENTRY lpDDColorTable) { UNIMPLEMENTED(); };
METHOD HRESULT SetEntries(DWORD dwFlags, DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries)
{
UNIMPLEMENTED();
};
};
class StubDraw : public IDirectDraw
{
METHOD HRESULT QueryInterface(REFIID refiid, LPVOID *lpvoid) { UNIMPLEMENTED(); };
METHOD ULONG AddRef() { UNIMPLEMENTED(); };
METHOD ULONG Release() { UNIMPLEMENTED(); };
METHOD HRESULT Compact() { UNIMPLEMENTED(); }
METHOD HRESULT CreateClipper(DWORD dwFlags, LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter)
{
UNIMPLEMENTED();
}
METHOD HRESULT CreatePalette(DWORD dwFlags, LPPALETTEENTRY lpColorTable, LPDIRECTDRAWPALETTE *lplpDDPalette,
IUnknown *pUnkOuter)
{
UNIMPLEMENTED();
}
METHOD HRESULT CreateSurface(LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE *lplpDDSurface,
IUnknown *pUnkOuter)
{
UNIMPLEMENTED();
}
METHOD HRESULT DuplicateSurface(LPDIRECTDRAWSURFACE lpDDSurface, LPDIRECTDRAWSURFACE *lplpDupDDSurface)
{
UNIMPLEMENTED();
}
METHOD HRESULT EnumDisplayModes(DWORD dwFlags, LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext,
LPDDENUMMODESCALLBACK lpEnumModesCallback)
{
UNIMPLEMENTED();
}
METHOD HRESULT EnumSurfaces(DWORD dwFlags, LPDDSURFACEDESC lpDDSD, LPVOID lpContext,
LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback)
{
UNIMPLEMENTED();
}
METHOD HRESULT FlipToGDISurface() { UNIMPLEMENTED(); }
METHOD HRESULT GetCaps(LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) { UNIMPLEMENTED(); }
METHOD HRESULT GetDisplayMode(LPDDSURFACEDESC lpDDSurfaceDesc) { UNIMPLEMENTED(); }
METHOD HRESULT GetFourCCCodes(LPDWORD lpNumCodes, LPDWORD lpCodes) { UNIMPLEMENTED(); }
METHOD HRESULT GetGDISurface(LPDIRECTDRAWSURFACE *lplpGDIDDSurface) { UNIMPLEMENTED(); }
METHOD HRESULT GetMonitorFrequency(LPDWORD lpdwFrequency) { UNIMPLEMENTED(); }
METHOD HRESULT GetScanLine(LPDWORD lpdwScanLine) { UNIMPLEMENTED(); }
METHOD HRESULT GetVerticalBlankStatus(BOOL *lpbIsInVB) { UNIMPLEMENTED(); }
METHOD HRESULT Initialize(GUID *lpGUID) { UNIMPLEMENTED(); }
METHOD HRESULT RestoreDisplayMode() { UNIMPLEMENTED(); }
METHOD HRESULT SetCooperativeLevel(HWND hWnd, DWORD dwFlags) { UNIMPLEMENTED(); }
METHOD HRESULT SetDisplayMode(DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) { UNIMPLEMENTED(); }
METHOD HRESULT WaitForVerticalBlank(DWORD dwFlags, HANDLE hEvent)
{
DUMMY();
return S_OK;
}
};
static StubDraw stub_draw;
static StubSurface stub_surface;
static StubPalette stub_palette;
//
// Main functions
//
void sdl_init_video()
{
SDL_CHECK(SDL_Init(SDL_INIT_VIDEO));
sdl_window =
SDL_CreateWindow("devil-test", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_SHOWN);
assert(sdl_window);
// Hack since ShowCursor is called before dx_init()
SDL_ShowCursor(SDL_DISABLE);
sdl_renderer = SDL_CreateRenderer(sdl_window, -1, SDL_RENDERER_PRESENTVSYNC);
assert(sdl_renderer);
// FUTURE: Use SDL_CreateRGBSurfaceWithFormat with SDL_PIXELFORMAT_RGBA8888
sdl_surface = SDL_CreateRGBSurface(0, 640, 480, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
assert(sdl_surface);
sdl_render_texture =
SDL_CreateTexture(sdl_renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 640, 480);
assert(sdl_render_texture);
sdl_palette = SDL_AllocPalette(256);
assert(sdl_palette);
}
void __fastcall dx_init(HWND hWnd)
{
DUMMY();
sdl_init_video();
gbActive = TRUE;
lpDDInterface = &stub_draw;
lpDDSPrimary = &stub_surface;
lpDDSBackBuf = &stub_surface;
lpDDPalette = &stub_palette;
}
/** Copy the palette surface to the main backbuffer */
void sdl_update_entire_surface()
{
assert(sdl_surface && sdl_pal_surface);
SDL_Rect src_rect = {64, 160, 640, 480};
SDL_CHECK(SDL_BlitSurface(sdl_pal_surface, &src_rect, sdl_surface, NULL));
}
void sdl_present_surface()
{
assert(!SDL_MUSTLOCK(sdl_surface));
SDL_CHECK(SDL_UpdateTexture(sdl_render_texture, NULL, sdl_surface->pixels, sdl_surface->pitch));
SDL_CHECK(SDL_RenderCopy(sdl_renderer, sdl_render_texture, NULL, NULL));
SDL_RenderPresent(sdl_renderer);
surface_dirty = false;
}
void __cdecl lock_buf_priv()
{
const int pitch = 640 + 64 + 64;
if (!gpBuffer) {
gpBuffer = (Screen *)malloc(sizeof(Screen));
gpBufEnd += (unsigned int)gpBuffer;
sdl_pal_surface = SDL_CreateRGBSurfaceFrom(gpBuffer, pitch, 160 + 480 + 16, 8, pitch, 0, 0, 0, 0);
assert(sdl_pal_surface);
SDL_CHECK(SDL_SetSurfacePalette(sdl_pal_surface, sdl_palette));
}
}
void __cdecl unlock_buf_priv()
{
gpBufEnd -= (unsigned int)gpBufEnd;
if (!surface_dirty) {
return;
}
sdl_present_surface();
}
void __cdecl dx_reinit()
{
UNIMPLEMENTED();
}
//
// Storm functions
//
BOOL STORMAPI SDrawUpdatePalette(unsigned int firstentry, unsigned int numentries, PALETTEENTRY *pPalEntries, int a4)
{
DUMMY_PRINT("first: %d num: %d", firstentry, numentries);
assert(firstentry == 0);
assert(numentries == 256);
SDL_Color colors[256];
for (int i = firstentry; i < numentries; i++) {
SDL_Color *c = &colors[i];
PALETTEENTRY *p = &pPalEntries[i];
c->r = p->peRed;
c->g = p->peGreen;
c->b = p->peBlue;
c->a = SDL_ALPHA_OPAQUE;
}
assert(sdl_palette);
SDL_CHECK(SDL_SetPaletteColors(sdl_palette, colors, firstentry, numentries));
if (sdl_pal_surface) {
sdl_update_entire_surface();
sdl_present_surface();
}
return TRUE;
}
//
// Windows API functions
//
WINBOOL WINAPI SetCursorPos(int X, int Y)
{
DUMMY();
assert(sdl_window);
SDL_WarpMouseInWindow(sdl_window, X, Y);
return TRUE;
}
int WINAPI ShowCursor(WINBOOL bShow)
{
DUMMY_PRINT("%d", bShow);
if (sdl_window) {
SDL_ShowCursor(bShow ? SDL_ENABLE : SDL_DISABLE);
}
return bShow;
}
WINBOOL WINAPI TextOutA(HDC hdc, int x, int y, LPCSTR lpString, int c)
{
DUMMY_ONCE();
assert(sdl_window);
SDL_SetWindowTitle(sdl_window, lpString);
return TRUE;
}

10
Stub/dx_stub.h

@ -0,0 +1,10 @@
#pragma once
#include <SDL2/SDL.h>
extern SDL_Window *sdl_window;
extern SDL_Renderer *sdl_renderer;
extern SDL_Texture *sdl_render_texture;
extern SDL_Surface *sdl_surface;
void sdl_present_surface();

10
Stub/fault.cpp

@ -0,0 +1,10 @@
#include "../types.h"
#include "stubs.h"
LPTOP_LEVEL_EXCEPTION_FILTER __cdecl exception_get_filter()
{
DUMMY();
return NULL;
}

96
Stub/init.cpp

@ -0,0 +1,96 @@
#include <dirent.h>
#include <string>
#include "../types.h"
#include "stubs.h"
#ifndef NO_GLOBALS
void *diabdat_mpq;
void *patch_rt_mpq;
_SNETVERSIONDATA fileinfo;
WNDPROC CurrentProc;
int gbActive;
#endif
char gszVersionNumber[260];
char gszProductName[260];
/**
* Case insensitive search for a file name in a directory.
* @return Empty string when not found.
*/
static std::string find_file_in_directory(const char *dirpath, const char *file)
{
DIR *dir = opendir(dirpath);
if (!dir) {
return "";
}
struct dirent *entry;
std::string result;
while ((entry = readdir(dir)) != NULL) {
if (strcasecmp(entry->d_name, file) == 0) {
result = std::string(dirpath) + "/" + entry->d_name;
break;
}
}
closedir(dir);
return result;
}
static std::string find_file_in_std_directories(const char *file)
{
for (auto dir : {".", "..", "../.."}) {
auto path = find_file_in_directory(dir, file);
if (!path.empty()) {
return path;
}
}
TermMsg("Required file %s not found", file);
}
void __fastcall init_create_window(int nCmdShow)
{
DUMMY();
init_get_file_info();
// pfile_init_save_directory();
dx_init(NULL);
snd_init(NULL);
init_archives();
}
LRESULT __stdcall MainWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
UNIMPLEMENTED();
}
WNDPROC __fastcall SetWindowProc(WNDPROC NewProc)
{
WNDPROC OldProc = CurrentProc;
CurrentProc = NewProc;
return OldProc;
}
void __cdecl init_archives()
{
DUMMY();
SFileOpenArchive(find_file_in_std_directories("diabdat.mpq").c_str(), 1000, 0, &diabdat_mpq);
assert(diabdat_mpq);
SFileOpenArchive(find_file_in_std_directories("patch_rt.mpq").c_str(), 1000, 0, &patch_rt_mpq);
assert(patch_rt_mpq);
}
void __cdecl init_get_file_info()
{
strcpy(gszVersionNumber, "0.1");
strcpy(gszProductName, "devil-test");
}

22
Stub/main.cpp

@ -0,0 +1,22 @@
#include <string>
#include "../types.h"
#include "stubs.h"
static std::string build_cmdline(int argc, char **argv)
{
std::string str;
for (int i = 1; i < argc; i++) {
if (i != 1) {
str += ' ';
}
str += argv[i];
}
return str;
}
int main(int argc, char **argv)
{
auto cmdline = build_cmdline(argc, argv);
return WinMain(NULL, NULL, cmdline.c_str(), 0);
}

12
Stub/main_harness.cpp

@ -0,0 +1,12 @@
#include "../types.h"
#include "Absolute/absolute.h"
#include "stubs.h"
#include <stddef.h>
int main(int argc, char **argv)
{
init_absolute();
d_WinMain(NULL, NULL, "", 0);
}

72
Stub/main_test.cpp

@ -0,0 +1,72 @@
#include "../types.h"
#include "stubs.h"
#include <stddef.h>
extern "C" const char *__asan_default_options()
{
return "halt_on_error=0:print_legend=0";
}
static void init()
{
init_archives();
encrypt_init_lookup_table();
diablo_init_screen();
InitLightTable();
gdwNormalMsgSize = 512;
}
static void test_levelgen()
{
init();
SetRndSeed(123);
currlevel = 2;
leveltype = DTYPE_CATACOMBS;
// DRLG_Init_Globals();
// LoadLvlGFX();
// CreateLevel(0);
// LoadGameLevel(TRUE, 0);
}
static void test_newgame()
{
init();
start_game(WM_DIABNEWGAME);
}
int main(int argc, char **argv)
{
//#define O(f) fprintf(stderr, "offsetof(%s) = %d\n", #f, offsetof(PlayerStruct, f))
//
// O(_pRSplType);
// O(_pSBkSplType);
// O(_pSplLvl);
// O(_pMemSpells64);
// O(_pAblSpells64);
// O(_pSpellFlags);
// O(_pClass);
// O(_pVar8);
// O(_pIBonusDamMod);
// O(_pISpells64);
// O(_pBData);
//
// printf("s %d\n", sizeof(UINT64));
// test_levelgen();
// test_newgame();
WinMain(NULL, NULL, argc > 1 ? argv[1] : (char*)"", 0);
eprintf("Done!\n");
return 0;
}

294
Stub/miniwin.cpp

@ -0,0 +1,294 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "miniwin.h"
#include "stubs.h"
DWORD last_error;
DWORD WINAPI GetLastError(VOID)
{
return last_error;
}
VOID WINAPI SetLastError(DWORD dwErrCode)
{
last_error = dwErrCode;
}
char __cdecl *_strlwr(char *str)
{
for (char *p = str; *p; ++p) {
*p = tolower(*p);
}
return str;
}
int WINAPIV wsprintfA(LPSTR dest, LPCSTR format, ...)
{
va_list args;
va_start(args, format);
return vsprintf(dest, format, args);
}
int __cdecl _strcmpi(const char *_Str1, const char *_Str2)
{
return strcasecmp(_Str1, _Str2);
}
char *__cdecl _itoa(int _Value, char *_Dest, int _Radix)
{
UNIMPLEMENTED();
}
DWORD WINAPI GetTickCount(VOID)
{
struct timespec now;
if (clock_gettime(CLOCK_MONOTONIC, &now))
return 0;
return now.tv_sec * 1000.0 + now.tv_nsec / 1000000.0;
}
VOID WINAPI Sleep(DWORD dwMilliseconds)
{
usleep(dwMilliseconds * 1000);
}
HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI FindClose(HANDLE hFindFile)
{
UNIMPLEMENTED();
}
UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters)
{
UNIMPLEMENTED();
}
DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
{
DUMMY();
assert(nSize >= 16);
const char *name = ".\\diablo.exe";
strncpy(lpFilename, name, nSize);
return strlen(name);
}
WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, WINBOOL bFailIfExists)
{
UNIMPLEMENTED();
}
HFILE WINAPI OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle)
{
UNIMPLEMENTED();
}
VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
{
UNIMPLEMENTED();
}
VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
{
DUMMY_ONCE();
}
VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
{
DUMMY_ONCE();
}
VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
{
UNIMPLEMENTED();
}
DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
{
UNIMPLEMENTED();
}
HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset, WINBOOL bInitialState,
LPCSTR lpName)
{
DUMMY_PRINT("%s", nullstr(lpName));
return NULL;
}
HWND WINAPI SetCapture(HWND hWnd)
{
DUMMY_ONCE();
return hWnd;
}
WINBOOL WINAPI ReleaseCapture(VOID)
{
DUMMY_ONCE();
return TRUE;
}
WINBOOL WINAPI DestroyWindow(HWND hWnd)
{
UNIMPLEMENTED();
}
HWND WINAPI GetLastActivePopup(HWND hWnd)
{
UNIMPLEMENTED();
}
HWND WINAPI GetTopWindow(HWND hWnd)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI SetForegroundWindow(HWND hWnd)
{
UNIMPLEMENTED();
}
HWND WINAPI SetFocus(HWND hWnd)
{
UNIMPLEMENTED();
}
HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName)
{
DUMMY_PRINT("class: %s window: %s", nullstr(lpClassName), nullstr(lpWindowName));
return NULL;
}
HANDLE WINAPI GetCurrentThread(VOID)
{
DUMMY_ONCE();
return NULL;
}
DWORD WINAPI GetCurrentThreadId(VOID)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority)
{
DUMMY_ONCE();
return TRUE;
}
VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo)
{
DUMMY();
memset(lpSystemInfo, 0, sizeof(*lpSystemInfo));
lpSystemInfo->dwPageSize = 4096;
}
HDC WINAPI GetDC(HWND hWnd)
{
UNIMPLEMENTED();
}
int WINAPI ReleaseDC(HWND hWnd, HDC hDC)
{
UNIMPLEMENTED();
}
int WINAPI GetDeviceCaps(HDC hdc, int index)
{
UNIMPLEMENTED();
}
UINT WINAPI GetSystemPaletteEntries(HDC hdc, UINT iStart, UINT cEntries, LPPALETTEENTRY pPalEntries)
{
UNIMPLEMENTED();
}
uintptr_t __cdecl _beginthreadex(void *_Security, unsigned _StackSize, unsigned(__stdcall *_StartAddress)(void *),
void *_ArgList, unsigned _InitFlag, unsigned *_ThrdAddr)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags,
LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation)
{
UNIMPLEMENTED();
}
VOID WINAPI ExitProcess(UINT uExitCode)
{
UNIMPLEMENTED();
}
DWORD WINAPI GetCurrentProcessId(VOID)
{
UNIMPLEMENTED();
}
HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName)
{
DUMMY();
assert(hFile == (HANDLE)-1);
return NULL;
}
LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap)
{
UNIMPLEMENTED();
}
WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress)
{
UNIMPLEMENTED();
}
DWORD WINAPI WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds)
{
UNIMPLEMENTED();
}
HWND WINAPI GetForegroundWindow(VOID)
{
UNIMPLEMENTED();
}
HWND WINAPI GetWindow(HWND hWnd, UINT uCmd)
{
UNIMPLEMENTED();
}
DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId)
{
UNIMPLEMENTED();
}
DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString,
DWORD nSize, LPCSTR lpFileName)
{
UNIMPLEMENTED();
}

557
Stub/miniwin.h

@ -0,0 +1,557 @@
#pragma once
#ifdef NO_GLOBALS
#define STATIC extern
#else
#define STATIC static
#endif
#include <ctype.h>
#include <math.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
// For _rotr()
#include <x86intrin.h>
// Constants
#define CONST const
#define TRUE true
#define FALSE false
#define NO_ERROR 0
// Calling conventions
#define __cdecl __attribute__((cdecl))
#define __fastcall __attribute__((fastcall))
#define __stdcall __attribute__((stdcall))
#define CALLBACK __stdcall
#define WINAPI __stdcall
#define WINAPIV __cdecl
#define ALIGNED(n) __attribute__((aligned(n)))
// Basic types
#define __int8 char
#define __int16 short
#define __int32 int
#define __int64 long long ALIGNED(8)
#define VOID void
typedef char CHAR;
typedef uint16_t SHORT;
typedef int32_t LONG;
typedef LONG *PLONG;
typedef unsigned long ULONG;
typedef ULONG *PULONG;
typedef unsigned short USHORT;
typedef USHORT *PUSHORT;
typedef unsigned char UCHAR;
typedef UCHAR *PUCHAR;
typedef char *PSZ;
typedef unsigned long DWORD;
typedef int BOOL, WINBOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef float FLOAT;
typedef FLOAT *PFLOAT;
typedef BOOL *LPBOOL;
typedef BYTE *LPBYTE;
typedef int *LPINT;
typedef WORD *LPWORD;
typedef long *LPLONG;
typedef DWORD *LPDWORD;
typedef void *LPVOID;
typedef CONST void *LPCVOID;
typedef int INT;
typedef unsigned int UINT;
typedef unsigned int *PUINT;
// GCC qword alignment is 4, MSVC is 8, work around by introducing a more aligned type
typedef long long INT64 ALIGNED(8);
typedef unsigned long long UINT64 ALIGNED(8);
typedef int INT_PTR, *PINT_PTR;
typedef unsigned int UINT_PTR, *PUINT_PTR;
typedef int32_t LONG_PTR, *PLONG_PTR;
typedef uint32_t ULONG_PTR, *PULONG_PTR;
typedef ULONG_PTR SIZE_T;
typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
typedef CHAR *LPSTR;
typedef CONST CHAR *LPCSTR;
typedef UINT_PTR WPARAM;
typedef LONG_PTR LPARAM;
typedef LONG_PTR LRESULT;
//
// Handles
//
typedef void *HANDLE;
#define INVALID_HANDLE ((HANDLE)-1)
typedef HANDLE HWND, HGDIOBJ, HMODULE, HDC, HRGN, HINSTANCE, HPALETTE, HFILE, HCURSOR;
typedef LONG LCID;
typedef DWORD COLORREF;
typedef LONG HRESULT;
typedef LRESULT(CALLBACK *WNDPROC)(HWND, UINT, WPARAM, LPARAM);
//
// Intrinsics
//
#define LOBYTE(w) ((BYTE)(((DWORD_PTR)(w)) & 0xff))
#define HIBYTE(w) ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
#define HIWORD(l) ((WORD)((((DWORD_PTR)(l)) >> 16) & 0xffff))
#define InterlockedIncrement(x) __sync_add_and_fetch(x, 1)
typedef struct waveformat_tag {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
} WAVEFORMAT, *PWAVEFORMAT, *LPWAVEFORMAT;
typedef struct pcmwaveformat_tag {
WAVEFORMAT wf;
WORD wBitsPerSample;
} PCMWAVEFORMAT, *PPCMWAVEFORMAT, *LPPCMWAVEFORMAT;
typedef struct tWAVEFORMATEX {
WORD wFormatTag;
WORD nChannels;
DWORD nSamplesPerSec;
DWORD nAvgBytesPerSec;
WORD nBlockAlign;
WORD wBitsPerSample;
WORD cbSize;
} WAVEFORMATEX, *LPWAVEFORMATEX, *LPCWAVEFORMATEX;
typedef struct _FILETIME {
DWORD dwLowDateTime;
DWORD dwHighDateTime;
} FILETIME, *LPFILETIME;
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
typedef RECT *LPRECT;
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT;
typedef struct tagSIZE {
LONG cx;
LONG cy;
} SIZE;
typedef struct tagVS_FIXEDFILEINFO {
DWORD dwSignature;
DWORD dwStrucVersion;
DWORD dwFileVersionMS;
DWORD dwFileVersionLS;
DWORD dwProductVersionMS;
DWORD dwProductVersionLS;
DWORD dwFileFlagsMask;
DWORD dwFileFlags;
DWORD dwFileOS;
DWORD dwFileType;
DWORD dwFileSubtype;
DWORD dwFileDateMS;
DWORD dwFileDateLS;
} VS_FIXEDFILEINFO;
typedef struct tagMSG {
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG, *LPMSG;
//
// COM
//
#define DECLARE_INTERFACE_(name, base) struct name : public base
#define THIS_
#define THIS
#define PURE = 0
#define STDMETHOD(name) STDMETHOD_(HRESULT, name)
#define STDMETHOD_(type, name) virtual WINAPI type name
typedef void *REFIID;
struct IUnknown {
// clang-format off
STDMETHOD(QueryInterface)(THIS_ REFIID, LPVOID *) PURE;
STDMETHOD_(ULONG, AddRef)(THIS) PURE;
STDMETHOD_(ULONG, Release)(THIS) PURE;
// clang-format on
};
#define MAKE_HRESULT(sev, fac, code) ((HRESULT)(((uint32_t)(sev) << 31) | ((uint32_t)(fac) << 16) | ((uint32_t)(code))))
#define E_FAIL ((HRESULT)0x80004005L)
#define S_OK ((HRESULT)0)
//
// Everything else
//
typedef struct tagPALETTEENTRY {
BYTE peRed;
BYTE peGreen;
BYTE peBlue;
BYTE peFlags;
} PALETTEENTRY, *PPALETTEENTRY, *LPPALETTEENTRY;
typedef void *LPTOP_LEVEL_EXCEPTION_FILTER, *PEXCEPTION_POINTERS;
typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId;
struct {
WORD wProcessorArchitecture;
WORD wReserved;
};
};
DWORD dwPageSize;
LPVOID lpMinimumApplicationAddress;
LPVOID lpMaximumApplicationAddress;
DWORD_PTR dwActiveProcessorMask;
DWORD dwNumberOfProcessors;
DWORD dwProcessorType;
DWORD dwAllocationGranularity;
WORD wProcessorLevel;
WORD wProcessorRevision;
} SYSTEM_INFO, *LPSYSTEM_INFO;
typedef void *LPSECURITY_ATTRIBUTES;
#define ERROR_ALREADY_EXISTS 183
typedef struct _LIST_ENTRY {
struct _LIST_ENTRY *Flink;
struct _LIST_ENTRY *Blink;
} LIST_ENTRY, *PLIST_ENTRY;
typedef struct _RTL_CRITICAL_SECTION_DEBUG {
WORD Type;
WORD CreatorBackTraceIndex;
struct _RTL_CRITICAL_SECTION *CriticalSection;
LIST_ENTRY ProcessLocksList;
DWORD EntryCount;
DWORD ContentionCount;
DWORD Flags;
WORD CreatorBackTraceIndexHigh;
WORD SpareWORD;
} RTL_CRITICAL_SECTION_DEBUG, *PRTL_CRITICAL_SECTION_DEBUG;
typedef struct {
PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
LONG LockCount;
LONG RecursionCount;
HANDLE OwningThread;
HANDLE LockSemaphore;
ULONG_PTR SpinCount;
} CRITICAL_SECTION, *LPCRITICAL_SECTION;
VOID WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
VOID WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
VOID WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
VOID WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds);
DWORD WINAPI GetTickCount(VOID);
DWORD WINAPI GetLastError(VOID);
VOID WINAPI SetLastError(DWORD dwErrCode);
WINBOOL WINAPI CloseHandle(HANDLE hObject);
HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, WINBOOL bManualReset, WINBOOL bInitialState,
LPCSTR lpName);
#define CreateEvent CreateEventA
WINBOOL WINAPI SetCursorPos(int X, int Y);
int WINAPI ShowCursor(WINBOOL bShow);
HWND WINAPI SetCapture(HWND hWnd);
WINBOOL WINAPI ReleaseCapture(VOID);
SHORT WINAPI GetAsyncKeyState(int vKey);
#define PM_NOREMOVE 0x0000
#define PM_REMOVE 0x0001
#define WM_QUIT 0x0012
WINBOOL WINAPI PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg);
#define PeekMessage PeekMessageA
WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg);
LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg);
#define DispatchMessage DispatchMessageA
WINBOOL WINAPI PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
#define PostMessage PostMessageA
WINBOOL WINAPI DestroyWindow(HWND hWnd);
HWND WINAPI GetLastActivePopup(HWND hWnd);
HWND WINAPI GetTopWindow(HWND hWnd);
WINBOOL WINAPI SetForegroundWindow(HWND hWnd);
HWND WINAPI SetFocus(HWND hWnd);
HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
#define FindWindow FindWindowA
#define THREAD_BASE_PRIORITY_MAX 2
#define THREAD_PRIORITY_NORMAL 0
#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX
#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST - 1)
HANDLE WINAPI GetCurrentThread(VOID);
DWORD WINAPI GetCurrentThreadId(VOID);
WINBOOL WINAPI SetThreadPriority(HANDLE hThread, int nPriority);
VOID WINAPI Sleep(DWORD dwMilliseconds);
VOID WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
HDC WINAPI GetDC(HWND hWnd);
int WINAPI ReleaseDC(HWND hWnd, HDC hDC);
WINBOOL WINAPI TextOutA(HDC hdc, int x, int y, LPCSTR lpString, int c);
#define TextOut TextOutA
#define NUMRESERVED 106
int WINAPI GetDeviceCaps(HDC hdc, int index);
UINT WINAPI GetSystemPaletteEntries(HDC hdc, UINT iStart, UINT cEntries, LPPALETTEENTRY pPalEntries);
uintptr_t __cdecl _beginthreadex(void *_Security, unsigned _StackSize, unsigned(__stdcall *_StartAddress)(void *),
void *_ArgList, unsigned _InitFlag, unsigned *_ThrdAddr);
int WINAPIV wsprintfA(LPSTR, LPCSTR, ...);
#define wsprintf wsprintfA
int __cdecl _strcmpi(const char *_Str1, const char *_Str2);
char *__cdecl _itoa(int _Value, char *_Dest, int _Radix);
char *__cdecl _strlwr(char *str);
//
// File I/O
//
#define FILE_BEGIN 0
#define FILE_CURRENT 1
#define FILE_FLAG_WRITE_THROUGH 0x80000000
#define CREATE_ALWAYS 2
#define GENERIC_READ 0x80000000L
#define GENERIC_WRITE 0x40000000L
#define OPEN_EXISTING 3
#define ERROR_FILE_NOT_FOUND 2
#define FILE_ATTRIBUTE_HIDDEN 0x00000002
#define FILE_ATTRIBUTE_SYSTEM 0x00000004
struct _WIN32_FIND_DATAA {
FILETIME ftCreationTime;
FILETIME ftLastWriteTime;
};
typedef struct _WIN32_FIND_DATAA *LPWIN32_FIND_DATAA;
typedef void *LPOVERLAPPED;
#define OFS_MAXPATHNAME 128
typedef struct _OFSTRUCT {
BYTE cBytes;
BYTE fFixedDisk;
WORD nErrCode;
WORD Reserved1;
WORD Reserved2;
CHAR szPathName[OFS_MAXPATHNAME];
} OFSTRUCT, *LPOFSTRUCT, *POFSTRUCT;
#define SEC_COMMIT 0x8000000
#define PAGE_READWRITE 0x04
#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS
#define SECTION_QUERY 0x0001
#define SECTION_MAP_WRITE 0x0002
#define SECTION_MAP_READ 0x0004
#define SECTION_MAP_EXECUTE 0x0008
#define SECTION_EXTEND_SIZE 0x0010
#define SECTION_MAP_EXECUTE_EXPLICIT 0x0020
#define STANDARD_RIGHTS_REQUIRED 0x000F0000
#define SECTION_ALL_ACCESS \
(STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_WRITE | SECTION_MAP_READ | SECTION_MAP_EXECUTE | \
SECTION_EXTEND_SIZE)
#define CREATE_NEW_PROCESS_GROUP 0x200
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
typedef void *LPSTARTUPINFOA;
WINBOOL WINAPI CreateProcessA(LPCSTR lpApplicationName, LPSTR lpCommandLine, LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes, WINBOOL bInheritHandles, DWORD dwCreationFlags,
LPVOID lpEnvironment, LPCSTR lpCurrentDirectory, LPSTARTUPINFOA lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation);
#define CreateProcess CreateProcessA
VOID WINAPI ExitProcess(UINT uExitCode);
DWORD WINAPI GetCurrentProcessId(VOID);
HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappingAttributes, DWORD flProtect,
DWORD dwMaximumSizeHigh, DWORD dwMaximumSizeLow, LPCSTR lpName);
#define CreateFileMapping CreateFileMappingA
LPVOID WINAPI MapViewOfFile(HANDLE hFileMappingObject, DWORD dwDesiredAccess, DWORD dwFileOffsetHigh,
DWORD dwFileOffsetLow, SIZE_T dwNumberOfBytesToMap);
WINBOOL WINAPI UnmapViewOfFile(LPCVOID lpBaseAddress);
DWORD WINAPI WaitForInputIdle(HANDLE hProcess, DWORD dwMilliseconds);
HWND WINAPI GetForegroundWindow(VOID);
HWND WINAPI GetWindow(HWND hWnd, UINT uCmd);
DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, LPDWORD lpdwProcessId);
DWORD WINAPI GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPSTR lpReturnedString,
DWORD nSize, LPCSTR lpFileName);
#define GetPrivateProfileString GetPrivateProfileStringA
WINBOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped);
DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod);
WINBOOL WINAPI SetEndOfFile(HANDLE hFile);
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName);
#define GetFileAttributes GetFileAttributesA
WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes);
#define SetFileAttributes SetFileAttributesA
HANDLE WINAPI FindFirstFileA(LPCSTR lpFileName, LPWIN32_FIND_DATAA lpFindFileData);
#define FindFirstFile FindFirstFileA
WINBOOL WINAPI FindClose(HANDLE hFindFile);
HANDLE WINAPI CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile);
#define CreateFile CreateFileA
WINBOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped);
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh);
UINT WINAPI GetWindowsDirectoryA(LPSTR lpBuffer, UINT uSize);
#define GetWindowsDirectory GetWindowsDirectoryA
WINBOOL WINAPI GetDiskFreeSpaceA(LPCSTR lpRootPathName, LPDWORD lpSectorsPerCluster, LPDWORD lpBytesPerSector,
LPDWORD lpNumberOfFreeClusters, LPDWORD lpTotalNumberOfClusters);
#define GetDiskFreeSpace GetDiskFreeSpaceA
DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize);
#define GetModuleFileName GetModuleFileNameA
WINBOOL WINAPI GetComputerNameA(LPSTR lpBuffer, LPDWORD nSize);
#define GetComputerName GetComputerNameA
WINBOOL WINAPI DeleteFileA(LPCSTR lpFileName);
#define DeleteFile DeleteFileA
WINBOOL WINAPI CopyFileA(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, WINBOOL bFailIfExists);
#define CopyFile CopyFileA
HFILE WINAPI OpenFile(LPCSTR lpFileName, LPOFSTRUCT lpReOpenBuff, UINT uStyle);
//
// Events
//
#define WM_MOUSEFIRST 0x0200
#define WM_MOUSEMOVE 0x0200
#define WM_LBUTTONDOWN 0x0201
#define WM_LBUTTONUP 0x0202
#define WM_RBUTTONDOWN 0x0204
#define WM_RBUTTONUP 0x0205
#define WM_KEYFIRST 0x0100
#define WM_KEYDOWN 0x0100
#define WM_KEYUP 0x0101
#define WM_SYSKEYDOWN 0x0104
#define WM_SYSCOMMAND 0x0112
#define WM_CHAR 0x0102
#define WM_CAPTURECHANGED 0x0215
#define SC_CLOSE 0xF060
#define VK_RETURN 0x0D
#define VK_BACK 0x08
#define VK_SHIFT 0x10
#define VK_ESCAPE 0x1B
#define VK_SPACE 0x20
#define VK_LEFT 0x25
#define VK_UP 0x26
#define VK_RIGHT 0x27
#define VK_DOWN 0x28
#define VK_F1 0x70
#define VK_F2 0x71
#define VK_F3 0x72
#define VK_F4 0x73
#define VK_F5 0x74
#define VK_F6 0x75
#define VK_F7 0x76
#define VK_F8 0x77
#define VK_F9 0x78
#define VK_F10 0x79
#define VK_F11 0x7A
#define VK_F12 0x7B
#define VK_TAB 0x09
#define VK_PAUSE 0x13
#define VK_PRIOR 0x21
#define VK_NEXT 0x22
#define VK_SNAPSHOT 0x2C
#define VK_OEM_1 0xBA
#define VK_OEM_PLUS 0xBB
#define VK_OEM_COMMA 0xBC
#define VK_OEM_MINUS 0xBD
#define VK_OEM_PERIOD 0xBE
#define VK_OEM_2 0xBF
#define VK_OEM_3 0xC0
#define VK_OEM_4 0xDB
#define VK_OEM_5 0xDC
#define VK_OEM_6 0xDD
#define VK_OEM_7 0xDE
//#define VK_OEM_8 0xDF
//#define VK_OEM_102 0xE2
//
// Total fakes
//
typedef struct {
} SOCKADDR, GUID;
typedef struct {
DWORD cb;
} STARTUPINFOA;
//
// MSCVRT emulation
//
int rand_miniwin(void);
void srand_miniwin(unsigned int seed);
#include "miniwin_ddraw.h"
#include "miniwin_dsound.h"

196
Stub/miniwin_ddraw.h

@ -0,0 +1,196 @@
#pragma once
#include "miniwin.h"
typedef struct _DDCOLORKEY {
DWORD dwColorSpaceLowValue;
DWORD dwColorSpaceHighValue;
} DDCOLORKEY;
typedef DDCOLORKEY *LPDDCOLORKEY;
typedef struct _DDSCAPS {
DWORD dwCaps;
} DDSCAPS, *LPDDSCAPS;
typedef struct _DDPIXELFORMAT {
DWORD dwSize;
DWORD dwFlags;
DWORD dwFourCC;
union {
DWORD dwRGBBitCount;
DWORD dwYUVBitCount;
DWORD dwZBufferBitDepth;
DWORD dwAlphaBitDepth;
};
union {
DWORD dwRBitMask;
DWORD dwYBitMask;
};
union {
DWORD dwGBitMask;
DWORD dwUBitMask;
};
union {
DWORD dwBBitMask;
DWORD dwVBitMask;
};
union {
DWORD dwRGBAlphaBitMask;
DWORD dwYUVAlphaBitMask;
DWORD dwRGBZBitMask;
DWORD dwYUVZBitMask;
};
} DDPIXELFORMAT, *LPDDPIXELFORMAT;
typedef struct _DDSURFACEDESC {
DWORD dwSize;
DWORD dwFlags;
DWORD dwHeight;
DWORD dwWidth;
union {
LONG lPitch;
DWORD dwLinearSize;
};
DWORD dwBackBufferCount;
union {
DWORD dwMipMapCount;
DWORD dwZBufferBitDepth;
DWORD dwRefreshRate;
};
DWORD dwAlphaBitDepth;
DWORD dwReserved;
LPVOID lpSurface;
DDCOLORKEY ddckCKDestOverlay;
DDCOLORKEY ddckCKDestBlt;
DDCOLORKEY ddckCKSrcOverlay;
DDCOLORKEY ddckCKSrcBlt;
DDPIXELFORMAT ddpfPixelFormat;
DDSCAPS ddsCaps;
} DDSURFACEDESC, *LPDDSURFACEDESC;
#define _FACDD 0x876
#define MAKE_DDHRESULT(code) MAKE_HRESULT(1, _FACDD, code)
#define DDERR_SURFACELOST MAKE_DDHRESULT(450)
#define DDERR_WASSTILLDRAWING MAKE_DDHRESULT(540)
#define DDERR_SURFACEBUSY MAKE_DDHRESULT(430)
typedef struct IDirectDrawPalette *LPDIRECTDRAWPALETTE;
typedef struct IDirectDrawSurface *LPDIRECTDRAWSURFACE;
typedef struct IDirectDraw *LPDIRECTDRAW;
// No methods are actually used
DECLARE_INTERFACE_(IDirectDrawPalette, IUnknown)
{
// clang-format off
STDMETHOD(GetCaps)(THIS_ LPDWORD lpdwCaps) PURE;
STDMETHOD(GetEntries)(THIS_ DWORD dwFlags, DWORD dwBase, DWORD dwNumEntries, LPPALETTEENTRY lpEntries) PURE;
STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW lpDD, DWORD dwFlags, LPPALETTEENTRY lpDDColorTable) PURE;
STDMETHOD(SetEntries)(THIS_ DWORD dwFlags, DWORD dwStartingEntry, DWORD dwCount, LPPALETTEENTRY lpEntries) PURE;
// clang-format on
};
/*
Actually used methods:
DECLARE_INTERFACE_(IDirectDrawSurface, IUnknown) {
STDMETHOD(GetDC)(THIS_ HDC *);
STDMETHOD(IsLost)(THIS);
STDMETHOD(Lock)(THIS_ LPRECT, LPDDSURFACEDESC, DWORD, HANDLE);
STDMETHOD(ReleaseDC)(THIS_ HDC);
STDMETHOD(Restore)(THIS);
STDMETHOD(Unlock)(THIS_ LPVOID);
STDMETHOD(BltFast)(THIS_ DWORD, DWORD, LPDIRECTDRAWSURFACE, LPRECT, DWORD);
STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE);
};
*/
typedef void *LPDDBLTBATCH, *LPDDBLTFX, *LPDIRECTDRAWCLIPPER, *LPDDENUMSURFACESCALLBACK, *LPDDOVERLAYFX;
DECLARE_INTERFACE_(IDirectDrawSurface, IUnknown)
{
// clang-format off
STDMETHOD(AddAttachedSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDSAttachedSurface) PURE;
STDMETHOD(AddOverlayDirtyRect)(THIS_ LPRECT lpRect) PURE;
STDMETHOD(Blt)(THIS_ LPRECT lpDestRect, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwFlags, LPDDBLTFX lpDDBltFx) PURE;
STDMETHOD(BltBatch)(THIS_ LPDDBLTBATCH lpDDBltBatch, DWORD dwCount, DWORD dwFlags) PURE;
STDMETHOD(BltFast)(THIS_ DWORD dwX, DWORD dwY, LPDIRECTDRAWSURFACE lpDDSrcSurface, LPRECT lpSrcRect, DWORD dwTrans) PURE;
STDMETHOD(DeleteAttachedSurface)(THIS_ DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSAttachedSurface) PURE;
STDMETHOD(EnumAttachedSurfaces)(THIS_ LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) PURE;
STDMETHOD(EnumOverlayZOrders)(THIS_ DWORD dwFlags, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpfnCallback) PURE;
STDMETHOD(Flip)(THIS_ LPDIRECTDRAWSURFACE lpDDSurfaceTargetOverride, DWORD dwFlags) PURE;
STDMETHOD(GetAttachedSurface)(THIS_ LPDDSCAPS lpDDSCaps, LPDIRECTDRAWSURFACE *lplpDDAttachedSurface) PURE;
STDMETHOD(GetBltStatus)(THIS_ DWORD dwFlags) PURE;
STDMETHOD(GetCaps)(THIS_ LPDDSCAPS lpDDSCaps) PURE;
STDMETHOD(GetClipper)(THIS_ LPDIRECTDRAWCLIPPER *lplpDDClipper) PURE;
STDMETHOD(GetColorKey)(THIS_ DWORD dwFlags, LPDDCOLORKEY lpDDColorKey) PURE;
STDMETHOD(GetDC)(THIS_ HDC *lphDC) PURE;
STDMETHOD(GetFlipStatus)(THIS_ DWORD dwFlags) PURE;
STDMETHOD(GetOverlayPosition)(THIS_ LPLONG lplX, LPLONG lplY) PURE;
STDMETHOD(GetPalette)(THIS_ LPDIRECTDRAWPALETTE *lplpDDPalette) PURE;
STDMETHOD(GetPixelFormat)(THIS_ LPDDPIXELFORMAT lpDDPixelFormat) PURE;
STDMETHOD(GetSurfaceDesc)(THIS_ LPDDSURFACEDESC lpDDSurfaceDesc) PURE;
STDMETHOD(Initialize)(THIS_ LPDIRECTDRAW lpDD, LPDDSURFACEDESC lpDDSurfaceDesc) PURE;
STDMETHOD(IsLost)(THIS) PURE;
STDMETHOD(Lock)(THIS_ LPRECT lpDestRect, LPDDSURFACEDESC lpDDSurfaceDesc, DWORD dwFlags, HANDLE hEvent) PURE;
STDMETHOD(ReleaseDC)(THIS_ HDC hDC) PURE;
STDMETHOD(Restore)(THIS) PURE;
STDMETHOD(SetClipper)(THIS_ LPDIRECTDRAWCLIPPER lpDDClipper) PURE;
STDMETHOD(SetColorKey)(THIS_ DWORD dwFlags, LPDDCOLORKEY lpDDColorKey) PURE;
STDMETHOD(SetOverlayPosition)(THIS_ LONG lX, LONG lY) PURE;
STDMETHOD(SetPalette)(THIS_ LPDIRECTDRAWPALETTE lpDDPalette) PURE;
STDMETHOD(Unlock)(THIS_ LPVOID lpSurfaceData) PURE;
STDMETHOD(UpdateOverlay)(THIS_ LPRECT lpSrcRect, LPDIRECTDRAWSURFACE lpDDDestSurface, LPRECT lpDestRect, DWORD dwFlags, LPDDOVERLAYFX lpDDOverlayFx) PURE;
STDMETHOD(UpdateOverlayDisplay)(THIS_ DWORD dwFlags) PURE;
STDMETHOD(UpdateOverlayZOrder)(THIS_ DWORD dwFlags, LPDIRECTDRAWSURFACE lpDDSReference) PURE;
// clang-format off
};
#define DDBLTFAST_WAIT 0x00000010
#define DDLOCK_WRITEONLY 0x00000020L
#define DDLOCK_WAIT 0x00000001L
#define DDPCAPS_ALLOW256 0x00000040l
#define DDPCAPS_8BIT 0x00000004l
#define PC_RESERVED 0x01
#define PC_NOCOLLAPSE 0x04
#define DDWAITVB_BLOCKBEGIN 0x00000001l
/*
Actually used methods:
DECLARE_INTERFACE_(IDirectDraw, IUnknown) {
STDMETHOD(CreatePalette)(THIS_ DWORD, LPPALETTEENTRY, LPDIRECTDRAWPALETTE *, IUnknown *);
STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD, HANDLE);
};
*/
typedef void *LPDDENUMMODESCALLBACK, *LPDDCAPS;
DECLARE_INTERFACE_(IDirectDraw,IUnknown)
{
// clang-format off
STDMETHOD(Compact)(THIS) PURE;
STDMETHOD(CreateClipper)(THIS_ DWORD dwFlags, LPDIRECTDRAWCLIPPER *lplpDDClipper, IUnknown *pUnkOuter) PURE;
STDMETHOD(CreatePalette)(THIS_ DWORD dwFlags, LPPALETTEENTRY lpColorTable, LPDIRECTDRAWPALETTE *lplpDDPalette, IUnknown *pUnkOuter) PURE;
STDMETHOD(CreateSurface)(THIS_ LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE *lplpDDSurface, IUnknown *pUnkOuter) PURE;
STDMETHOD(DuplicateSurface)(THIS_ LPDIRECTDRAWSURFACE lpDDSurface, LPDIRECTDRAWSURFACE *lplpDupDDSurface) PURE;
STDMETHOD(EnumDisplayModes)(THIS_ DWORD dwFlags, LPDDSURFACEDESC lpDDSurfaceDesc, LPVOID lpContext, LPDDENUMMODESCALLBACK lpEnumModesCallback) PURE;
STDMETHOD(EnumSurfaces)(THIS_ DWORD dwFlags, LPDDSURFACEDESC lpDDSD, LPVOID lpContext, LPDDENUMSURFACESCALLBACK lpEnumSurfacesCallback) PURE;
STDMETHOD(FlipToGDISurface)(THIS) PURE;
STDMETHOD(GetCaps)(THIS_ LPDDCAPS lpDDDriverCaps, LPDDCAPS lpDDHELCaps) PURE;
STDMETHOD(GetDisplayMode)(THIS_ LPDDSURFACEDESC lpDDSurfaceDesc) PURE;
STDMETHOD(GetFourCCCodes)(THIS_ LPDWORD lpNumCodes, LPDWORD lpCodes) PURE;
STDMETHOD(GetGDISurface)(THIS_ LPDIRECTDRAWSURFACE *lplpGDIDDSurface) PURE;
STDMETHOD(GetMonitorFrequency)(THIS_ LPDWORD lpdwFrequency) PURE;
STDMETHOD(GetScanLine)(THIS_ LPDWORD lpdwScanLine) PURE;
STDMETHOD(GetVerticalBlankStatus)(THIS_ BOOL *lpbIsInVB) PURE;
STDMETHOD(Initialize)(THIS_ GUID *lpGUID) PURE;
STDMETHOD(RestoreDisplayMode)(THIS) PURE;
STDMETHOD(SetCooperativeLevel)(THIS_ HWND hWnd, DWORD dwFlags) PURE;
STDMETHOD(SetDisplayMode)(THIS_ DWORD dwWidth, DWORD dwHeight, DWORD dwBPP) PURE;
STDMETHOD(WaitForVerticalBlank)(THIS_ DWORD dwFlags, HANDLE hEvent) PURE;
// clang-format on
};

46
Stub/miniwin_dsound.h

@ -0,0 +1,46 @@
#pragma once
#include "miniwin.h"
typedef void *LPDSBCAPS, *LPDIRECTSOUND, *LPCDSBUFFERDESC;
DECLARE_INTERFACE_(IDirectSoundBuffer, IUnknown)
{
// clang-format off
STDMETHOD(GetCaps)(THIS_ LPDSBCAPS pDSBufferCaps);
STDMETHOD(GetCurrentPosition)(THIS_ LPDWORD pdwCurrentPlayCursor, LPDWORD pdwCurrentWriteCursor);
STDMETHOD(GetFormat)(THIS_ LPWAVEFORMATEX pwfxFormat, DWORD dwSizeAllocated, LPDWORD pdwSizeWritten);
STDMETHOD(GetVolume)(THIS_ LPLONG plVolume);
STDMETHOD(GetPan)(THIS_ LPLONG plPan);
STDMETHOD(GetFrequency)(THIS_ LPDWORD pdwFrequency);
STDMETHOD(GetStatus)(THIS_ LPDWORD pdwStatus);
STDMETHOD(Initialize)(THIS_ LPDIRECTSOUND pDirectSound, LPCDSBUFFERDESC pcDSBufferDesc);
STDMETHOD(Lock)(THIS_ DWORD dwOffset, DWORD dwBytes, LPVOID *ppvAudioPtr1, LPDWORD pdwAudioBytes1,
LPVOID *ppvAudioPtr2, LPDWORD pdwAudioBytes2, DWORD dwFlags);
STDMETHOD(Play)(THIS_ DWORD dwReserved1, DWORD dwPriority, DWORD dwFlags);
STDMETHOD(SetCurrentPosition)(THIS_ DWORD dwNewPosition);
STDMETHOD(SetFormat)(THIS_ LPCWAVEFORMATEX pcfxFormat);
STDMETHOD(SetVolume)(THIS_ LONG lVolume);
STDMETHOD(SetPan)(THIS_ LONG lPan);
STDMETHOD(SetFrequency)(THIS_ DWORD dwFrequency);
STDMETHOD(Stop)(THIS);
STDMETHOD(Unlock)(THIS_ LPVOID pvAudioPtr1, DWORD dwAudioBytes1, LPVOID pvAudioPtr2, DWORD dwAudioBytes2);
STDMETHOD(Restore)(THIS);
// clang-format on
};
typedef void *LPDIRECTSOUNDBUFFER, *LPDSCAPS, *LPUNKNOWN, *LPCGUID;
DECLARE_INTERFACE_(IDirectSound, IUnknown)
{
// clang-format off
STDMETHOD(CreateSoundBuffer)(THIS_ LPCDSBUFFERDESC pcDSBufferDesc, LPDIRECTSOUNDBUFFER *ppDSBuffer, LPUNKNOWN pUnkOuter);
STDMETHOD(GetCaps)(THIS_ LPDSCAPS pDSCaps);
STDMETHOD(DuplicateSoundBuffer)(THIS_ LPDIRECTSOUNDBUFFER pDSBufferOriginal, LPDIRECTSOUNDBUFFER *ppDSBufferDuplicate);
STDMETHOD(SetCooperativeLevel)(THIS_ HWND hwnd, DWORD dwLevel);
STDMETHOD(Compact)(THIS);
STDMETHOD(GetSpeakerConfig)(THIS_ LPDWORD pdwSpeakerConfig);
STDMETHOD(SetSpeakerConfig)(THIS_ DWORD dwSpeakerConfig);
STDMETHOD(Initialize)(THIS_ LPCGUID pcGuidDevice);
// clang-format on
};

141
Stub/miniwin_io.cpp

@ -0,0 +1,141 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include "miniwin.h"
#include "stubs.h"
void TranslateFileName(char *dst, int dstLen, const char *src)
{
for (int i = 0; i < dstLen; i++) {
char c = *src++;
dst[i] = c == '\\' ? '/' : c;
if (!c) {
break;
}
}
}
HANDLE WINAPI CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode,
LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
char name[260];
TranslateFileName(name, sizeof(name), lpFileName);
DUMMY_PRINT("file: %s (%s)", lpFileName, name);
assert(dwDesiredAccess == GENERIC_READ | GENERIC_WRITE);
int flags = O_RDWR;
mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
if (dwCreationDisposition == OPEN_EXISTING) {
// Nothing
} else if (dwCreationDisposition == CREATE_ALWAYS) {
flags |= O_CREAT | O_TRUNC;
} else {
UNIMPLEMENTED();
}
int fd = open(name, flags, mode);
return (HANDLE)fd;
}
WINBOOL WINAPI ReadFile(HANDLE hFile, LPVOID lpBuffer, DWORD nNumberOfBytesToRead, LPDWORD lpNumberOfBytesRead,
LPOVERLAPPED lpOverlapped)
{
DUMMY_ONCE();
assert(!lpOverlapped);
int len = read((int)hFile, lpBuffer, nNumberOfBytesToRead);
assert(len != -1);
*lpNumberOfBytesRead = len;
return TRUE;
}
DWORD WINAPI GetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
{
DUMMY_ONCE();
assert(!lpFileSizeHigh);
struct stat s;
int ret = fstat((int)hFile, &s);
assert(ret == 0);
return s.st_size;
}
WINBOOL WINAPI WriteFile(HANDLE hFile, LPCVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten,
LPOVERLAPPED lpOverlapped)
{
DUMMY_ONCE();
assert(!lpOverlapped);
ssize_t len = write((int)hFile, lpBuffer, nNumberOfBytesToWrite);
if (len == -1) {
*lpNumberOfBytesWritten = 0;
return FALSE;
}
*lpNumberOfBytesWritten = (DWORD)len;
return TRUE;
}
DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistanceToMoveHigh, DWORD dwMoveMethod)
{
DUMMY_ONCE();
assert(!lpDistanceToMoveHigh);
int whence;
if (dwMoveMethod == FILE_BEGIN) {
whence = SEEK_SET;
} else if (dwMoveMethod == FILE_CURRENT) {
whence = SEEK_CUR;
} else {
UNIMPLEMENTED();
}
off_t ret = lseek((int)hFile, lDistanceToMove, whence);
return (DWORD)ret;
}
WINBOOL WINAPI SetEndOfFile(HANDLE hFile)
{
DUMMY_ONCE();
off_t cur = lseek((int)hFile, 0, SEEK_CUR);
assert(cur != -1);
int res = ftruncate((int)hFile, cur);
assert(res == 0);
return TRUE;
}
DWORD WINAPI GetFileAttributesA(LPCSTR lpFileName)
{
char name[260];
TranslateFileName(name, sizeof(name), lpFileName);
DUMMY_PRINT("file: %s (%s)", lpFileName, name);
struct stat s;
int res = stat(name, &s);
if (res == -1) {
SetLastError(ERROR_FILE_NOT_FOUND);
return (DWORD)-1;
}
return 0x80;
}
WINBOOL WINAPI SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes)
{
DUMMY_PRINT("file: %s", lpFileName);
return TRUE;
}
WINBOOL WINAPI CloseHandle(HANDLE hObject)
{
DUMMY();
int ret = close((int)hObject);
assert(ret == 0);
return TRUE;
}

277
Stub/miniwin_msg_sdl.cpp

@ -0,0 +1,277 @@
/** @file
* *
* Windows message handling and keyboard event conversion for SDL.
*/
#include <deque>
#include "miniwin_sdl.h"
#include "../types.h"
#include "stubs.h"
static std::deque<MSG> message_queue;
static int translate_sdl_key(SDL_Keysym key)
{
int sym = key.sym;
switch (sym) {
case SDLK_ESCAPE:
return VK_ESCAPE;
case SDLK_RETURN:
return VK_RETURN;
case SDLK_TAB:
return VK_TAB;
case SDLK_BACKSPACE:
return VK_BACK;
case SDLK_DOWN:
return VK_DOWN;
case SDLK_LEFT:
return VK_LEFT;
case SDLK_RIGHT:
return VK_RIGHT;
case SDLK_UP:
return VK_UP;
case SDLK_PAGEUP:
return VK_PRIOR;
case SDLK_PAGEDOWN:
return VK_NEXT;
case SDLK_PAUSE:
return VK_PAUSE;
case SDLK_SEMICOLON:
return VK_OEM_1;
case SDLK_QUESTION:
return VK_OEM_2;
case SDLK_BACKQUOTE:
return VK_OEM_3;
case SDLK_LEFTBRACKET:
return VK_OEM_4;
case SDLK_BACKSLASH:
return VK_OEM_5;
case SDLK_RIGHTBRACKET:
return VK_OEM_6;
case SDLK_QUOTE:
return VK_OEM_7;
case SDLK_MINUS:
return VK_OEM_MINUS;
case SDLK_PLUS:
return VK_OEM_PLUS;
case SDLK_PERIOD:
return VK_OEM_PERIOD;
case SDLK_COMMA:
return VK_OEM_COMMA;
case SDLK_LSHIFT:
case SDLK_RSHIFT:
// Not handled yet
return -1;
default:
if (sym >= SDLK_a && sym <= SDLK_z) {
return 'A' + (sym - SDLK_a);
} else if (sym >= SDLK_0 && sym <= SDLK_9) {
return '0' + (sym - SDLK_0);
} else if (sym >= SDLK_F1 && sym <= SDLK_F12) {
return VK_F1 + (sym - SDLK_F1);
}
DUMMY_PRINT("unknown key: name=%s sym=0x%X scan=%d mod=0x%X", SDL_GetKeyName(sym), sym, key.scancode, key.mod);
return -1;
}
}
WINBOOL WINAPI PeekMessageA(LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax, UINT wRemoveMsg)
{
// DUMMY_PRINT("hwnd: %d", hWnd);
assert(wMsgFilterMin == 0 && wMsgFilterMax == 0);
if (wRemoveMsg == PM_NOREMOVE) {
// XXX: This does not actually fill out lpMsg properly
lpMsg->hwnd = (HWND)-1;
lpMsg->message = 0;
return !message_queue.empty() || SDL_PollEvent(NULL);
} else if (wRemoveMsg == PM_REMOVE) {
if (!message_queue.empty()) {
*lpMsg = message_queue.front();
message_queue.pop_front();
return TRUE;
}
SDL_Event e;
int pending = SDL_PollEvent(&e);
if (!pending) {
return FALSE;
}
lpMsg->hwnd = hWnd;
lpMsg->lParam = 0;
lpMsg->wParam = 0;
switch (e.type) {
case SDL_QUIT: {
lpMsg->message = WM_QUIT;
break;
}
case SDL_KEYDOWN:
case SDL_KEYUP: {
int key = translate_sdl_key(e.key.keysym);
if (key == -1) {
return FALSE;
}
lpMsg->message = e.type == SDL_KEYDOWN ? WM_KEYFIRST : WM_KEYUP;
lpMsg->wParam = (DWORD)key;
// Hack: Encode modifier in lParam for TranslateMessage later
lpMsg->lParam = e.key.keysym.mod << 16;
break;
}
case SDL_MOUSEMOTION: {
lpMsg->message = WM_MOUSEMOVE;
lpMsg->lParam = (e.motion.y << 16) | (e.motion.x & 0xFFFF);
break;
}
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: {
int button = e.button.button;
if (button != SDL_BUTTON_LEFT && button != SDL_BUTTON_RIGHT) {
return FALSE;
}
bool left = button == SDL_BUTTON_LEFT;
lpMsg->message = e.type == SDL_MOUSEBUTTONDOWN ? (left ? WM_LBUTTONDOWN : WM_RBUTTONDOWN)
: (left ? WM_LBUTTONUP : WM_RBUTTONUP);
lpMsg->lParam = (e.button.y << 16) | (e.button.x & 0xFFFF);
break;
}
case SDL_TEXTINPUT:
case SDL_WINDOWEVENT: {
return FALSE;
}
default: {
DUMMY_PRINT("unknown SDL message 0x%X", e.type);
return FALSE;
}
}
return TRUE;
}
UNIMPLEMENTED();
}
WINBOOL WINAPI TranslateMessage(CONST MSG *lpMsg)
{
DUMMY_ONCE();
assert(lpMsg->hwnd == 0);
if (lpMsg->message == WM_KEYDOWN) {
int key = lpMsg->wParam;
unsigned mod = (DWORD)lpMsg->lParam >> 16;
bool shift = (mod & KMOD_SHIFT) != 0;
bool upper = shift != (mod & KMOD_CAPS);
bool is_alpha = (key >= 'A' && key <= 'Z');
bool is_numeric = (key >= '0' && key <= '9');
bool is_control = key == VK_SPACE || key == VK_BACK || key == VK_ESCAPE || key == VK_TAB || key == VK_RETURN;
bool is_oem = (key >= VK_OEM_1 && key <= VK_OEM_7);
if (is_control || is_alpha || is_numeric || is_oem) {
if (!upper && is_alpha) {
key = tolower(key);
} else if (shift && is_numeric) {
key = key == '0' ? ')' : key - 0x10;
} else if (is_oem) {
// XXX: This probably only supports US keyboard layout
switch (key) {
case VK_OEM_1:
key = shift ? ':' : ';';
break;
case VK_OEM_2:
key = shift ? '?' : '/';
break;
case VK_OEM_3:
key = shift ? '~' : '`';
break;
case VK_OEM_4:
key = shift ? '{' : '[';
break;
case VK_OEM_5:
key = shift ? '|' : '\\';
break;
case VK_OEM_6:
key = shift ? '}' : ']';
break;
case VK_OEM_7:
key = shift ? '"' : '\'';
break;
case VK_OEM_MINUS:
key = shift ? '_' : '-';
break;
case VK_OEM_PLUS:
key = shift ? '+' : '=';
break;
case VK_OEM_PERIOD:
key = shift ? '>' : '.';
break;
case VK_OEM_COMMA:
key = shift ? '<' : ',';
break;
default:
UNIMPLEMENTED();
}
}
if (key >= 32) {
DUMMY_PRINT("char: %c", key);
}
// XXX: This does not add extended info to lParam
PostMessageA(lpMsg->hwnd, WM_CHAR, key, 0);
}
}
return TRUE;
}
SHORT WINAPI GetAsyncKeyState(int vKey)
{
DUMMY_ONCE();
// TODO: Not handled yet.
return 0;
}
LRESULT WINAPI DispatchMessageA(CONST MSG *lpMsg)
{
DUMMY_ONCE();
assert(lpMsg->hwnd == 0);
assert(CurrentProc);
// assert(CurrentProc == GM_Game);
return CurrentProc(lpMsg->hwnd, lpMsg->message, lpMsg->wParam, lpMsg->lParam);
}
WINBOOL WINAPI PostMessageA(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
DUMMY();
assert(hWnd == 0);
MSG msg;
msg.hwnd = hWnd;
msg.message = Msg;
msg.wParam = wParam;
msg.lParam = lParam;
message_queue.push_back(msg);
return TRUE;
}

20
Stub/miniwin_rand.cpp

@ -0,0 +1,20 @@
/** @file
*
* An implementation of the MSVCRT random number generator for codec_encode().
*/
#include "miniwin.h"
#include "stubs.h"
unsigned int rand_state = 1;
int rand_miniwin(void)
{
rand_state = rand_state * 214013 + 2531011;
return (rand_state >> 16) & 0x7FFF;
}
void srand_miniwin(unsigned int seed)
{
rand_state = seed;
}

11
Stub/miniwin_sdl.h

@ -0,0 +1,11 @@
#pragma once
/** @file
* Utilities for SDL.
*/
#include <assert.h>
#include <SDL2/SDL.h>
#define SDL_CHECK(e) assert(e == 0)

11
Stub/movie.cpp

@ -0,0 +1,11 @@
#include "../types.h"
#include "stubs.h"
#ifndef NO_GLOBALS
BOOL loop_movie;
#endif
void __fastcall play_movie(char *pszMovie, BOOL user_can_close)
{
DUMMY_PRINT("%s", pszMovie);
}

81
Stub/nthread.cpp

@ -0,0 +1,81 @@
#include <algorithm>
#include "../types.h"
#include "stubs.h"
#ifndef NO_GLOBALS
int gdwNormalMsgSize;
int gdwLargestMsgSize;
int gdwMsgLenTbl[4];
int glpMsgTbl[4];
int gdwTurnsInTransit;
char byte_679704;
#endif
void __fastcall nthread_start(bool set_turn_upper_bit)
{
DUMMY();
byte_679704 = 1;
gdwTurnsInTransit = 1;
gdwLargestMsgSize = 496;
gdwNormalMsgSize = 496;
}
void __cdecl nthread_cleanup()
{
DUMMY();
}
void __fastcall nthread_terminate_game(char *pszFcn)
{
UNIMPLEMENTED();
}
void __fastcall nthread_ignore_mutex(bool bStart)
{
DUMMY();
}
bool __cdecl nthread_has_500ms_passed()
{
DUMMY_ONCE();
return TRUE;
}
DWORD last_frame_time = 0;
const int MSEC_PER_FRAME = 1000 / 35;
static void frame_rate_limiter()
{
if (last_frame_time) {
int elapsed = GetTickCount() - last_frame_time;
int remaining = MSEC_PER_FRAME - elapsed;
if (remaining > 0) {
Sleep(std::max(remaining, MSEC_PER_FRAME));
}
}
last_frame_time = GetTickCount();
}
int __fastcall nthread_send_and_recv_turn(int cur_turn, int turn_delta)
{
DUMMY_ONCE();
// DUMMY_PRINT("cur_turn: %d turn_delta: %d", cur_turn, turn_delta);
frame_rate_limiter();
return 1;
}
void __cdecl nthread_set_turn_upper_bit()
{
UNIMPLEMENTED();
}
int __fastcall nthread_recv_turns(int *pfSendAsync)
{
DUMMY_ONCE();
*pfSendAsync = 0;
return TRUE;
}

14
Stub/restrict.cpp

@ -0,0 +1,14 @@
#include "../types.h"
#include "stubs.h"
bool __cdecl RestrictedTest()
{
DUMMY();
return FALSE;
}
bool __cdecl ReadOnlyTest()
{
DUMMY();
return FALSE;
}

66
Stub/sound.cpp

@ -0,0 +1,66 @@
#include "../types.h"
#include "stubs.h"
#ifndef NO_GLOBALS
char gbSndInited;
char gbDupSounds;
UCHAR gbMusicOn;
UCHAR gbSoundOn;
#endif
void __fastcall snd_init(HWND hWnd)
{
DUMMY();
}
void __fastcall music_start(int nTrack)
{
DUMMY();
}
void __cdecl music_stop()
{
DUMMY();
}
bool __fastcall snd_playing(TSnd *pSnd)
{
UNIMPLEMENTED();
}
void __fastcall snd_play_snd(TSnd *pSnd, int lVolume, int lPan)
{
UNIMPLEMENTED();
}
void __fastcall snd_stop_snd(TSnd *pSnd)
{
DUMMY();
}
TSnd *__fastcall sound_file_load(char *path)
{
UNIMPLEMENTED();
}
void __fastcall sound_file_cleanup(TSnd *sound_file)
{
UNIMPLEMENTED();
}
int __fastcall sound_get_or_set_sound_volume(int volume)
{
DUMMY_PRINT("volume: %d", volume);
return volume;
}
int __fastcall sound_get_or_set_music_volume(int volume)
{
DUMMY_PRINT("volume: %d", volume);
return volume;
}
void __fastcall snd_update(bool bStopAll)
{
DUMMY_PRINT("stopall: %d", bStopAll);
}

367
Stub/storm.cpp

@ -0,0 +1,367 @@
#include "../types.h"
#include "stubs.h"
DWORD nLastError = 0;
BOOL STORMAPI SNetCreateGame(const char *pszGameName, const char *pszGamePassword, const char *pszGameStatString,
DWORD dwGameType, char *GameTemplateData, int GameTemplateSize, int playerCount,
char *creatorName, char *a11, int *playerID)
{
DUMMY();
return TRUE;
}
BOOL STORMAPI SNetDestroy()
{
DUMMY();
return TRUE;
}
BOOL STORMAPI SNetDropPlayer(int playerid, DWORD flags)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SNetGetGameInfo(int type, void *dst, size_t length, size_t *byteswritten)
{
DUMMY();
return TRUE;
}
BOOL STORMAPI SNetGetTurnsInTransit(int *turns)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SNetLeaveGame(int type)
{
DUMMY();
return TRUE;
}
BOOL STORMAPI SNetPerformUpgrade(DWORD *upgradestatus)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SNetReceiveTurns(int a1, int arraysize, char **arraydata, unsigned int *arraydatabytes,
DWORD *arrayplayerstatus)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SNetSendTurn(char *data, size_t databytes)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SNetSetGameMode(DWORD modeFlags, bool makePublic)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SNetSendServerChatCommand(const char *command)
{
UNIMPLEMENTED();
}
// BOOL STORMAPI SFileCloseArchive(HANDLE hArchive)
// {
// UNIMPLEMENTED();
// }
// BOOL STORMAPI SFileCloseFile(HANDLE hFile)
// {
// UNIMPLEMENTED();
// }
BOOL STORMAPI SFileDdaBeginEx(HANDLE directsound, DWORD flags, DWORD mask, unsigned __int32 lDistanceToMove,
signed __int32 volume, signed int a6, int a7)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SFileDdaDestroy()
{
UNIMPLEMENTED();
}
BOOL STORMAPI SFileDdaEnd(HANDLE directsound)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SFileDdaGetPos(HANDLE directsound, int a2, int a3)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SFileDdaInitialize(HANDLE directsound)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SFileDdaSetVolume(HANDLE directsound, signed int bigvolume, signed int volume)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SFileGetFileArchive(HANDLE hFile, HANDLE archive)
{
UNIMPLEMENTED();
}
// LONG STORMAPI SFileGetFileSize(HANDLE hFile, LPDWORD lpFileSizeHigh)
// {
// UNIMPLEMENTED();
// }
// BOOL STORMAPI SFileOpenArchive(const char *szMpqName, DWORD dwPriority, DWORD dwFlags, HANDLE
// *phMpq)
// {
// UNIMPLEMENTED();
// }
BOOL STORMAPI SFileOpenFile(const char *filename, HANDLE *phFile)
{
BOOL result;
eprintf("%s: %s\n", __FUNCTION__, filename);
result = SFileOpenFileEx((HANDLE)patch_rt_mpq, filename, 0, phFile);
if (!result) {
result = SFileOpenFileEx((HANDLE)diabdat_mpq, filename, 0, phFile);
}
if (!result || !*phFile) {
eprintf("%s: Not found: %s\n", __FUNCTION__, filename);
}
return result;
}
// BOOL STORMAPI SFileOpenFileEx(HANDLE hMpq, const char *szFileName, DWORD dwSearchScope, HANDLE
// *phFile)
// {
// UNIMPLEMENTED();
// }
// BOOL STORMAPI SFileReadFile(HANDLE hFile, void *buffer, DWORD nNumberOfBytesToRead, DWORD *read,
// LONG lpDistanceToMoveHigh)
// {
// UNIMPLEMENTED();
// }
// int __stdcall SFileSetFilePointer(HANDLE, int, HANDLE, int)
// {
// UNIMPLEMENTED();
// }
HWND STORMAPI SDrawGetFrameWindow(HWND *sdraw_framewindow)
{
DUMMY();
return NULL;
}
// BOOL STORMAPI SDrawManualInitialize(HWND hWnd, LPDIRECTDRAW ddInterface, LPDIRECTDRAWSURFACE
// primarySurface, LPDIRECTDRAWSURFACE surface2, LPDIRECTDRAWSURFACE surface3, LPDIRECTDRAWSURFACE
// backSurface, LPDIRECTDRAWPALETTE ddPalette, HPALETTE hPalette)
//{
// UNIMPLEMENTED();
//}
void *STORMAPI SMemAlloc(size_t amount, char *logfilename, int logline, char defaultValue)
{
// fprintf(stderr, "%s: %d (%s:%d)\n", __FUNCTION__, amount, logfilename, logline);
assert(amount != -1);
return malloc(amount);
}
BOOL STORMAPI SMemFree(void *location, char *logfilename, int logline, char defaultValue)
{
// fprintf(stderr, "%s: (%s:%d)\n", __FUNCTION__, logfilename, logline);
assert(location);
free(location);
return TRUE;
}
void *STORMAPI SMemReAlloc(void *location, size_t amount, char *logfilename, int logline, char defaultValue)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SRegLoadData(const char *keyname, const char *valuename, int size, LPBYTE lpData, BYTE flags,
LPDWORD lpcbData)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SRegLoadString(const char *keyname, const char *valuename, BYTE flags, char *buffer, size_t buffersize)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SRegLoadValue(const char *keyname, const char *valuename, BYTE flags, int *value)
{
DUMMY_PRINT("key: %s value: %s", keyname, valuename);
return FALSE;
}
BOOL STORMAPI SRegSaveData(const char *keyname, const char *valuename, int size, BYTE *lpData, DWORD cbData)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SRegSaveString(const char *keyname, const char *valuename, BYTE flags, char *string)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SRegSaveValue(const char *keyname, const char *valuename, BYTE flags, DWORD result)
{
DUMMY_PRINT("key: %s value: %s", keyname, valuename);
return TRUE;
}
// BOOL STORMAPI SVidDestroy()
//{
// UNIMPLEMENTED();
//}
//
// BOOL STORMAPI SVidInitialize(HANDLE video)
//{
// UNIMPLEMENTED();
//}
//
// BOOL STORMAPI SVidPlayBegin(char *filename, int arg4, int a3, int a4, int a5, int a6, HANDLE
// *video)
//{
// UNIMPLEMENTED();
//}
//
// BOOL STORMAPI SVidPlayEnd(HANDLE video)
//{
// UNIMPLEMENTED();
//}
BOOL STORMAPI SErrDisplayError(DWORD dwErrMsg, const char *logfilename, int logline, const char *message,
BOOL allowOption, int exitCode)
{
UNIMPLEMENTED();
}
BOOL STORMAPI SErrGetErrorStr(DWORD dwErrCode, char *buffer, size_t bufferchars)
{
UNIMPLEMENTED();
}
DWORD STORMAPI SErrGetLastError()
{
return nLastError;
}
void STORMAPI SErrSetLastError(DWORD dwErrCode)
{
nLastError = dwErrCode;
}
void STORMAPI SMemCopy(void *dest, const void *source, size_t size)
{
UNIMPLEMENTED();
}
void STORMAPI SMemFill(void *location, size_t length, char fillWith)
{
UNIMPLEMENTED();
}
void STORMAPI SMemZero(void *location, DWORD length)
{
UNIMPLEMENTED();
}
int STORMAPI SMemCmp(void *location1, void *location2, DWORD size)
{
UNIMPLEMENTED();
}
int STORMAPI SStrCopy(char *dest, const char *src, int max_length)
{
UNIMPLEMENTED();
}
int STORMAPI SStrCmp(const char *string1, const char *string2, size_t size)
{
UNIMPLEMENTED();
}
int STORMAPI SStrCmpI(const char *string1, const char *string2, size_t size)
{
UNIMPLEMENTED();
}
// void __stdcall SDrawMessageBox(char *, char *, int)
//{
// UNIMPLEMENTED();
//}
//
// void __cdecl SDrawDestroy(void)
//{
// UNIMPLEMENTED();
//}
//
// bool __cdecl StormDestroy(void)
//{
// UNIMPLEMENTED();
//}
//
// bool __stdcall SFileSetBasePath(char *)
//{
// UNIMPLEMENTED();
//}
void __cdecl SDrawRealizePalette(void)
{
DUMMY();
}
// bool __cdecl SVidPlayContinue(void)
//{
// UNIMPLEMENTED();
//}
bool __stdcall SNetGetOwnerTurnsWaiting(int *)
{
UNIMPLEMENTED();
}
void *__stdcall SNetUnregisterEventHandler(int, void(__stdcall *)(struct _SNETEVENT *))
{
DUMMY();
return (void *)-1;
}
void *__stdcall SNetRegisterEventHandler(int, void(__stdcall *)(struct _SNETEVENT *))
{
UNIMPLEMENTED();
}
bool __stdcall SNetSetBasePlayer(int)
{
DUMMY();
return TRUE;
}
int __stdcall SNetInitializeProvider(unsigned long a1, struct _SNETPROGRAMDATA *client_info,
struct _SNETPLAYERDATA *user_info, struct _SNETUIDATA *ui_info,
struct _SNETVERSIONDATA *fileinfo)
{
DUMMY();
ui_info->selectnamecallback(0, 0, 0, 0, 0, NULL, 0, NULL, 0, NULL);
return TRUE;
}
int __stdcall SNetGetProviderCaps(struct _SNETCAPS *)
{
UNIMPLEMENTED();
}

49
Stub/storm_net.cpp

@ -0,0 +1,49 @@
/** @file
*
* A minimal implementation of the Storm network stack necessary for local play.
*/
#include <deque>
#include <string>
#include "../types.h"
#include "stubs.h"
struct StubMessage {
int playerid;
std::string data;
};
/** A queue of messages waiting to be processed. */
static std::deque<StubMessage> snet_messages;
/**
* Last message returned from SNetReceiveMessage().
* Must always be kept alive because the caller will read the data afterwards.
*/
static StubMessage snet_current_message;
BOOL STORMAPI SNetReceiveMessage(int *senderplayerid, char **data, int *databytes)
{
DUMMY_ONCE();
if (snet_messages.empty()) {
SErrSetLastError(STORM_ERROR_NO_MESSAGES_WAITING);
return FALSE;
}
snet_current_message = std::move(snet_messages.front());
snet_messages.pop_front();
*senderplayerid = snet_current_message.playerid;
*data = const_cast<char *>(snet_current_message.data.data());
*databytes = snet_current_message.data.size();
return TRUE;
}
BOOL STORMAPI SNetSendMessage(int playerID, void *data, size_t databytes)
{
DUMMY();
snet_messages.push_back(StubMessage{playerID, std::string((char *)data, databytes)});
return TRUE;
}

34
Stub/stubs.h

@ -0,0 +1,34 @@
#pragma once
/** @file
* Utility functions for stubs.
*/
#include <assert.h>
#include <stdio.h>
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define UNIMPLEMENTED() \
{ \
eprintf("UNIMPLEMENTED: %s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \
abort(); \
}
#define DUMMY() eprintf("DUMMY: %s @ %s:%d\n", __FUNCTION__, __FILE__, __LINE__)
#define DUMMY_ONCE() \
{ \
static bool dummy_shown = false; \
if (!dummy_shown) { \
DUMMY(); \
dummy_shown = true; \
} \
}
#define DUMMY_PRINT(fmt, ...) eprintf("DUMMY: %s : " fmt "\n", __FUNCTION__, __VA_ARGS__)
static inline const char *nullstr(const char *a)
{
return a ? a : "(null)";
}

6
Stub/validate.cpp

@ -0,0 +1,6 @@
/** @file
* Perform some basic compile-time validation to make sure things line up.
*/
#include "../types.h"
static_assert(sizeof(plr) == 0x15360u, "sizeof(PlayerStruct) is wrong");

9
docker/arch/Dockerfile

@ -0,0 +1,9 @@
FROM base/archlinux
RUN echo -e "[multilib]\nInclude = /etc/pacman.d/mirrorlist" >> /etc/pacman.conf
RUN pacman -Sy
RUN pacman --noconfirm -Sy \
make gcc cmake pkg-config nasm lib32-gcc-libs lib32-sdl2
WORKDIR /build
VOLUME /src

10
docker/build.sh

@ -0,0 +1,10 @@
#!/bin/bash
#
# Build script to run inside a Docker container
#
set -e
cmake /src
make -j$(nproc)

10
docker/ubuntu/Dockerfile

@ -0,0 +1,10 @@
FROM ubuntu:16.04
RUN dpkg --add-architecture i386
RUN apt-get update
RUN apt-get update && apt-get install -y --no-install-recommends \
g++-multilib cmake nasm pkg-config libsdl2-dev:i386
WORKDIR /build
VOLUME /src
Loading…
Cancel
Save