00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../../stdafx.h"
00013 #include "../../debug.h"
00014 #include "../../gfx_func.h"
00015 #include "../../textbuf_gui.h"
00016 #include "../../fileio_func.h"
00017 #include "../../fios.h"
00018 #include <windows.h>
00019 #include <fcntl.h>
00020 #include <shlobj.h>
00021 #include "win32.h"
00022 #include "../../core/alloc_func.hpp"
00023 #include "../../openttd.h"
00024 #include "../../core/random_func.hpp"
00025 #include "../../string_func.h"
00026 #include "../../crashlog.h"
00027 #include <errno.h>
00028 #include <sys/stat.h>
00029
00030 static bool _has_console;
00031 static bool _cursor_disable = true;
00032 static bool _cursor_visible = true;
00033
00034 bool MyShowCursor(bool show, bool toggle)
00035 {
00036 if (toggle) _cursor_disable = !_cursor_disable;
00037 if (_cursor_disable) return show;
00038 if (_cursor_visible == show) return show;
00039
00040 _cursor_visible = show;
00041 ShowCursor(show);
00042
00043 return !show;
00044 }
00045
00051 bool LoadLibraryList(Function proc[], const char *dll)
00052 {
00053 while (*dll != '\0') {
00054 HMODULE lib;
00055 lib = LoadLibrary(MB_TO_WIDE(dll));
00056
00057 if (lib == NULL) return false;
00058 for (;;) {
00059 FARPROC p;
00060
00061 while (*dll++ != '\0') { }
00062 if (*dll == '\0') break;
00063 #if defined(WINCE)
00064 p = GetProcAddress(lib, MB_TO_WIDE(dll));
00065 #else
00066 p = GetProcAddress(lib, dll);
00067 #endif
00068 if (p == NULL) return false;
00069 *proc++ = (Function)p;
00070 }
00071 dll++;
00072 }
00073 return true;
00074 }
00075
00076 void ShowOSErrorBox(const char *buf, bool system)
00077 {
00078 MyShowCursor(true);
00079 MessageBox(GetActiveWindow(), MB_TO_WIDE(buf), _T("Error!"), MB_ICONSTOP);
00080 }
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091 static DIR _global_dir;
00092 static LONG _global_dir_is_in_use = false;
00093
00094 static inline DIR *dir_calloc()
00095 {
00096 DIR *d;
00097
00098 if (InterlockedExchange(&_global_dir_is_in_use, true) == (LONG)true) {
00099 d = CallocT<DIR>(1);
00100 } else {
00101 d = &_global_dir;
00102 memset(d, 0, sizeof(*d));
00103 }
00104 return d;
00105 }
00106
00107 static inline void dir_free(DIR *d)
00108 {
00109 if (d == &_global_dir) {
00110 _global_dir_is_in_use = (LONG)false;
00111 } else {
00112 free(d);
00113 }
00114 }
00115
00116 DIR *opendir(const TCHAR *path)
00117 {
00118 DIR *d;
00119 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
00120 DWORD fa = GetFileAttributes(path);
00121
00122 if ((fa != INVALID_FILE_ATTRIBUTES) && (fa & FILE_ATTRIBUTE_DIRECTORY)) {
00123 d = dir_calloc();
00124 if (d != NULL) {
00125 TCHAR search_path[MAX_PATH];
00126 bool slash = path[_tcslen(path) - 1] == '\\';
00127
00128
00129
00130 _sntprintf(search_path, lengthof(search_path), _T("%s%s*"), path, slash ? _T("") : _T("\\"));
00131 *lastof(search_path) = '\0';
00132 d->hFind = FindFirstFile(search_path, &d->fd);
00133
00134 if (d->hFind != INVALID_HANDLE_VALUE ||
00135 GetLastError() == ERROR_NO_MORE_FILES) {
00136 d->ent.dir = d;
00137 d->at_first_entry = true;
00138 } else {
00139 dir_free(d);
00140 d = NULL;
00141 }
00142 } else {
00143 errno = ENOMEM;
00144 }
00145 } else {
00146
00147 d = NULL;
00148 errno = ENOENT;
00149 }
00150
00151 SetErrorMode(sem);
00152 return d;
00153 }
00154
00155 struct dirent *readdir(DIR *d)
00156 {
00157 DWORD prev_err = GetLastError();
00158
00159 if (d->at_first_entry) {
00160
00161 if (d->hFind == INVALID_HANDLE_VALUE) return NULL;
00162 d->at_first_entry = false;
00163 } else if (!FindNextFile(d->hFind, &d->fd)) {
00164 if (GetLastError() == ERROR_NO_MORE_FILES) SetLastError(prev_err);
00165 return NULL;
00166 }
00167
00168
00169
00170 d->ent.d_name = d->fd.cFileName;
00171 return &d->ent;
00172 }
00173
00174 int closedir(DIR *d)
00175 {
00176 FindClose(d->hFind);
00177 dir_free(d);
00178 return 0;
00179 }
00180
00181 bool FiosIsRoot(const char *file)
00182 {
00183 return file[3] == '\0';
00184 }
00185
00186 void FiosGetDrives()
00187 {
00188 #if defined(WINCE)
00189
00190 FiosItem *fios = _fios_items.Append();
00191 fios->type = FIOS_TYPE_DRIVE;
00192 fios->mtime = 0;
00193 snprintf(fios->name, lengthof(fios->name), PATHSEP "");
00194 strecpy(fios->title, fios->name, lastof(fios->title));
00195 #else
00196 TCHAR drives[256];
00197 const TCHAR *s;
00198
00199 GetLogicalDriveStrings(lengthof(drives), drives);
00200 for (s = drives; *s != '\0';) {
00201 FiosItem *fios = _fios_items.Append();
00202 fios->type = FIOS_TYPE_DRIVE;
00203 fios->mtime = 0;
00204 snprintf(fios->name, lengthof(fios->name), "%c:", s[0] & 0xFF);
00205 strecpy(fios->title, fios->name, lastof(fios->title));
00206 while (*s++ != '\0') { }
00207 }
00208 #endif
00209 }
00210
00211 bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb)
00212 {
00213
00214 static const int64 posix_epoch_hns = 0x019DB1DED53E8000LL;
00215 const WIN32_FIND_DATA *fd = &ent->dir->fd;
00216
00217 sb->st_size = ((uint64) fd->nFileSizeHigh << 32) + fd->nFileSizeLow;
00218
00219
00220
00221
00222
00223 sb->st_mtime = (time_t)((*(uint64*)&fd->ftLastWriteTime - posix_epoch_hns) / 1E7);
00224 sb->st_mode = (fd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)? S_IFDIR : S_IFREG;
00225
00226 return true;
00227 }
00228
00229 bool FiosIsHiddenFile(const struct dirent *ent)
00230 {
00231 return (ent->dir->fd.dwFileAttributes & (FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM)) != 0;
00232 }
00233
00234 bool FiosGetDiskFreeSpace(const char *path, uint64 *tot)
00235 {
00236 UINT sem = SetErrorMode(SEM_FAILCRITICALERRORS);
00237 bool retval = false;
00238 TCHAR root[4];
00239 DWORD spc, bps, nfc, tnc;
00240
00241 _sntprintf(root, lengthof(root), _T("%c:") _T(PATHSEP), path[0]);
00242 if (tot != NULL && GetDiskFreeSpace(root, &spc, &bps, &nfc, &tnc)) {
00243 *tot = ((spc * bps) * (uint64)nfc);
00244 retval = true;
00245 }
00246
00247 SetErrorMode(sem);
00248 return retval;
00249 }
00250
00251 static int ParseCommandLine(char *line, char **argv, int max_argc)
00252 {
00253 int n = 0;
00254
00255 do {
00256
00257 while (*line == ' ' || *line == '\t') line++;
00258
00259
00260 if (*line == '\0') break;
00261
00262
00263 if (*line == '"') {
00264 argv[n++] = ++line;
00265 while (*line != '"') {
00266 if (*line == '\0') return n;
00267 line++;
00268 }
00269 } else {
00270 argv[n++] = line;
00271 while (*line != ' ' && *line != '\t') {
00272 if (*line == '\0') return n;
00273 line++;
00274 }
00275 }
00276 *line++ = '\0';
00277 } while (n != max_argc);
00278
00279 return n;
00280 }
00281
00282 void CreateConsole()
00283 {
00284 #if defined(WINCE)
00285
00286 #else
00287 HANDLE hand;
00288 CONSOLE_SCREEN_BUFFER_INFO coninfo;
00289
00290 if (_has_console) return;
00291 _has_console = true;
00292
00293 AllocConsole();
00294
00295 hand = GetStdHandle(STD_OUTPUT_HANDLE);
00296 GetConsoleScreenBufferInfo(hand, &coninfo);
00297 coninfo.dwSize.Y = 500;
00298 SetConsoleScreenBufferSize(hand, coninfo.dwSize);
00299
00300
00301 #if !defined(__CYGWIN__)
00302
00303
00304 int fd = _open_osfhandle((intptr_t)hand, _O_TEXT);
00305 if (fd == -1) {
00306
00307 FreeConsole();
00308 _has_console = false;
00309 _close(fd);
00310 CloseHandle(hand);
00311
00312 ShowInfo("Unable to open an output handle to the console. Check known-bugs.txt for details.");
00313 return;
00314 }
00315
00316 *stdout = *_fdopen(fd, "w");
00317 *stdin = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT), "r" );
00318 *stderr = *_fdopen(_open_osfhandle((intptr_t)GetStdHandle(STD_ERROR_HANDLE), _O_TEXT), "w" );
00319 #else
00320
00321 *stdout = *fdopen(1, "w" );
00322 *stdin = *fdopen(0, "r" );
00323 *stderr = *fdopen(2, "w" );
00324 #endif
00325
00326 setvbuf(stdin, NULL, _IONBF, 0);
00327 setvbuf(stdout, NULL, _IONBF, 0);
00328 setvbuf(stderr, NULL, _IONBF, 0);
00329 #endif
00330 }
00331
00333 static const char *_help_msg;
00334
00336 static INT_PTR CALLBACK HelpDialogFunc(HWND wnd, UINT msg, WPARAM wParam, LPARAM lParam)
00337 {
00338 switch (msg) {
00339 case WM_INITDIALOG: {
00340 char help_msg[8192];
00341 const char *p = _help_msg;
00342 char *q = help_msg;
00343 while (q != lastof(help_msg) && *p != '\0') {
00344 if (*p == '\n') {
00345 *q++ = '\r';
00346 if (q == lastof(help_msg)) {
00347 q[-1] = '\0';
00348 break;
00349 }
00350 }
00351 *q++ = *p++;
00352 }
00353 *q = '\0';
00354 #if defined(UNICODE)
00355
00356
00357 wchar_t help_msgW[8192];
00358 #endif
00359 SetDlgItemText(wnd, 11, MB_TO_WIDE_BUFFER(help_msg, help_msgW, lengthof(help_msgW)));
00360 SendDlgItemMessage(wnd, 11, WM_SETFONT, (WPARAM)GetStockObject(ANSI_FIXED_FONT), FALSE);
00361 } return TRUE;
00362
00363 case WM_COMMAND:
00364 if (wParam == 12) ExitProcess(0);
00365 return TRUE;
00366 case WM_CLOSE:
00367 ExitProcess(0);
00368 }
00369
00370 return FALSE;
00371 }
00372
00373 void ShowInfo(const char *str)
00374 {
00375 if (_has_console) {
00376 fprintf(stderr, "%s\n", str);
00377 } else {
00378 bool old;
00379 ReleaseCapture();
00380 _left_button_clicked = _left_button_down = false;
00381
00382 old = MyShowCursor(true);
00383 if (strlen(str) > 2048) {
00384
00385
00386
00387 _help_msg = str;
00388 DialogBox(GetModuleHandle(NULL), MAKEINTRESOURCE(101), NULL, HelpDialogFunc);
00389 } else {
00390 #if defined(UNICODE)
00391
00392
00393 wchar_t help_msgW[8192];
00394 #endif
00395 MessageBox(GetActiveWindow(), MB_TO_WIDE_BUFFER(str, help_msgW, lengthof(help_msgW)), _T("OpenTTD"), MB_ICONINFORMATION | MB_OK);
00396 }
00397 MyShowCursor(old);
00398 }
00399 }
00400
00401 #if defined(WINCE)
00402 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
00403 #else
00404 int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
00405 #endif
00406 {
00407 int argc;
00408 char *argv[64];
00409 char *cmdline;
00410
00411 #if !defined(UNICODE)
00412 _codepage = GetACP();
00413 #endif
00414
00415 CrashLog::InitialiseCrashLog();
00416
00417 #if defined(UNICODE)
00418
00419 #if !defined(WINCE)
00420
00421 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.");
00422 #endif
00423
00424
00425
00426
00427 char cmdlinebuf[MAX_PATH];
00428 #endif
00429
00430 cmdline = WIDE_TO_MB_BUFFER(GetCommandLine(), cmdlinebuf, lengthof(cmdlinebuf));
00431
00432 #if defined(_DEBUG)
00433 CreateConsole();
00434 #endif
00435
00436 #if !defined(WINCE)
00437 _set_error_mode(_OUT_TO_MSGBOX);
00438 #endif
00439
00440
00441 SetRandomSeed(GetTickCount());
00442
00443 argc = ParseCommandLine(cmdline, argv, lengthof(argv));
00444
00445 ttd_main(argc, argv);
00446 return 0;
00447 }
00448
00449 #if defined(WINCE)
00450 void GetCurrentDirectoryW(int length, wchar_t *path)
00451 {
00452
00453 GetModuleFileName(NULL, path, length);
00454
00455
00456 wchar_t *pDest = wcsrchr(path, '\\');
00457 if (pDest != NULL) {
00458 int result = pDest - path + 1;
00459 path[result] = '\0';
00460 }
00461 }
00462 #endif
00463
00464 char *getcwd(char *buf, size_t size)
00465 {
00466 #if defined(WINCE)
00467 TCHAR path[MAX_PATH];
00468 GetModuleFileName(NULL, path, MAX_PATH);
00469 convert_from_fs(path, buf, size);
00470
00471 char *p = strrchr(buf, '\\');
00472 if (p != NULL) *p = '\0';
00473 #elif defined(UNICODE)
00474 TCHAR path[MAX_PATH];
00475 GetCurrentDirectory(MAX_PATH - 1, path);
00476 convert_from_fs(path, buf, size);
00477 #else
00478 GetCurrentDirectory(size, buf);
00479 #endif
00480 return buf;
00481 }
00482
00483
00484 void DetermineBasePaths(const char *exe)
00485 {
00486 char tmp[MAX_PATH];
00487 TCHAR path[MAX_PATH];
00488 #ifdef WITH_PERSONAL_DIR
00489 SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path);
00490 strecpy(tmp, WIDE_TO_MB_BUFFER(path, tmp, lengthof(tmp)), lastof(tmp));
00491 AppendPathSeparator(tmp, MAX_PATH);
00492 ttd_strlcat(tmp, PERSONAL_DIR, MAX_PATH);
00493 AppendPathSeparator(tmp, MAX_PATH);
00494 _searchpaths[SP_PERSONAL_DIR] = strdup(tmp);
00495
00496 SHGetFolderPath(NULL, CSIDL_COMMON_DOCUMENTS, NULL, SHGFP_TYPE_CURRENT, path);
00497 strecpy(tmp, WIDE_TO_MB_BUFFER(path, tmp, lengthof(tmp)), lastof(tmp));
00498 AppendPathSeparator(tmp, MAX_PATH);
00499 ttd_strlcat(tmp, PERSONAL_DIR, MAX_PATH);
00500 AppendPathSeparator(tmp, MAX_PATH);
00501 _searchpaths[SP_SHARED_DIR] = strdup(tmp);
00502 #else
00503 _searchpaths[SP_PERSONAL_DIR] = NULL;
00504 _searchpaths[SP_SHARED_DIR] = NULL;
00505 #endif
00506
00507
00508 getcwd(tmp, lengthof(tmp));
00509 AppendPathSeparator(tmp, MAX_PATH);
00510 _searchpaths[SP_WORKING_DIR] = strdup(tmp);
00511
00512 if (!GetModuleFileName(NULL, path, lengthof(path))) {
00513 DEBUG(misc, 0, "GetModuleFileName failed (%lu)\n", GetLastError());
00514 _searchpaths[SP_BINARY_DIR] = NULL;
00515 } else {
00516 TCHAR exec_dir[MAX_PATH];
00517 _tcsncpy(path, MB_TO_WIDE_BUFFER(exe, path, lengthof(path)), lengthof(path));
00518 if (!GetFullPathName(path, lengthof(exec_dir), exec_dir, NULL)) {
00519 DEBUG(misc, 0, "GetFullPathName failed (%lu)\n", GetLastError());
00520 _searchpaths[SP_BINARY_DIR] = NULL;
00521 } else {
00522 strecpy(tmp, WIDE_TO_MB_BUFFER(exec_dir, tmp, lengthof(tmp)), lastof(tmp));
00523 char *s = strrchr(tmp, PATHSEPCHAR);
00524 *(s + 1) = '\0';
00525 _searchpaths[SP_BINARY_DIR] = strdup(tmp);
00526 }
00527 }
00528
00529 _searchpaths[SP_INSTALLATION_DIR] = NULL;
00530 _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
00531 }
00532
00533
00534 bool GetClipboardContents(char *buffer, size_t buff_len)
00535 {
00536 HGLOBAL cbuf;
00537 const char *ptr;
00538
00539 if (IsClipboardFormatAvailable(CF_UNICODETEXT)) {
00540 OpenClipboard(NULL);
00541 cbuf = GetClipboardData(CF_UNICODETEXT);
00542
00543 ptr = (const char*)GlobalLock(cbuf);
00544 const char *ret = convert_from_fs((wchar_t*)ptr, buffer, buff_len);
00545 GlobalUnlock(cbuf);
00546 CloseClipboard();
00547
00548 if (*ret == '\0') return false;
00549 #if !defined(UNICODE)
00550 } else if (IsClipboardFormatAvailable(CF_TEXT)) {
00551 OpenClipboard(NULL);
00552 cbuf = GetClipboardData(CF_TEXT);
00553
00554 ptr = (const char*)GlobalLock(cbuf);
00555 ttd_strlcpy(buffer, FS2OTTD(ptr), buff_len);
00556
00557 GlobalUnlock(cbuf);
00558 CloseClipboard();
00559 #endif
00560 } else {
00561 return false;
00562 }
00563
00564 return true;
00565 }
00566
00567
00568 void CSleep(int milliseconds)
00569 {
00570 Sleep(milliseconds);
00571 }
00572
00573
00587 const char *FS2OTTD(const TCHAR *name)
00588 {
00589 static char utf8_buf[512];
00590 #if defined(UNICODE)
00591 return convert_from_fs(name, utf8_buf, lengthof(utf8_buf));
00592 #else
00593 char *s = utf8_buf;
00594
00595 for (; *name != '\0'; name++) {
00596 wchar_t w;
00597 int len = MultiByteToWideChar(_codepage, 0, name, 1, &w, 1);
00598 if (len != 1) {
00599 DEBUG(misc, 0, "[utf8] M2W error converting '%c'. Errno %lu", *name, GetLastError());
00600 continue;
00601 }
00602
00603 if (s + Utf8CharLen(w) >= lastof(utf8_buf)) break;
00604 s += Utf8Encode(s, w);
00605 }
00606
00607 *s = '\0';
00608 return utf8_buf;
00609 #endif
00610 }
00611
00625 const TCHAR *OTTD2FS(const char *name)
00626 {
00627 static TCHAR system_buf[512];
00628 #if defined(UNICODE)
00629 return convert_to_fs(name, system_buf, lengthof(system_buf));
00630 #else
00631 char *s = system_buf;
00632
00633 for (WChar c; (c = Utf8Consume(&name)) != '\0';) {
00634 if (s >= lastof(system_buf)) break;
00635
00636 char mb;
00637 int len = WideCharToMultiByte(_codepage, 0, (wchar_t*)&c, 1, &mb, 1, NULL, NULL);
00638 if (len != 1) {
00639 DEBUG(misc, 0, "[utf8] W2M error converting '0x%X'. Errno %lu", c, GetLastError());
00640 continue;
00641 }
00642
00643 *s++ = mb;
00644 }
00645
00646 *s = '\0';
00647 return system_buf;
00648 #endif
00649 }
00650
00651
00660 char *convert_from_fs(const wchar_t *name, char *utf8_buf, size_t buflen)
00661 {
00662 int len = WideCharToMultiByte(CP_UTF8, 0, name, -1, utf8_buf, (int)buflen, NULL, NULL);
00663 if (len == 0) {
00664 DEBUG(misc, 0, "[utf8] W2M error converting wide-string. Errno %lu", GetLastError());
00665 utf8_buf[0] = '\0';
00666 }
00667
00668 return utf8_buf;
00669 }
00670
00671
00681 wchar_t *convert_to_fs(const char *name, wchar_t *utf16_buf, size_t buflen)
00682 {
00683 int len = MultiByteToWideChar(CP_UTF8, 0, name, -1, utf16_buf, (int)buflen);
00684 if (len == 0) {
00685 DEBUG(misc, 0, "[utf8] M2W error converting '%s'. Errno %lu", name, GetLastError());
00686 utf16_buf[0] = '\0';
00687 }
00688
00689 return utf16_buf;
00690 }
00691
00698 HRESULT OTTDSHGetFolderPath(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPTSTR pszPath)
00699 {
00700 static HRESULT (WINAPI *SHGetFolderPath)(HWND, int, HANDLE, DWORD, LPTSTR) = NULL;
00701 static bool first_time = true;
00702
00703
00704 if (first_time) {
00705 #if defined(UNICODE)
00706 # define W(x) x "W"
00707 #else
00708 # define W(x) x "A"
00709 #endif
00710 if (!LoadLibraryList((Function*)&SHGetFolderPath, "SHFolder.dll\0" W("SHGetFolderPath") "\0\0")) {
00711 DEBUG(misc, 0, "Unable to load " W("SHGetFolderPath") "from SHFolder.dll");
00712 }
00713 #undef W
00714 first_time = false;
00715 }
00716
00717 if (SHGetFolderPath != NULL) return SHGetFolderPath(hwnd, csidl, hToken, dwFlags, pszPath);
00718
00719
00720
00721
00722
00723
00724
00725
00726 {
00727 DWORD ret;
00728 switch (csidl) {
00729 case CSIDL_FONTS:
00730 ret = GetEnvironmentVariable(_T("WINDIR"), pszPath, MAX_PATH);
00731 if (ret == 0) break;
00732 _tcsncat(pszPath, _T("\\Fonts"), MAX_PATH);
00733
00734 return (HRESULT)0;
00735
00736
00737 }
00738 }
00739
00740 return E_INVALIDARG;
00741 }
00742
00744 const char *GetCurrentLocale(const char *)
00745 {
00746 char lang[9], country[9];
00747 if (GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO639LANGNAME, lang, lengthof(lang)) == 0 ||
00748 GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SISO3166CTRYNAME, country, lengthof(country)) == 0) {
00749
00750 return NULL;
00751 }
00752
00753 static char retbuf[6] = {lang[0], lang[1], '_', country[0], country[1], 0};
00754 return retbuf;
00755 }
00756
00757 uint GetCPUCoreCount()
00758 {
00759 SYSTEM_INFO info;
00760
00761 GetSystemInfo(&info);
00762 return info.dwNumberOfProcessors;
00763 }