From e0561dbded57f195e7842cf69764e3ee2c3a71da Mon Sep 17 00:00:00 2001 From: Niels Martin Hansen Date: Sun, 21 Feb 2021 17:03:19 +0100 Subject: Fix #8713: Change OTTD2FS and FS2OTTD to return string objects instead of static buffers --- src/debug.cpp | 2 +- src/fileio.cpp | 14 +++++----- src/fileio_func.h | 2 +- src/fios.cpp | 4 +-- src/ini.cpp | 6 ++--- src/music/cocoa_m.cpp | 4 +-- src/music/dmusic.cpp | 4 +-- src/network/core/address.cpp | 2 +- src/os/os2/os2.cpp | 3 --- src/os/unix/unix.cpp | 21 +++++++-------- src/os/windows/crashlog_win.cpp | 35 ++++++++++++++---------- src/os/windows/font_win32.cpp | 11 ++++---- src/os/windows/font_win32.h | 3 ++- src/os/windows/win32.cpp | 60 ++++++++++++++++++++++------------------- src/stdafx.h | 26 +++++++++--------- src/strings.cpp | 6 ++--- src/video/win32_v.cpp | 4 +-- 17 files changed, 108 insertions(+), 99 deletions(-) diff --git a/src/debug.cpp b/src/debug.cpp index 034af755f..eb8dc5d4f 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -134,7 +134,7 @@ static void debug_print(const char *dbg, const char *buf) #if defined(_WIN32) wchar_t system_buf[512]; convert_to_fs(buffer, system_buf, lengthof(system_buf), true); - _fputts(system_buf, stderr); + fputws(system_buf, stderr); #else fputs(buffer, stderr); #endif diff --git a/src/fileio.cpp b/src/fileio.cpp index 6b33f8aa2..f2a2b14f3 100644 --- a/src/fileio.cpp +++ b/src/fileio.cpp @@ -279,7 +279,7 @@ bool FioCheckFileExists(const std::string &filename, Subdirectory subdir) */ bool FileExists(const std::string &filename) { - return access(OTTD2FS(filename.c_str()), 0) == 0; + return access(OTTD2FS(filename).c_str(), 0) == 0; } /** @@ -358,7 +358,7 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc } #if defined(_WIN32) - if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf.c_str())) == INVALID_FILE_ATTRIBUTES) return nullptr; + if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf).c_str()) == INVALID_FILE_ATTRIBUTES) return nullptr; #endif f = fopen(buf.c_str(), mode); @@ -506,11 +506,11 @@ void FioCreateDirectory(const std::string &name) /* Ignore directory creation errors; they'll surface later on, and most * of the time they are 'directory already exists' errors anyhow. */ #if defined(_WIN32) - CreateDirectory(OTTD2FS(name.c_str()), nullptr); + CreateDirectory(OTTD2FS(name).c_str(), nullptr); #elif defined(OS2) && !defined(__INNOTEK_LIBC__) - mkdir(OTTD2FS(name.c_str())); + mkdir(OTTD2FS(name).c_str()); #else - mkdir(OTTD2FS(name.c_str()), 0755); + mkdir(OTTD2FS(name).c_str(), 0755); #endif } @@ -1315,7 +1315,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s if (path == nullptr || (dir = ttd_opendir(path)) == nullptr) return 0; while ((dirent = readdir(dir)) != nullptr) { - const char *d_name = FS2OTTD(dirent->d_name); + std::string d_name = FS2OTTD(dirent->d_name); if (!FiosIsValidFile(path, dirent, &sb)) continue; @@ -1325,7 +1325,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s if (S_ISDIR(sb.st_mode)) { /* Directory */ if (!recursive) continue; - if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue; + if (d_name == "." || d_name == "..") continue; AppendPathSeparator(filename); num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive); } else if (S_ISREG(sb.st_mode)) { diff --git a/src/fileio_func.h b/src/fileio_func.h index 6dbaea897..142835650 100644 --- a/src/fileio_func.h +++ b/src/fileio_func.h @@ -132,7 +132,7 @@ int closedir(DIR *d); */ static inline DIR *ttd_opendir(const char *path) { - return opendir(OTTD2FS(path)); + return opendir(OTTD2FS(path).c_str()); } diff --git a/src/fios.cpp b/src/fios.cpp index b48bc2108..b68da08f8 100644 --- a/src/fios.cpp +++ b/src/fios.cpp @@ -309,7 +309,7 @@ bool FiosFileScanner::AddFile(const std::string &filename, size_t basepath_lengt FiosItem *fios = file_list.Append(); #ifdef _WIN32 // Retrieve the file modified date using GetFileTime rather than stat to work around an obscure MSVC bug that affects Windows XP - HANDLE fh = CreateFile(OTTD2FS(filename.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); + HANDLE fh = CreateFile(OTTD2FS(filename).c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr); if (fh != INVALID_HANDLE_VALUE) { FILETIME ft; @@ -384,7 +384,7 @@ static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *c /* Show subdirectories */ if ((dir = ttd_opendir(_fios_path->c_str())) != nullptr) { while ((dirent = readdir(dir)) != nullptr) { - strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name)); + strecpy(d_name, FS2OTTD(dirent->d_name).c_str(), lastof(d_name)); /* found file must be directory, but not '.' or '..' */ if (FiosIsValidFile(_fios_path->c_str(), dirent, &sb) && S_ISDIR(sb.st_mode) && diff --git a/src/ini.cpp b/src/ini.cpp index 4988c778e..a5045b715 100644 --- a/src/ini.cpp +++ b/src/ini.cpp @@ -53,7 +53,7 @@ bool IniFile::SaveToDisk(const std::string &filename) std::string file_new{ filename }; file_new.append(".new"); - std::ofstream os(OTTD2FS(file_new.c_str())); + std::ofstream os(OTTD2FS(file_new)); if (os.fail()) return false; for (const IniGroup *group = this->group; group != nullptr; group = group->next) { @@ -94,8 +94,8 @@ bool IniFile::SaveToDisk(const std::string &filename) #if defined(_WIN32) /* Allocate space for one more \0 character. */ wchar_t tfilename[MAX_PATH + 1], tfile_new[MAX_PATH + 1]; - wcsncpy(tfilename, OTTD2FS(filename.c_str()), MAX_PATH); - wcsncpy(tfile_new, OTTD2FS(file_new.c_str()), MAX_PATH); + wcsncpy(tfilename, OTTD2FS(filename).c_str(), MAX_PATH); + wcsncpy(tfile_new, OTTD2FS(file_new).c_str(), MAX_PATH); /* SHFileOperation wants a double '\0' terminated string. */ tfilename[MAX_PATH - 1] = '\0'; tfile_new[MAX_PATH - 1] = '\0'; diff --git a/src/music/cocoa_m.cpp b/src/music/cocoa_m.cpp index a989cfe76..279e0b38a 100644 --- a/src/music/cocoa_m.cpp +++ b/src/music/cocoa_m.cpp @@ -134,8 +134,8 @@ void MusicDriver_Cocoa::PlaySong(const MusicSongInfo &song) return; } - const char *os_file = OTTD2FS(filename.c_str()); - CFAutoRelease url(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file, strlen(os_file), false)); + std::string os_file = OTTD2FS(filename); + CFAutoRelease url(CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (const UInt8*)os_file.c_str(), os_file.length(), false)); if (MusicSequenceFileLoad(_sequence, url.get(), kMusicSequenceFile_AnyType, 0) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file"); diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp index c9447206a..619a20d8b 100644 --- a/src/music/dmusic.cpp +++ b/src/music/dmusic.cpp @@ -430,7 +430,7 @@ bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length) bool DLSFile::LoadFile(const wchar_t *file) { - DEBUG(driver, 2, "DMusic: Try to load DLS file %s", FS2OTTD(file)); + DEBUG(driver, 2, "DMusic: Try to load DLS file %s", FS2OTTD(file).c_str()); FILE *f = _wfopen(file, L"rb"); if (f == nullptr) return false; @@ -881,7 +881,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls) if (!dls_file.LoadFile(path)) return "Can't load GM DLS collection"; } } else { - if (!dls_file.LoadFile(OTTD2FS(user_dls))) return "Can't load GM DLS collection"; + if (!dls_file.LoadFile(OTTD2FS(user_dls).c_str())) return "Can't load GM DLS collection"; } /* Get download port and allocate download IDs. */ diff --git a/src/network/core/address.cpp b/src/network/core/address.cpp index 2e00b5b19..a45bd4914 100644 --- a/src/network/core/address.cpp +++ b/src/network/core/address.cpp @@ -246,7 +246,7 @@ SOCKET NetworkAddress::Resolve(int family, int socktype, int flags, SocketList * if (e != 0) { if (func != ResolveLoopProc) { DEBUG(net, 0, "getaddrinfo for hostname \"%s\", port %s, address family %s and socket type %s failed: %s", - this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e))); + this->hostname, port_name, AddressFamilyAsString(family), SocketTypeAsString(socktype), FS2OTTD(gai_strerror(e)).c_str()); } return INVALID_SOCKET; } diff --git a/src/os/os2/os2.cpp b/src/os/os2/os2.cpp index f1128b0c6..009a3e0ed 100644 --- a/src/os/os2/os2.cpp +++ b/src/os/os2/os2.cpp @@ -203,9 +203,6 @@ bool GetClipboardContents(char *buffer, const char *last) } -const char *FS2OTTD(const char *name) {return name;} -const char *OTTD2FS(const char *name) {return name;} - void OSOpenBrowser(const char *url) { // stub only diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp index 9ef2bc386..57edf1d38 100644 --- a/src/os/unix/unix.cpp +++ b/src/os/unix/unix.cpp @@ -146,9 +146,8 @@ static const char *GetLocalCode() * Convert between locales, which from and which to is set in the calling * functions OTTD2FS() and FS2OTTD(). */ -static const char *convert_tofrom_fs(iconv_t convd, const char *name) +static const char *convert_tofrom_fs(iconv_t convd, const char *name, char *outbuf, size_t outlen) { - static char buf[1024]; /* There are different implementations of iconv. The older ones, * e.g. SUSv2, pass a const pointer, whereas the newer ones, e.g. * IEEE 1003.1 (2004), pass a non-const pointer. */ @@ -158,9 +157,8 @@ static const char *convert_tofrom_fs(iconv_t convd, const char *name) const char *inbuf = name; #endif - char *outbuf = buf; - size_t outlen = sizeof(buf) - 1; size_t inlen = strlen(name); + char *buf = outbuf; strecpy(outbuf, name, outbuf + outlen); @@ -179,9 +177,10 @@ static const char *convert_tofrom_fs(iconv_t convd, const char *name) * @param name pointer to a valid string that will be converted * @return pointer to a new stringbuffer that contains the converted string */ -const char *OTTD2FS(const char *name) +std::string OTTD2FS(const std::string &name) { static iconv_t convd = (iconv_t)(-1); + char buf[1024] = {}; if (convd == (iconv_t)(-1)) { const char *env = GetLocalCode(); @@ -192,17 +191,18 @@ const char *OTTD2FS(const char *name) } } - return convert_tofrom_fs(convd, name); + return convert_tofrom_fs(convd, name.c_str(), buf, lengthof(buf)); } /** * Convert to OpenTTD's encoding from that of the local environment - * @param name pointer to a valid string that will be converted + * @param name valid string that will be converted * @return pointer to a new stringbuffer that contains the converted string */ -const char *FS2OTTD(const char *name) +std::string FS2OTTD(const std::string &name) { static iconv_t convd = (iconv_t)(-1); + char buf[1024] = {}; if (convd == (iconv_t)(-1)) { const char *env = GetLocalCode(); @@ -213,12 +213,9 @@ const char *FS2OTTD(const char *name) } } - return convert_tofrom_fs(convd, name); + return convert_tofrom_fs(convd, name.c_str(), buf, lengthof(buf)); } -#else -const char *FS2OTTD(const char *name) {return name;} -const char *OTTD2FS(const char *name) {return name;} #endif /* WITH_ICONV */ void ShowInfo(const char *str) diff --git a/src/os/windows/crashlog_win.cpp b/src/os/windows/crashlog_win.cpp index 76a05eaa9..9768bcc82 100644 --- a/src/os/windows/crashlog_win.cpp +++ b/src/os/windows/crashlog_win.cpp @@ -189,7 +189,7 @@ static char *PrintModuleInfo(char *output, const char *last, HMODULE mod) GetModuleFileName(mod, buffer, MAX_PATH); GetFileInfo(&dfi, buffer); output += seprintf(output, last, " %-20s handle: %p size: %d crc: %.8X date: %d-%.2d-%.2d %.2d:%.2d:%.2d\n", - FS2OTTD(buffer), + FS2OTTD(buffer).c_str(), mod, dfi.size, dfi.crc32, @@ -501,7 +501,7 @@ char *CrashLogWindows::AppendDecodedStacktrace(char *buffer, const char *last) c MiniDumpWriteDump_t funcMiniDumpWriteDump = (MiniDumpWriteDump_t)GetProcAddress(dbghelp, "MiniDumpWriteDump"); if (funcMiniDumpWriteDump != nullptr) { seprintf(filename, filename_last, "%scrash.dmp", _personal_dir.c_str()); - HANDLE file = CreateFile(OTTD2FS(filename), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); + HANDLE file = CreateFile(OTTD2FS(filename).c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, 0, 0); HANDLE proc = GetCurrentProcess(); DWORD procid = GetCurrentProcessId(); MINIDUMP_EXCEPTION_INFORMATION mdei; @@ -689,7 +689,8 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA switch (msg) { case WM_INITDIALOG: { /* We need to put the crash-log in a separate buffer because the default - * buffer in OTTD2FS is not large enough (512 chars) */ + * buffer in MB_TO_WIDE is not large enough (512 chars) */ + wchar_t filenamebuf[MAX_PATH * 2]; 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; @@ -704,19 +705,23 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA /* Add path to crash.log and crash.dmp (if any) to the crash window text */ 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; + len += wcslen(convert_to_fs(CrashLogWindows::current->crashlog_filename, filenamebuf, lengthof(filenamebuf), false)) + 2; + len += wcslen(convert_to_fs(CrashLogWindows::current->crashdump_filename, filenamebuf, lengthof(filenamebuf), false)) + 2; + len += wcslen(convert_to_fs(CrashLogWindows::current->screenshot_filename, filenamebuf, lengthof(filenamebuf), false)) + 1; wchar_t *text = AllocaM(wchar_t, len); - _snwprintf(text, len, _crash_desc, OTTD2FS(CrashLogWindows::current->crashlog_filename)); - if (OTTD2FS(CrashLogWindows::current->crashdump_filename)[0] != L'\0') { + int printed = _snwprintf(text, len, _crash_desc, convert_to_fs(CrashLogWindows::current->crashlog_filename, filenamebuf, lengthof(filenamebuf), false)); + if (printed < 0 || (size_t)printed > len) { + MessageBox(wnd, L"Catastrophic failure trying to display crash message. Could not perform text formatting.", L"OpenTTD", MB_ICONERROR); + return FALSE; + } + if (convert_to_fs(CrashLogWindows::current->crashdump_filename, filenamebuf, lengthof(filenamebuf), false)[0] != L'\0') { wcscat(text, L"\n"); - wcscat(text, OTTD2FS(CrashLogWindows::current->crashdump_filename)); + wcscat(text, filenamebuf); } - if (OTTD2FS(CrashLogWindows::current->screenshot_filename)[0] != L'\0') { + if (convert_to_fs(CrashLogWindows::current->screenshot_filename, filenamebuf, lengthof(filenamebuf), false)[0] != L'\0') { wcscat(text, L"\n"); - wcscat(text, OTTD2FS(CrashLogWindows::current->screenshot_filename)); + wcscat(text, filenamebuf); } SetDlgItemText(wnd, 10, text); @@ -730,18 +735,20 @@ static INT_PTR CALLBACK CrashDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARA CrashLog::AfterCrashLogCleanup(); ExitProcess(2); case 13: // Emergency save + wchar_t filenamebuf[MAX_PATH * 2]; char filename[MAX_PATH]; if (CrashLogWindows::current->WriteSavegame(filename, lastof(filename))) { - size_t len = wcslen(_save_succeeded) + wcslen(OTTD2FS(filename)) + 1; + convert_to_fs(filename, filenamebuf, lengthof(filenamebuf), false); + size_t len = lengthof(_save_succeeded) + wcslen(filenamebuf) + 1; wchar_t *text = AllocaM(wchar_t, len); - _snwprintf(text, len, _save_succeeded, OTTD2FS(filename)); + _snwprintf(text, len, _save_succeeded, filenamebuf); MessageBox(wnd, text, L"Save successful", MB_ICONINFORMATION); } else { MessageBox(wnd, L"Save failed", L"Save failed", MB_ICONINFORMATION); } break; case 15: // Expand window to show crash-message - _expanded ^= 1; + _expanded = !_expanded; SetWndSize(wnd, _expanded); break; } diff --git a/src/os/windows/font_win32.cpp b/src/os/windows/font_win32.cpp index 9a9dba2f2..1d923ddb2 100644 --- a/src/os/windows/font_win32.cpp +++ b/src/os/windows/font_win32.cpp @@ -83,7 +83,7 @@ FT_Error GetFontByFaceName(const char *font_name, FT_Face *face) } /* Convert font name to file system encoding. */ - wchar_t *font_namep = wcsdup(OTTD2FS(font_name)); + wchar_t *font_namep = wcsdup(OTTD2FS(font_name).c_str()); for (index = 0;; index++) { wchar_t *s; @@ -377,6 +377,7 @@ Win32FontCache::Win32FontCache(FontSize fs, const LOGFONT &logfont, int pixels) { this->dc = CreateCompatibleDC(nullptr); this->SetFontSize(fs, pixels); + this->fontname = FS2OTTD(this->logfont.lfFaceName); } Win32FontCache::~Win32FontCache() @@ -438,7 +439,7 @@ void Win32FontCache::SetFontSize(FontSize fs, int pixels) this->glyph_size.cx = otm->otmTextMetrics.tmMaxCharWidth; this->glyph_size.cy = otm->otmTextMetrics.tmHeight; - DEBUG(freetype, 2, "Loaded font '%s' with size %d", FS2OTTD((LPTSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)), pixels); + DEBUG(freetype, 2, "Loaded font '%s' with size %d", FS2OTTD((LPWSTR)((BYTE *)otm + (ptrdiff_t)otm->otmpFullName)).c_str(), pixels); } /** @@ -541,10 +542,10 @@ void Win32FontCache::ClearFontCache() /* Convert characters outside of the BMP into surrogate pairs. */ WCHAR chars[2]; if (key >= 0x010000U) { - chars[0] = (WCHAR)(((key - 0x010000U) >> 10) + 0xD800); - chars[1] = (WCHAR)(((key - 0x010000U) & 0x3FF) + 0xDC00); + chars[0] = (wchar_t)(((key - 0x010000U) >> 10) + 0xD800); + chars[1] = (wchar_t)(((key - 0x010000U) & 0x3FF) + 0xDC00); } else { - chars[0] = (WCHAR)(key & 0xFFFF); + chars[0] = (wchar_t)(key & 0xFFFF); } WORD glyphs[2] = { 0, 0 }; diff --git a/src/os/windows/font_win32.h b/src/os/windows/font_win32.h index ba413fae5..6ab304c89 100644 --- a/src/os/windows/font_win32.h +++ b/src/os/windows/font_win32.h @@ -21,6 +21,7 @@ private: HDC dc = nullptr; ///< Cached GDI device context. HGDIOBJ old_font; ///< Old font selected into the GDI context. SIZE glyph_size; ///< Maximum size of regular glyphs. + std::string fontname; ///< Cached copy of this->logfont.lfFaceName void SetFontSize(FontSize fs, int pixels); @@ -33,7 +34,7 @@ public: ~Win32FontCache(); void ClearFontCache() override; GlyphID MapCharToGlyph(WChar key) override; - const char *GetFontName() override { return FS2OTTD(this->logfont.lfFaceName); } + const char *GetFontName() override { return this->fontname.c_str(); } const void *GetOSHandle() override { return &this->logfont; } }; diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index cfe7d42d9..568876ab1 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -57,7 +57,7 @@ bool LoadLibraryList(Function proc[], const char *dll) { while (*dll != '\0') { HMODULE lib; - lib = LoadLibrary(OTTD2FS(dll)); + lib = LoadLibrary(OTTD2FS(dll).c_str()); if (lib == nullptr) return false; for (;;) { @@ -77,12 +77,12 @@ bool LoadLibraryList(Function proc[], const char *dll) void ShowOSErrorBox(const char *buf, bool system) { MyShowCursor(true); - MessageBox(GetActiveWindow(), OTTD2FS(buf), L"Error!", MB_ICONSTOP | MB_TASKMODAL); + MessageBox(GetActiveWindow(), OTTD2FS(buf).c_str(), L"Error!", MB_ICONSTOP | MB_TASKMODAL); } void OSOpenBrowser(const char *url) { - ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url), nullptr, nullptr, SW_SHOWNORMAL); + ShellExecute(GetActiveWindow(), L"open", OTTD2FS(url).c_str(), nullptr, nullptr, SW_SHOWNORMAL); } /* Code below for windows version of opendir/readdir/closedir copied and @@ -141,14 +141,14 @@ DIR *opendir(const wchar_t *path) if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { d = dir_calloc(); if (d != nullptr) { - wchar_t search_path[MAX_PATH]; + std::wstring search_path = 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 */ - _snwprintf(search_path, lengthof(search_path), L"%s%s*", path, slash ? L"" : L"\\"); - *lastof(search_path) = '\0'; - d->hFind = FindFirstFile(search_path, &d->fd); + if (!slash) search_path += L"\\"; + search_path += L"*"; + d->hFind = FindFirstFile(search_path.c_str(), &d->fd); if (d->hFind != INVALID_HANDLE_VALUE || GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty @@ -246,7 +246,7 @@ bool FiosGetDiskFreeSpace(const char *path, uint64 *tot) UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box ULARGE_INTEGER bytes_free; - bool retval = GetDiskFreeSpaceEx(OTTD2FS(path), &bytes_free, nullptr, nullptr); + bool retval = GetDiskFreeSpaceEx(OTTD2FS(path).c_str(), &bytes_free, nullptr, nullptr); if (retval) *tot = bytes_free.QuadPart; SetErrorMode(sem); // reset previous setting @@ -415,7 +415,7 @@ int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi /* 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(). */ - char *cmdline = stredup(FS2OTTD(GetCommandLine())); + char *cmdline = stredup(FS2OTTD(GetCommandLine()).c_str()); #if defined(_DEBUG) CreateConsole(); @@ -553,34 +553,40 @@ bool GetClipboardContents(char *buffer, const char *last) /** - * Convert to OpenTTD's encoding from wide characters. + * Convert to OpenTTD's encoding from a wide string. * 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 - * @param name pointer to a valid string that will be converted (local, or wide) - * @return pointer to the converted string; if failed string is of zero-length + * @param name valid string that will be converted (local, or wide) + * @return converted string; if failed string is of zero-length * @see the current code-page comes from video\win32_v.cpp, event-notification * WM_INPUTLANGCHANGE */ -const char *FS2OTTD(const wchar_t *name) +std::string FS2OTTD(const std::wstring &name) { - static char utf8_buf[512]; - return convert_from_fs(name, utf8_buf, lengthof(utf8_buf)); + int name_len = (name.length() >= INT_MAX) ? INT_MAX : (int)name.length(); + int len = WideCharToMultiByte(CP_UTF8, 0, name.c_str(), name_len, nullptr, 0, nullptr, nullptr); + if (len <= 0) return std::string(); + char *utf8_buf = AllocaM(char, len + 1); + utf8_buf[len] = '\0'; + WideCharToMultiByte(CP_UTF8, 0, name.c_str(), name_len, utf8_buf, len, nullptr, nullptr); + return std::string(utf8_buf, static_cast(len)); } /** - * Convert from OpenTTD's encoding to wide characters. + * Convert from OpenTTD's encoding to a wide string. * 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 - * @param name pointer to a valid string that will be converted (UTF8) + * @param name valid string that will be converted (UTF8) * @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 + * @return converted string; if failed string is of zero-length */ -const wchar_t *OTTD2FS(const char *name, bool console_cp) +std::wstring OTTD2FS(const std::string &name, bool console_cp) { - static wchar_t system_buf[512]; - return convert_to_fs(name, system_buf, lengthof(system_buf), console_cp); + int name_len = (name.length() >= INT_MAX) ? INT_MAX : (int)name.length(); + int len = MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name_len, nullptr, 0); + if (len <= 0) return std::wstring(); + wchar_t *system_buf = AllocaM(wchar_t, len + 1); + system_buf[len] = L'\0'; + MultiByteToWideChar(CP_UTF8, 0, name.c_str(), name_len, system_buf, len); + return std::wstring(system_buf, static_cast(len)); } @@ -594,10 +600,8 @@ const wchar_t *OTTD2FS(const char *name, bool console_cp) */ char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen) { - 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); + int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, nullptr, nullptr); if (len == 0) utf8_buf[0] = '\0'; return utf8_buf; diff --git a/src/stdafx.h b/src/stdafx.h index 42a6106e8..06860f104 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -93,6 +93,7 @@ #include #include #include +#include #ifndef SIZE_MAX # define SIZE_MAX ((size_t)-1) @@ -252,25 +253,26 @@ #endif /* defined(_MSC_VER) */ -/* NOTE: the string returned by these functions is only valid until the next - * call to the same function and is not thread- or reentrancy-safe */ #if !defined(STRGEN) && !defined(SETTINGSGEN) # if defined(_WIN32) char *getcwd(char *buf, size_t size); -# include # include +# include - namespace std { using ::_wfopen; } -# define fopen(file, mode) _wfopen(OTTD2FS(file), _T(mode)) -# define unlink(file) _wunlink(OTTD2FS(file)) +# define fopen(file, mode) _wfopen(OTTD2FS(file).c_str(), _T(mode)) +# define unlink(file) _wunlink(OTTD2FS(file).c_str()) - const char *FS2OTTD(const wchar_t *name); - const wchar_t *OTTD2FS(const char *name, bool console_cp = false); + std::string FS2OTTD(const std::wstring &name); + std::wstring OTTD2FS(const std::string &name, bool console_cp = false); +# elif defined(WITH_ICONV) +# define fopen(file, mode) fopen(OTTD2FS(file).c_str(), mode) + std::string FS2OTTD(const std::string &name); + std::string OTTD2FS(const std::string &name); # else -# define fopen(file, mode) fopen(OTTD2FS(file), mode) - const char *FS2OTTD(const char *name); - const char *OTTD2FS(const char *name); -# endif /* _WIN32 */ + // no override of fopen() since no transformation is required of the filename + template std::string FS2OTTD(T name) { return name; } + template std::string OTTD2FS(T name) { return name; } +# endif /* _WIN32 or WITH_ICONV */ #endif /* STRGEN || SETTINGSGEN */ #if defined(_WIN32) || defined(__OS2__) && !defined(__INNOTEK_LIBC__) diff --git a/src/strings.cpp b/src/strings.cpp index 08e826141..7cbdc3cb0 100644 --- a/src/strings.cpp +++ b/src/strings.cpp @@ -1910,14 +1910,14 @@ static void GetLanguageList(const char *path) if (dir != nullptr) { struct dirent *dirent; while ((dirent = readdir(dir)) != nullptr) { - const char *d_name = FS2OTTD(dirent->d_name); - const char *extension = strrchr(d_name, '.'); + std::string d_name = FS2OTTD(dirent->d_name); + const char *extension = strrchr(d_name.c_str(), '.'); /* Not a language file */ if (extension == nullptr || strcmp(extension, ".lng") != 0) continue; LanguageMetadata lmd; - seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name); + seprintf(lmd.file, lastof(lmd.file), "%s%s", path, d_name.c_str()); /* Check whether the file is of the correct version */ if (!GetLanguageFileHeader(lmd.file, &lmd)) { diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 1d9cd3e2b..1b3476dab 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -214,7 +214,7 @@ bool VideoDriver_Win32Base::MakeWindow(bool full_screen, bool resize) char window_title[64]; seprintf(window_title, lastof(window_title), "OpenTTD %s", _openttd_revision); - this->main_wnd = CreateWindow(L"OTTD", OTTD2FS(window_title), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), this); + this->main_wnd = CreateWindow(L"OTTD", OTTD2FS(window_title).c_str(), style, x, y, w, h, 0, 0, GetModuleHandle(nullptr), this); if (this->main_wnd == nullptr) usererror("CreateWindow failed"); ShowWindow(this->main_wnd, showstyle); } @@ -331,7 +331,7 @@ static LRESULT HandleIMEComposition(HWND hwnd, WPARAM wParam, LPARAM lParam) /* Transmit text to windowing system. */ if (len > 0) { HandleTextInput(nullptr, true); // Clear marked string. - HandleTextInput(FS2OTTD(str)); + HandleTextInput(FS2OTTD(str).c_str()); } SetCompositionPos(hwnd); -- cgit v1.2.3-54-g00ecf