Merge tag '1.11.0-beta2' into jgrpp

# Conflicts:
#	.github/workflows/ci-build.yml
#	.github/workflows/release.yml
#	CMakeLists.txt
#	src/blitter/32bpp_optimized.cpp
#	src/debug.cpp
#	src/gfx.cpp
#	src/gfx_func.h
#	src/lang/czech.txt
#	src/lang/english.txt
#	src/lang/italian.txt
#	src/lang/swedish.txt
#	src/lang/ukrainian.txt
#	src/network/network_server.cpp
#	src/os/windows/crashlog_win.cpp
#	src/os/windows/win32.cpp
#	src/pathfinder/follow_track.hpp
#	src/screenshot.cpp
#	src/settings_type.h
#	src/spritecache.cpp
#	src/vehicle_gui.cpp
#	src/video/sdl2_v.cpp
#	src/video/video_driver.cpp
#	src/video/video_driver.hpp
#	src/video/win32_v.cpp
This commit is contained in:
Jonathan G Rennison
2021-03-02 11:59:03 +00:00
148 changed files with 19670 additions and 1452 deletions

View File

@@ -286,6 +286,7 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
SpriteLoader::Sprite sprite;
sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
sprite.type = ST_FONT;
sprite.colours = (use_aa ? SCC_PAL | SCC_ALPHA : SCC_PAL);
sprite.width = width;
sprite.height = height;
sprite.x_offs = (int16)std::round(CGRectGetMinX(bounds));
@@ -332,7 +333,7 @@ const Sprite *CoreTextFontCache::InternalGetGlyph(GlyphID key, bool use_aa)
}
GlyphEntry new_glyph;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, SimpleSpriteAlloc);
new_glyph.width = (byte)std::round(CTFontGetAdvancesForGlyphs(this->font.get(), kCTFontOrientationDefault, &glyph, nullptr, 1));
this->SetGlyphPtr(key, &new_glyph);

View File

@@ -191,7 +191,7 @@ static uint32 CalcCRC(byte *data, uint size, uint32 crc)
return crc;
}
static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename)
static void GetFileInfo(DebugFileInfo *dfi, const wchar_t *filename)
{
HANDLE file;
memset(dfi, 0, sizeof(*dfi));
@@ -224,7 +224,7 @@ static void GetFileInfo(DebugFileInfo *dfi, const TCHAR *filename)
static char *PrintModuleInfo(char *output, const char *last, HMODULE mod)
{
TCHAR buffer[MAX_PATH];
wchar_t buffer[MAX_PATH];
DebugFileInfo dfi;
GetModuleFileName(mod, buffer, MAX_PATH);
@@ -568,7 +568,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c
if (_settings_client.gui.developer == 0) return 0;
int ret = 0;
HMODULE dbghelp = LoadLibrary(_T("dbghelp.dll"));
HMODULE dbghelp = LoadLibrary(L"dbghelp.dll");
if (dbghelp != nullptr) {
typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
MINIDUMP_TYPE,
@@ -631,10 +631,10 @@ static LONG WINAPI ExceptionHandler(EXCEPTION_POINTERS *ep)
const char *abort_reason = CrashLog::GetAbortCrashlogReason();
if (abort_reason != nullptr) {
TCHAR _emergency_crash[512];
_sntprintf(_emergency_crash, lengthof(_emergency_crash),
_T("A serious fault condition occurred in the game. The game will shut down. (%s)\n"), OTTD2FS(abort_reason));
MessageBox(nullptr, _emergency_crash, _T("Fatal Application Failure"), MB_ICONERROR);
wchar_t _emergency_crash[512];
_snwprintf(_emergency_crash, lengthof(_emergency_crash),
L"A serious fault condition occurred in the game. The game will shut down. (%s)\n", OTTD2FS(abort_reason));
MessageBox(nullptr, _emergency_crash, L"Fatal Application Failure", MB_ICONERROR);
ExitProcess(3);
}
@@ -750,20 +750,20 @@ static void CDECL CustomAbort(int signal)
static bool _expanded;
static const TCHAR _crash_desc[] =
_T("A serious fault condition occurred in the game. The game will shut down.\n")
_T("Please send the crash information (log files and crash saves, if any) to the patchpack developer.\n")
_T("This will greatly help debugging. The correct place to do this is https://www.tt-forums.net/viewtopic.php?f=33&t=73469")
_T(" or https://github.com/JGRennison/OpenTTD-patches\n")
_T("The information contained in the report is displayed below.\n")
_T("Press \"Emergency save\" to attempt saving the game. Generated file(s):\n")
_T("%s");
L"A serious fault condition occurred in the game. The game will shut down.\n"
L"Please send the crash information (log files and crash saves, if any) to the patchpack developer.\n"
L"This will greatly help debugging. The correct place to do this is https://www.tt-forums.net/viewtopic.php?f=33&t=73469"
L" or https://github.com/JGRennison/OpenTTD-patches\n"
L"The information contained in the report is displayed below.\n"
L"Press \"Emergency save\" to attempt saving the game. Generated file(s):\n"
L"%s";
static const TCHAR _save_succeeded[] =
_T("Emergency save succeeded.\nIts location is '%s'.\n")
_T("Be aware that critical parts of the internal game state may have become ")
_T("corrupted. The saved game is not guaranteed to work.");
static const wchar_t _save_succeeded[] =
L"Emergency save succeeded.\nIts location is '%s'.\n"
L"Be aware that critical parts of the internal game state may have become "
L"corrupted. The saved game is not guaranteed to work.";
static const TCHAR * const _expand_texts[] = {_T("S&how report >>"), _T("&Hide report <<") };
static const wchar_t * const _expand_texts[] = {L"S&how report >>", L"&Hide report <<" };
static void SetWndSize(HWND wnd, int mode)
{
@@ -786,17 +786,13 @@ static void SetWndSize(HWND wnd, int mode)
}
}
/* When TCHAR is char, then _sntprintf becomes snprintf. When TCHAR is wchar it doesn't. Likewise for strcat. */
#undef snprintf
#undef strcat
static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_INITDIALOG: {
/* We need to put the crash-log in a separate buffer because the default
* buffer in MB_TO_WIDE is not large enough (512 chars) */
TCHAR crash_msgW[lengthof(CrashLogWindows::current->crashlog)];
* buffer in OTTD2FS is not large enough (512 chars) */
wchar_t crash_msgW[lengthof(CrashLogWindows::current->crashlog)];
/* Convert unix -> dos newlines because the edit box only supports that properly :( */
const char *unix_nl = CrashLogWindows::current->crashlog;
char dos_nl[lengthof(CrashLogWindows::current->crashlog)];
@@ -809,20 +805,20 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
*p = '\0';
/* Add path to crash.log and crash.dmp (if any) to the crash window text */
size_t len = _tcslen(_crash_desc) + 2;
len += _tcslen(OTTD2FS(CrashLogWindows::current->crashlog_filename)) + 2;
len += _tcslen(OTTD2FS(CrashLogWindows::current->crashdump_filename)) + 2;
len += _tcslen(OTTD2FS(CrashLogWindows::current->screenshot_filename)) + 1;
size_t len = wcslen(_crash_desc) + 2;
len += wcslen(OTTD2FS(CrashLogWindows::current->crashlog_filename)) + 2;
len += wcslen(OTTD2FS(CrashLogWindows::current->crashdump_filename)) + 2;
len += wcslen(OTTD2FS(CrashLogWindows::current->screenshot_filename)) + 1;
TCHAR *text = AllocaM(TCHAR, len);
_sntprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename));
if (_settings_client.gui.developer > 0 && OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != _T('\0')) {
_tcscat(text, _T("\n"));
_tcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename));
wchar_t *text = AllocaM(wchar_t, len);
_snwprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename));
if (_settings_client.gui.developer > 0 && OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != L'\0') {
wcscat(text, L"\n");
wcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename));
}
if (OTTD2FS(CrashLogWindows::current->screenshot_filename)[0] != _T('\0')) {
_tcscat(text, _T("\n"));
_tcscat(text, OTTD2FS(CrashLogWindows::current->screenshot_filename));
if (OTTD2FS(CrashLogWindows::current->screenshot_filename)[0] != L'\0') {
wcscat(text, L"\n");
wcscat(text, OTTD2FS(CrashLogWindows::current->screenshot_filename));
}
SetDlgItemText(wnd, 10, text);
@@ -840,12 +836,12 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA
_save_DBGC_data = true;
char filename[MAX_PATH];
if (CrashLogWindows::current->WriteSavegame(filename, lastof(filename), CrashLogWindows::current->name_buffer)) {
size_t len = _tcslen(_save_succeeded) + _tcslen(OTTD2FS(filename)) + 1;
TCHAR *text = AllocaM(TCHAR, len);
_sntprintf(text, len, _save_succeeded, OTTD2FS(filename));
MessageBox(wnd, text, _T("Save successful"), MB_ICONINFORMATION);
size_t len = wcslen(_save_succeeded) + wcslen(OTTD2FS(filename)) + 1;
wchar_t *text = AllocaM(wchar_t, len);
_snwprintf(text, len, _save_succeeded, OTTD2FS(filename));
MessageBox(wnd, text, L"Save successful", MB_ICONINFORMATION);
} else {
MessageBox(wnd, _T("Save failed"), _T("Save failed"), MB_ICONINFORMATION);
MessageBox(wnd, L"Save failed", L"Save failed", MB_ICONINFORMATION);
}
_savegame_DBGL_data = nullptr;
_save_DBGC_data = false;

View File

@@ -46,17 +46,12 @@ extern FT_Library _library;
* @param long_path the path in system encoding.
* @return the short path in ANSI (ASCII).
*/
static const char *GetShortPath(const TCHAR *long_path)
static const char *GetShortPath(const wchar_t *long_path)
{
static char short_path[MAX_PATH];
#ifdef UNICODE
WCHAR short_path_w[MAX_PATH];
wchar_t short_path_w[MAX_PATH];
GetShortPathName(long_path, short_path_w, lengthof(short_path_w));
WideCharToMultiByte(CP_ACP, 0, short_path_w, -1, short_path, lengthof(short_path), nullptr, nullptr);
#else
/* Technically not needed, but do it for consistency. */
GetShortPathName(long_path, short_path, lengthof(short_path));
#endif
return short_path;
}
@@ -68,35 +63,30 @@ static const char *GetShortPath(const TCHAR *long_path)
* kept in memory then until the font is no longer needed. This could mean
* an additional memory usage of 30MB (just for fonts!) when using an eastern
* font for all font sizes */
#define FONT_DIR_NT "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts"
#define FONT_DIR_9X "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Fonts"
static const wchar_t *FONT_DIR_NT = L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts";
FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
{
FT_Error err = FT_Err_Cannot_Open_Resource;
HKEY hKey;
LONG ret;
TCHAR vbuffer[MAX_PATH], dbuffer[256];
TCHAR *pathbuf;
wchar_t vbuffer[MAX_PATH], dbuffer[256];
wchar_t *pathbuf;
const char *font_path;
uint index;
size_t path_len;
/* On windows NT (2000, NT3.5, XP, etc.) the fonts are stored in the
* "Windows NT" key, on Windows 9x in the Windows key. To save us having
* to retrieve the windows version, we'll just query both */
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_NT), 0, KEY_READ, &hKey);
if (ret != ERROR_SUCCESS) ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T(FONT_DIR_9X), 0, KEY_READ, &hKey);
ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, FONT_DIR_NT, 0, KEY_READ, &hKey);
if (ret != ERROR_SUCCESS) {
DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows (NT)\\CurrentVersion\\Fonts");
DEBUG(freetype, 0, "Cannot open registry key HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Fonts");
return err;
}
/* Convert font name to file system encoding. */
TCHAR *font_namep = _tcsdup(OTTD2FS(font_name));
wchar_t *font_namep = wcsdup(OTTD2FS(font_name));
for (index = 0;; index++) {
TCHAR *s;
wchar_t *s;
DWORD vbuflen = lengthof(vbuffer);
DWORD dbuflen = lengthof(dbuffer);
@@ -112,17 +102,17 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
* TTC files, font files which contain more than one font are separated
* by '&'. Our best bet will be to do substr match for the fontname
* and then let FreeType figure out which index to load */
s = _tcschr(vbuffer, _T('('));
s = wcschr(vbuffer, L'(');
if (s != nullptr) s[-1] = '\0';
if (_tcschr(vbuffer, _T('&')) == nullptr) {
if (_tcsicmp(vbuffer, font_namep) == 0) break;
if (wcschr(vbuffer, L'&') == nullptr) {
if (wcsicmp(vbuffer, font_namep) == 0) break;
} else {
if (_tcsstr(vbuffer, font_namep) != nullptr) break;
if (wcsstr(vbuffer, font_namep) != nullptr) break;
}
}
if (!SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, vbuffer))) {
if (!SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_FONTS, nullptr, SHGFP_TYPE_CURRENT, vbuffer))) {
DEBUG(freetype, 0, "SHGetFolderPath cannot return fonts directory");
goto folder_error;
}
@@ -131,9 +121,9 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face)
* contain multiple fonts inside this single file. GetFontData however
* returns the whole file, so we need to check each font inside to get the
* proper font. */
path_len = _tcslen(vbuffer) + _tcslen(dbuffer) + 2; // '\' and terminating nul.
pathbuf = AllocaM(TCHAR, path_len);
_sntprintf(pathbuf, path_len, _T("%s\\%s"), vbuffer, dbuffer);
path_len = wcslen(vbuffer) + wcslen(dbuffer) + 2; // '\' and terminating nul.
pathbuf = AllocaM(wchar_t, path_len);
_snwprintf(pathbuf, path_len, L"%s\\%s", vbuffer, dbuffer);
/* Convert the path into something that FreeType understands. */
font_path = GetShortPath(pathbuf);
@@ -238,13 +228,13 @@ err2:
ReleaseDC(nullptr, dc);
DeleteObject(font);
err1:
return ret_font_name == nullptr ? WIDE_TO_MB((const TCHAR *)logfont->elfFullName) : ret_font_name;
return ret_font_name == nullptr ? FS2OTTD((const wchar_t *)logfont->elfFullName) : ret_font_name;
}
#endif /* WITH_FREETYPE */
class FontList {
protected:
TCHAR **fonts;
wchar_t **fonts;
uint items;
uint capacity;
@@ -261,9 +251,9 @@ public:
free(this->fonts);
}
bool Add(const TCHAR *font) {
bool Add(const wchar_t *font) {
for (uint i = 0; i < this->items; i++) {
if (_tcscmp(this->fonts[i], font) == 0) return false;
if (wcscmp(this->fonts[i], font) == 0) return false;
}
if (this->items == this->capacity) {
@@ -271,7 +261,7 @@ public:
this->fonts = ReallocT(this->fonts, this->capacity);
}
this->fonts[this->items++] = _tcsdup(font);
this->fonts[this->items++] = wcsdup(font);
return true;
}
@@ -289,7 +279,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
EFCParam *info = (EFCParam *)lParam;
/* Skip duplicates */
if (!info->fonts.Add((const TCHAR *)logfont->elfFullName)) return 1;
if (!info->fonts.Add((const wchar_t *)logfont->elfFullName)) return 1;
/* Only use TrueType fonts */
if (!(type & TRUETYPE_FONTTYPE)) return 1;
/* Don't use SYMBOL fonts */
@@ -315,7 +305,7 @@ static int CALLBACK EnumFontCallback(const ENUMLOGFONTEX *logfont, const NEWTEXT
}
char font_name[MAX_PATH];
convert_from_fs((const TCHAR *)logfont->elfFullName, font_name, lengthof(font_name));
convert_from_fs((const wchar_t *)logfont->elfFullName, font_name, lengthof(font_name));
#ifdef WITH_FREETYPE
/* Add english name after font name */
@@ -352,7 +342,7 @@ bool SetFallbackFont(FreeTypeSettings *settings, const char *language_isocode, i
{
DEBUG(freetype, 1, "Trying fallback fonts");
EFCParam langInfo;
if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(TCHAR)) == 0) {
if (GetLocaleInfo(MAKELCID(winlangid, SORT_DEFAULT), LOCALE_FONTSIGNATURE, (LPTSTR)&langInfo.locale, sizeof(langInfo.locale) / sizeof(wchar_t)) == 0) {
/* Invalid langid or some other mysterious error, can't determine fallback font. */
DEBUG(freetype, 1, "Can't get locale info for fallback font (langid=0x%x)", winlangid);
return false;
@@ -497,6 +487,7 @@ void Win32FontCache::ClearFontCache()
SpriteLoader::Sprite sprite;
sprite.AllocateData(ZOOM_LVL_NORMAL, width * height);
sprite.type = ST_FONT;
sprite.colours = (aa ? SCC_PAL | SCC_ALPHA : SCC_PAL);
sprite.width = width;
sprite.height = height;
sprite.x_offs = gm.gmptGlyphOrigin.x;
@@ -533,7 +524,7 @@ void Win32FontCache::ClearFontCache()
}
GlyphEntry new_glyph;
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, AllocateFont);
new_glyph.sprite = BlitterFactory::GetCurrentBlitter()->Encode(&sprite, SimpleSpriteAlloc);
new_glyph.width = gm.gmCellIncX;
this->SetGlyphPtr(key, &new_glyph);
@@ -612,7 +603,7 @@ void LoadWin32Font(FontSize fs)
} else if (strchr(settings->font, '.') != nullptr) {
/* Might be a font file name, try load it. */
TCHAR fontPath[MAX_PATH] = {};
wchar_t fontPath[MAX_PATH] = {};
/* See if this is an absolute path. */
if (FileExists(settings->font)) {
@@ -630,11 +621,7 @@ void LoadWin32Font(FontSize fs)
/* Try a nice little undocumented function first for getting the internal font name.
* Some documentation is found at: http://www.undocprint.org/winspool/getfontresourceinfo */
typedef BOOL(WINAPI *PFNGETFONTRESOURCEINFO)(LPCTSTR, LPDWORD, LPVOID, DWORD);
#ifdef UNICODE
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoW");
#else
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(_T("Gdi32")), "GetFontResourceInfoA");
#endif
static PFNGETFONTRESOURCEINFO GetFontResourceInfo = (PFNGETFONTRESOURCEINFO)GetProcAddress(GetModuleHandle(L"Gdi32"), "GetFontResourceInfoW");
if (GetFontResourceInfo != nullptr) {
/* Try to query an array of LOGFONTs that describe the file. */
@@ -649,10 +636,10 @@ void LoadWin32Font(FontSize fs)
/* No dice yet. Use the file name as the font face name, hoping it matches. */
if (logfont.lfFaceName[0] == 0) {
TCHAR fname[_MAX_FNAME];
_tsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
wchar_t fname[_MAX_FNAME];
_wsplitpath(fontPath, nullptr, nullptr, fname, nullptr);
_tcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
wcsncpy_s(logfont.lfFaceName, lengthof(logfont.lfFaceName), fname, _TRUNCATE);
logfont.lfWeight = strcasestr(settings->font, " bold") != nullptr || strcasestr(settings->font, "-bold") != nullptr ? FW_BOLD : FW_NORMAL; // Poor man's way to allow selecting bold fonts.
}
} else {

View File

@@ -33,7 +33,7 @@ public:
~Win32FontCache();
void ClearFontCache() override;
GlyphID MapCharToGlyph(WChar key) override;
const char *GetFontName() override { return WIDE_TO_MB(this->logfont.lfFaceName); }
const char *GetFontName() override { return FS2OTTD(this->logfont.lfFaceName); }
const void *GetOSHandle() override { return &this->logfont; }
};

View File

@@ -48,7 +48,7 @@ static DWORD _tlsdata_key;
struct TLSData {
char utf8_buf[512];
TCHAR system_buf[512];
wchar_t system_buf[512];
char locale_retbuf[6];
};
@@ -76,14 +76,12 @@ bool MyShowCursor(bool show, bool toggle)
/**
* Helper function needed by dynamically loading libraries
* XXX: Hurray for MS only having an ANSI GetProcAddress function
* on normal windows and no Wide version except for in Windows Mobile/CE
*/
bool LoadLibraryList(Function proc[], const char *dll)
{
while (*dll != '\0') {
HMODULE lib;
lib = LoadLibrary(MB_TO_WIDE(dll));
lib = LoadLibrary(OTTD2FS(dll));
if (lib == nullptr) return false;
for (;;) {
@@ -103,12 +101,12 @@ bool LoadLibraryList(Function proc[], const char *dll)
void ShowOSErrorBox(const char *buf, bool system)
{
MyShowCursor(true);
MessageBox(GetActiveWindow(), OTTD2FS(buf), _T("Error!"), MB_ICONSTOP | MB_TASKMODAL);
MessageBox(GetActiveWindow(), OTTD2FS(buf), L"Error!", MB_ICONSTOP | MB_TASKMODAL);
}
void OSOpenBrowser(const char *url)
{
ShellExecute(GetActiveWindow(), _T("open"), OTTD2FS(url), nullptr, nullptr, SW_SHOWNORMAL);
ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url), nullptr, nullptr, SW_SHOWNORMAL);
}
/* Code below for windows version of opendir/readdir/closedir copied and
@@ -158,7 +156,7 @@ static inline void dir_free(DIR *d)
}
}
DIR *opendir(const TCHAR *path)
DIR *opendir(const wchar_t *path)
{
DIR *d;
UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
@@ -167,12 +165,12 @@ DIR *opendir(const TCHAR *path)
if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
d = dir_calloc();
if (d != nullptr) {
TCHAR search_path[MAX_PATH];
bool slash = path[_tcslen(path) - 1] == '\\';
wchar_t search_path[MAX_PATH];
bool slash = path[wcslen(path) - 1] == '\\';
/* build search path for FindFirstFile, try not to append additional slashes
* as it throws Win9x off its groove for root directories */
_sntprintf(search_path, lengthof(search_path), _T("%s%s*"), path, slash ? _T("") : _T("\\"));
_snwprintf(search_path, lengthof(search_path), L"%s%s*", path, slash ? L"" : L"\\");
*lastof(search_path) = '\0';
d->hFind = FindFirstFile(search_path, &d->fd);
@@ -230,8 +228,8 @@ bool FiosIsRoot(const char *file)
void FiosGetDrives(FileList &file_list)
{
TCHAR drives[256];
const TCHAR *s;
wchar_t drives[256];
const wchar_t *s;
GetLogicalDriveStrings(lengthof(drives), drives);
for (s = drives; *s != '\0';) {
@@ -270,15 +268,10 @@ bool FiosIsHiddenFile(const struct dirent *ent)
bool FiosGetDiskFreeSpace(const char *path, uint64 *tot)
{
UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box
bool retval = false;
TCHAR root[4];
DWORD spc, bps, nfc, tnc;
_sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]);
if (tot != nullptr && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
*tot = ((spc * bps) * (uint64)nfc);
retval = true;
}
ULARGE_INTEGER bytes_free;
bool retval = GetDiskFreeSpaceEx(OTTD2FS(path), &bytes_free, nullptr, nullptr);
if (retval) *tot = bytes_free.QuadPart;
SetErrorMode(sem); // reset previous setting
return retval;
@@ -392,7 +385,7 @@ static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM
*q = '\0';
/* We need to put the text in a separate buffer because the default
* buffer in OTTD2FS might not be large enough (512 chars). */
TCHAR help_msg_buf[8192];
wchar_t help_msg_buf[8192];
SetDlgItemText(wnd, 11, convert_to_fs(help_msg, help_msg_buf, lengthof(help_msg_buf)));
SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
} return TRUE;
@@ -426,8 +419,8 @@ void ShowInfo(const char *str)
} else {
/* We need to put the text in a separate buffer because the default
* buffer in OTTD2FS might not be large enough (512 chars). */
TCHAR help_msg_buf[8192];
MessageBox(GetActiveWindow(), convert_to_fs(str, help_msg_buf, lengthof(help_msg_buf)), _T("OpenTTD"), MB_ICONINFORMATION | MB_OK);
wchar_t help_msg_buf[8192];
MessageBox(GetActiveWindow(), convert_to_fs(str, help_msg_buf, lengthof(help_msg_buf)), L"OpenTTD", MB_ICONINFORMATION | MB_OK);
}
MyShowCursor(old);
}
@@ -445,11 +438,6 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
CrashLog::InitialiseCrashLog();
#if defined(UNICODE)
/* Check if a win9x user started the win32 version */
if (HasBit(GetVersion(), 31)) usererror("This version of OpenTTD doesn't run on windows 95/98/ME.\nPlease download the win9x binary and try again.");
#endif
/* Convert the command line to UTF-8. We need a dedicated buffer
* for this because argv[] points into this buffer and this needs to
* be available between subsequent calls to FS2OTTD(). */
@@ -480,7 +468,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi
char *getcwd(char *buf, size_t size)
{
TCHAR path[MAX_PATH];
wchar_t path[MAX_PATH];
GetCurrentDirectory(MAX_PATH - 1, path);
convert_from_fs(path, buf, size);
return buf;
@@ -492,9 +480,9 @@ void DetermineBasePaths(const char *exe)
{
extern std::array<std::string, NUM_SEARCHPATHS> _searchpaths;
TCHAR path[MAX_PATH];
wchar_t path[MAX_PATH];
#ifdef WITH_PERSONAL_DIR
if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, path))) {
if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_PERSONAL, nullptr, SHGFP_TYPE_CURRENT, path))) {
std::string tmp(FS2OTTD(path));
AppendPathSeparator(tmp);
tmp += PERSONAL_DIR;
@@ -508,7 +496,7 @@ void DetermineBasePaths(const char *exe)
_searchpaths[SP_PERSONAL_DIR].clear();
}
if (SUCCEEDED(OTTDSHGetFolderPath(nullptr, CSIDL_COMMON_DOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) {
if (SUCCEEDED(SHGetFolderPath(nullptr, CSIDL_COMMON_DOCUMENTS, nullptr, SHGFP_TYPE_CURRENT, path))) {
std::string tmp(FS2OTTD(path));
AppendPathSeparator(tmp);
tmp += PERSONAL_DIR;
@@ -530,8 +518,8 @@ void DetermineBasePaths(const char *exe)
_searchpaths[SP_WORKING_DIR] = cwd_s;
} else {
/* Use the folder of the config file as working directory. */
TCHAR config_dir[MAX_PATH];
_tcsncpy(path, convert_to_fs(_config_file.c_str(), path, lengthof(path)), lengthof(path));
wchar_t config_dir[MAX_PATH];
wcsncpy(path, convert_to_fs(_config_file.c_str(), path, lengthof(path)), lengthof(path));
if (!GetFullPathName(path, lengthof(config_dir), config_dir, nullptr)) {
DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError());
_searchpaths[SP_WORKING_DIR].clear();
@@ -548,8 +536,8 @@ void DetermineBasePaths(const char *exe)
DEBUG(misc, 0, "GetModuleFileName failed (%lu)\n", GetLastError());
_searchpaths[SP_BINARY_DIR].clear();
} else {
TCHAR exec_dir[MAX_PATH];
_tcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path));
wchar_t exec_dir[MAX_PATH];
wcsncpy(path, convert_to_fs(exe, path, lengthof(path)), lengthof(path));
if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, nullptr)) {
DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError());
_searchpaths[SP_BINARY_DIR].clear();
@@ -582,17 +570,6 @@ bool GetClipboardContents(char *buffer, const char *last)
CloseClipboard();
if (out_len == 0) return false;
#if !defined(UNICODE)
} else if (IsClipboardFormatAvailable(CF_TEXT)) {
OpenClipboard(nullptr);
cbuf = GetClipboardData(CF_TEXT);
ptr = (const char*)GlobalLock(cbuf);
strecpy(buffer, FS2OTTD(ptr), last);
GlobalUnlock(cbuf);
CloseClipboard();
#endif /* UNICODE */
} else {
return false;
}
@@ -602,10 +579,7 @@ bool GetClipboardContents(char *buffer, const char *last)
/**
* Convert to OpenTTD's encoding from that of the local environment.
* When the project is built in UNICODE, the system codepage is irrelevant and
* the input string is wide. In ANSI mode, the string is in the
* local codepage which we'll convert to wide-char, and then to UTF-8.
* Convert to OpenTTD's encoding from wide characters.
* OpenTTD internal encoding is UTF8.
* The returned value's contents can only be guaranteed until the next call to
* this function. So if the value is needed for anything else, use convert_from_fs
@@ -614,17 +588,14 @@ bool GetClipboardContents(char *buffer, const char *last)
* @see the current code-page comes from video\win32_v.cpp, event-notification
* WM_INPUTLANGCHANGE
*/
const char *FS2OTTD(const TCHAR *name)
const char *FS2OTTD(const wchar_t *name)
{
TLSData *data = GetTLSData();
return convert_from_fs(name, data->utf8_buf, lengthof(data->utf8_buf));
}
/**
* Convert from OpenTTD's encoding to that of the local environment.
* When the project is built in UNICODE the system codepage is irrelevant and
* the converted string is wide. In ANSI mode, the UTF8 string is converted
* to multi-byte.
* Convert from OpenTTD's encoding to wide characters.
* OpenTTD internal encoding is UTF8.
* The returned value's contents can only be guaranteed until the next call to
* this function. So if the value is needed for anything else, use convert_from_fs
@@ -632,7 +603,7 @@ const char *FS2OTTD(const TCHAR *name)
* @param console_cp convert to the console encoding instead of the normal system encoding.
* @return pointer to the converted string; if failed string is of zero-length
*/
const TCHAR *OTTD2FS(const char *name, bool console_cp)
const wchar_t *OTTD2FS(const char *name, bool console_cp)
{
TLSData *data = GetTLSData();
return convert_to_fs(name, data->system_buf, lengthof(data->system_buf), console_cp);
@@ -641,27 +612,15 @@ const TCHAR *OTTD2FS(const char *name, bool console_cp)
/**
* Convert to OpenTTD's encoding from that of the environment in
* UNICODE. OpenTTD encoding is UTF8, local is wide
* UNICODE. OpenTTD encoding is UTF8, local is wide.
* @param name pointer to a valid string that will be converted
* @param utf8_buf pointer to a valid buffer that will receive the converted string
* @param buflen length in characters of the receiving buffer
* @return pointer to utf8_buf. If conversion fails the string is of zero-length
*/
char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
{
#if defined(UNICODE)
const WCHAR *wide_buf = name;
#else
/* Convert string from the local codepage to UTF-16. */
int wide_len = MultiByteToWideChar(CP_ACP, 0, name, -1, nullptr, 0);
if (wide_len == 0) {
utf8_buf[0] = '\0';
return utf8_buf;
}
WCHAR *wide_buf = AllocaM(WCHAR, wide_len);
MultiByteToWideChar(CP_ACP, 0, name, -1, wide_buf, wide_len);
#endif
const wchar_t *wide_buf = name;
/* Convert UTF-16 string to UTF-8. */
int len = WideCharToMultiByte(CP_UTF8, 0, wide_buf, -1, utf8_buf, (int)buflen, nullptr, nullptr);
@@ -673,7 +632,7 @@ char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
/**
* Convert from OpenTTD's encoding to that of the environment in
* UNICODE. OpenTTD encoding is UTF8, local is wide
* UNICODE. OpenTTD encoding is UTF8, local is wide.
* @param name pointer to a valid string that will be converted
* @param system_buf pointer to a valid wide-char buffer that will receive the
* converted string
@@ -681,93 +640,14 @@ char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen)
* @param console_cp convert to the console encoding instead of the normal system encoding.
* @return pointer to system_buf. If conversion fails the string is of zero-length
*/
TCHAR *convert_to_fs(const char *name, TCHAR *system_buf, size_t buflen, bool console_cp)
wchar_t *convert_to_fs(const char *name, wchar_t *system_buf, size_t buflen, bool console_cp)
{
#if defined(UNICODE)
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, system_buf, (int)buflen);
if (len == 0) system_buf[0] = '\0';
#else
int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, nullptr, 0);
if (len == 0) {
system_buf[0] = '\0';
return system_buf;
}
WCHAR *wide_buf = AllocaM(WCHAR, len);
MultiByteToWideChar(CP_UTF8, 0, name, -1, wide_buf, len);
len = WideCharToMultiByte(console_cp ? CP_OEMCP : CP_ACP, 0, wide_buf, len, system_buf, (int)buflen, nullptr, nullptr);
if (len == 0) system_buf[0] = '\0';
#endif
return system_buf;
}
/**
* Our very own SHGetFolderPath function for support of windows operating
* systems that don't have this function (eg Win9x, etc.). We try using the
* native function, and if that doesn't exist we will try a more crude approach
* of environment variables and hope for the best
*/
HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
{
static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = nullptr;
static bool first_time = true;
/* We only try to load the library one time; if it fails, it fails */
if (first_time) {
#if defined(UNICODE)
# define W(x) x "W"
#else
# define W(x) x "A"
#endif
/* The function lives in shell32.dll for all current Windows versions, but it first started to appear in SHFolder.dll. */
if (!LoadLibraryList((Function*)&SHGetFolderPath, "shell32.dll\0" W("SHGetFolderPath") "\0\0")) {
if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) {
DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from either shell32.dll or SHFolder.dll");
}
}
#undef W
first_time = false;
}
if (SHGetFolderPath != nullptr) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
/* SHGetFolderPath doesn't exist, try a more conservative approach,
* eg environment variables. This is only included for legacy modes
* MSDN says: that 'pszPath' is a "Pointer to a null-terminated string of
* length MAX_PATH which will receive the path" so let's assume that
* Windows 95 with Internet Explorer 5.0, Windows 98 with Internet Explorer 5.0,
* Windows 98 Second Edition (SE), Windows NT 4.0 with Internet Explorer 5.0,
* Windows NT 4.0 with Service Pack 4 (SP4) */
{
DWORD ret;
switch (csidl) {
case CSIDL_FONTS: // Get the system font path, eg %WINDIR%\Fonts
ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH);
if (ret == 0) break;
_tcsncat(pszPath, _T("\\Fonts"), MAX_PATH);
return (HRESULT)0;
case CSIDL_PERSONAL:
case CSIDL_COMMON_DOCUMENTS: {
HKEY key;
if (RegOpenKeyEx(csidl == CSIDL_PERSONAL ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE, REGSTR_PATH_SPECIAL_FOLDERS, 0, KEY_READ, &key) != ERROR_SUCCESS) break;
DWORD len = MAX_PATH;
ret = RegQueryValueEx(key, csidl == CSIDL_PERSONAL ? _T("Personal") : _T("Common Documents"), nullptr, nullptr, (LPBYTE)pszPath, &len);
RegCloseKey(key);
if (ret == ERROR_SUCCESS) return (HRESULT)0;
break;
}
/* XXX - other types to go here when needed... */
}
}
return E_INVALIDARG;
}
/** Determine the current user's locale. */
const char *GetCurrentLocale(const char *)
{
@@ -824,7 +704,7 @@ int OTTDStringCompare(const char *s1, const char *s2)
#endif
if (first_time) {
_CompareStringEx = (PFNCOMPARESTRINGEX)GetProcAddress(GetModuleHandle(_T("Kernel32")), "CompareStringEx");
_CompareStringEx = (PFNCOMPARESTRINGEX)GetProcAddress(GetModuleHandle(L"Kernel32"), "CompareStringEx");
first_time = false;
}
@@ -845,7 +725,7 @@ int OTTDStringCompare(const char *s1, const char *s2)
}
}
TCHAR s1_buf[512], s2_buf[512];
wchar_t s1_buf[512], s2_buf[512];
convert_to_fs(s1, s1_buf, lengthof(s1_buf));
convert_to_fs(s2, s2_buf, lengthof(s2_buf));
@@ -888,6 +768,38 @@ int GetCurrentThreadName(char *str, const char *last)
return 0;
}
/**
* Is the current Windows version Vista or later?
* @return True if the current Windows is Vista or later.
*/
bool IsWindowsVistaOrGreater()
{
typedef BOOL (WINAPI * LPVERIFYVERSIONINFO)(LPOSVERSIONINFOEX, DWORD, DWORDLONG);
typedef ULONGLONG (NTAPI * LPVERSETCONDITIONMASK)(ULONGLONG, DWORD, BYTE);
#ifdef UNICODE
static LPVERIFYVERSIONINFO _VerifyVersionInfo = (LPVERIFYVERSIONINFO)GetProcAddress(GetModuleHandle(_T("Kernel32")), "VerifyVersionInfoW");
#else
static LPVERIFYVERSIONINFO _VerifyVersionInfo = (LPVERIFYVERSIONINFO)GetProcAddress(GetModuleHandle(_T("Kernel32")), "VerifyVersionInfoA");
#endif
static LPVERSETCONDITIONMASK _VerSetConditionMask = (LPVERSETCONDITIONMASK)GetProcAddress(GetModuleHandle(_T("Kernel32")), "VerSetConditionMask");
if (_VerifyVersionInfo != nullptr && _VerSetConditionMask != nullptr) {
OSVERSIONINFOEX osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
DWORDLONG dwlConditionMask = 0;
dwlConditionMask = _VerSetConditionMask(dwlConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
dwlConditionMask = _VerSetConditionMask(dwlConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
dwlConditionMask = _VerSetConditionMask(dwlConditionMask, VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);
osvi.dwMajorVersion = 6;
osvi.dwMinorVersion = 0;
osvi.wServicePackMajor = 0;
return _VerifyVersionInfo(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
} else {
return LOBYTE(GetVersion()) >= 6;
}
}
#ifdef _MSC_VER
/* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
const DWORD MS_VC_EXCEPTION = 0x406D1388;

View File

@@ -16,22 +16,8 @@ bool MyShowCursor(bool show, bool toggle = false);
typedef void (*Function)(int);
bool LoadLibraryList(Function proc[], const char *dll);
char *convert_from_fs(const TCHAR *name, char *utf8_buf, size_t buflen);
TCHAR *convert_to_fs(const char *name, TCHAR *utf16_buf, size_t buflen, bool console_cp = false);
/* Function shortcuts for UTF-8 <> UNICODE conversion. When unicode is not
* defined these macros return the string passed to them, with UNICODE
* they return a pointer to the converted string. These functions use an
* internal buffer of max 512 characters. */
#if defined(UNICODE)
# define MB_TO_WIDE(str) OTTD2FS(str)
# define WIDE_TO_MB(str) FS2OTTD(str)
#else
# define MB_TO_WIDE(str) (str)
# define WIDE_TO_MB(str) (str)
#endif
HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);
char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen);
wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen, bool console_cp = false);
#if defined(__MINGW32__) && !defined(__MINGW64__) && !(_WIN32_IE >= 0x0500)
#define SHGFP_TYPE_CURRENT 0
@@ -39,5 +25,6 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);
void Win32SetCurrentLocaleName(const char *iso_code);
int OTTDStringCompare(const char *s1, const char *s2);
bool IsWindowsVistaOrGreater();
#endif /* WIN32_H */