From 2536a14abd95098fa752835dce90db679a557721 Mon Sep 17 00:00:00 2001 From: Darkvater Date: Wed, 7 Mar 2007 18:58:28 +0000 Subject: (svn r9055) -Codechange: Change windows unicode handling and allow a pure non-unicode build to function. Win9x binaries will be possible with mingw/nightly system. --- src/win32.cpp | 155 ++++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 103 insertions(+), 52 deletions(-) (limited to 'src/win32.cpp') diff --git a/src/win32.cpp b/src/win32.cpp index 63f1b26ae..33e5fd964 100644 --- a/src/win32.cpp +++ b/src/win32.cpp @@ -658,23 +658,23 @@ static inline void dir_free(DIR *d) } } -DIR *opendir(const wchar_t *path) +DIR *opendir(const TCHAR *path) { DIR *d; UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS); // disable 'no-disk' message box - DWORD fa = GetFileAttributesW(path); + DWORD fa = GetFileAttributes(path); if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) { d = dir_calloc(); if (d != NULL) { - wchar_t search_path[MAX_PATH]; - bool slash = path[wcslen(path) - 1] == L'\\'; + TCHAR search_path[MAX_PATH]; + bool slash = path[_tcslen(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"\\"); + _sntprintf(search_path, lengthof(search_path), _T("%s%s*"), path, slash ? _T("") : _T("\\")); *lastof(search_path) = '\0'; - d->hFind = FindFirstFileW(search_path, &d->fd); + d->hFind = FindFirstFile(search_path, &d->fd); if (d->hFind != INVALID_HANDLE_VALUE || GetLastError() == ERROR_NO_MORE_FILES) { // the directory is empty @@ -705,7 +705,7 @@ struct dirent *readdir(DIR *d) /* the directory was empty when opened */ if (d->hFind == INVALID_HANDLE_VALUE) return NULL; d->at_first_entry = false; - } else if (!FindNextFileW(d->hFind, &d->fd)) { // determine cause and bail + } else if (!FindNextFile(d->hFind, &d->fd)) { // determine cause and bail if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err); return NULL; } @@ -748,7 +748,7 @@ bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb { // hectonanoseconds between Windows and POSIX epoch static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL; - const WIN32_FIND_DATAW *fd = &ent->dir->fd; + const WIN32_FIND_DATA *fd = &ent->dir->fd; sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow; /* UTC FILETIME to seconds-since-1970 UTC @@ -878,13 +878,7 @@ void ShowInfo(const char *str) int _set_error_mode(int); #endif -#if defined(WINCE) && !defined(_tWinMain) -/* GCC crosscompiler for WINCE doesn't support wide version */ -# define _tWinMain WinMain -#endif /* WINCE */ - -int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, - LPTSTR lpCmdLine, int nCmdShow) +int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { int argc; char *argv[64]; // max 64 command line arguments @@ -947,11 +941,15 @@ void GetCurrentDirectoryW(int length, wchar_t *path) void DeterminePaths() { char *s, *cfg; - wchar_t path[MAX_PATH]; _paths.personal_dir = _paths.game_data_dir = cfg = (char*)malloc(MAX_PATH); - GetCurrentDirectoryW(MAX_PATH - 1, path); +#if defined(UNICODE) + TCHAR path[MAX_PATH]; + GetCurrentDirectory(MAX_PATH - 1, path); convert_from_fs(path, cfg, MAX_PATH); +#else + GetCurrentDirectory(MAX_PATH - 1, cfg); +#endif cfg[0] = toupper(cfg[0]); s = strchr(cfg, '\0'); @@ -972,10 +970,10 @@ void DeterminePaths() _log_file = str_fmt("%sopenttd.log", _paths.personal_dir); // make (auto)save and scenario folder - CreateDirectoryW(OTTD2FS(_paths.save_dir), NULL); - CreateDirectoryW(OTTD2FS(_paths.autosave_dir), NULL); - CreateDirectoryW(OTTD2FS(_paths.scenario_dir), NULL); - CreateDirectoryW(OTTD2FS(_paths.heightmap_dir), NULL); + CreateDirectory(OTTD2FS(_paths.save_dir), NULL); + CreateDirectory(OTTD2FS(_paths.autosave_dir), NULL); + CreateDirectory(OTTD2FS(_paths.scenario_dir), NULL); + CreateDirectory(OTTD2FS(_paths.heightmap_dir), NULL); } /** @@ -1069,39 +1067,85 @@ int64 GetTS() return (__int64)(value * freq); } -/** Convert from OpenTTD's encoding to that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char - * @param name pointer to a valid string that will be converted - * @param utf16_buf pointer to a valid wide-char buffer that will receive the - * converted string - * @param buflen length in wide characters of the receiving buffer - * @return pointer to utf16_buf. If conversion fails the string is of zero-length */ -wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen) + +/** + * 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. + * 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 + * @see the current code-page comes from video\win32_v.cpp, event-notification + * WM_INPUTLANGCHANGE */ +const char *FS2OTTD(const TCHAR *name) { - int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, buflen); - if (len == 0) { - DEBUG(misc, 0, "[utf8] error converting '%s'. Errno %d", name, GetLastError()); - utf16_buf[0] = '\0'; + static char utf8_buf[512]; +#if defined(UNICODE) + return convert_from_fs(name, utf8_buf, lengthof(utf8_buf)); +#else + char *s = utf8_buf; + + for (; *name != '\0'; name++) { + wchar_t w; + int len = MultiByteToWideChar(_codepage, 0, name, 1, &w, 1); + if (len != 1) { + DEBUG(misc, 0, "[utf8] M2W error converting '%c'. Errno %d", *name, GetLastError()); + continue; + } + + if (s + Utf8CharLen(w) >= lastof(utf8_buf)) break; + s += Utf8Encode(s, w); } - return utf16_buf; + *s = '\0'; + return utf8_buf; +#endif /* UNICODE */ } -/** Convert from OpenTTD's encoding to that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char. +/** + * 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. + * 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 - * @return pointer to the converted string; if failed string is of zero-length */ -const wchar_t *OTTD2FS(const char *name) + * @param name pointer to a valid string that will be converted (UTF8) + * @return pointer to the 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 TCHAR *OTTD2FS(const char *name) { - static wchar_t utf16_buf[512]; - return convert_to_fs(name, utf16_buf, lengthof(utf16_buf)); + static TCHAR system_buf[512]; +#if defined(UNICODE) + return convert_to_fs(name, system_buf, lengthof(system_buf)); +#else + char *s = system_buf; + + for (WChar c; (c = Utf8Consume(&name)) != '\0';) { + if (s >= lastof(system_buf)) break; + + char mb; + int len = WideCharToMultiByte(_codepage, 0, (wchar_t*)&c, 1, &mb, 1, NULL, NULL); + if (len != 1) { + DEBUG(misc, 0, "[utf8] W2M error converting '0x%X'. Errno %d", c, GetLastError()); + continue; + } + + *s++ = mb; + } + + *s = '\0'; + return system_buf; +#endif /* UNICODE */ } -/** Convert to OpenTTD's encoding from that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char +/** Convert to OpenTTD's encoding from that of the environment in + * 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 @@ -1110,23 +1154,30 @@ char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen) { int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, buflen, NULL, NULL); if (len == 0) { - DEBUG(misc, 0, "[utf8] error converting wide-string. Errno %d", GetLastError()); + DEBUG(misc, 0, "[utf8] W2M error converting wide-string. Errno %d", GetLastError()); utf8_buf[0] = '\0'; } return utf8_buf; } -/** Convert to OpenTTD's encoding from that of the local environment in - * UNICODE. OpenTTD encoding is UTF8, local is wide-char. - * 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 + +/** Convert from OpenTTD's encoding to that of the environment in + * UNICODE. OpenTTD encoding is UTF8, local is wide * @param name pointer to a valid string that will be converted - * @return pointer to the converted string; if failed string is of zero-length */ -const char *FS2OTTD(const wchar_t *name) + * @param utf16_buf pointer to a valid wide-char buffer that will receive the + * converted string + * @param buflen length in wide characters of the receiving buffer + * @return pointer to utf16_buf. If conversion fails the string is of zero-length */ +wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen) { - static char utf8_buf[512]; - return convert_from_fs(name, utf8_buf, lengthof(utf8_buf)); + int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, buflen); + if (len == 0) { + DEBUG(misc, 0, "[utf8] M2W error converting '%s'. Errno %d", name, GetLastError()); + utf16_buf[0] = '\0'; + } + + return utf16_buf; } /** Our very own SHGetFolderPath function for support of windows operating -- cgit v1.2.3-54-g00ecf