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