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