00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "fileio.h"
00008 #include "variables.h"
00009 #include "debug.h"
00010 #include "fios.h"
00011 #include "core/alloc_func.hpp"
00012 #include "core/math_func.hpp"
00013 #include "string_func.h"
00014 #ifdef WIN32
00015 #include <windows.h>
00016 #else
00017 #include <pwd.h>
00018 #include <unistd.h>
00019 #endif
00020 #include <sys/stat.h>
00021
00022
00023
00024
00025
00026 #define FIO_BUFFER_SIZE 512
00027
00028 struct Fio {
00029 byte *buffer, *buffer_end;
00030 uint32 pos;
00031 FILE *cur_fh;
00032 const char *filename;
00033 FILE *handles[MAX_FILE_SLOTS];
00034 byte buffer_start[FIO_BUFFER_SIZE];
00035 const char *filenames[MAX_FILE_SLOTS];
00036 char *shortnames[MAX_FILE_SLOTS];
00037 #if defined(LIMITED_FDS)
00038 uint open_handles;
00039 uint usage_count[MAX_FILE_SLOTS];
00040 #endif
00041 };
00042
00043 static Fio _fio;
00044
00045
00046 uint32 FioGetPos()
00047 {
00048 return _fio.pos + (_fio.buffer - _fio.buffer_start) - FIO_BUFFER_SIZE;
00049 }
00050
00051 const char *FioGetFilename(uint8 slot)
00052 {
00053 return _fio.shortnames[slot];
00054 }
00055
00056 void FioSeekTo(uint32 pos, int mode)
00057 {
00058 if (mode == SEEK_CUR) pos += FioGetPos();
00059 _fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE;
00060 _fio.pos = pos;
00061 fseek(_fio.cur_fh, _fio.pos, SEEK_SET);
00062 }
00063
00064 #if defined(LIMITED_FDS)
00065 static void FioRestoreFile(int slot)
00066 {
00067
00068 if (_fio.handles[slot] == NULL) {
00069 DEBUG(misc, 6, "Restoring file '%s' in slot '%d' from disk", _fio.filenames[slot], slot);
00070 FioOpenFile(slot, _fio.filenames[slot]);
00071 }
00072 _fio.usage_count[slot]++;
00073 }
00074 #endif
00075
00076
00077 void FioSeekToFile(uint8 slot, uint32 pos)
00078 {
00079 FILE *f;
00080 #if defined(LIMITED_FDS)
00081
00082 FioRestoreFile(slot);
00083 #endif
00084 f = _fio.handles[slot];
00085 assert(f != NULL);
00086 _fio.cur_fh = f;
00087 _fio.filename = _fio.filenames[slot];
00088 FioSeekTo(pos, SEEK_SET);
00089 }
00090
00091 byte FioReadByte()
00092 {
00093 if (_fio.buffer == _fio.buffer_end) {
00094 _fio.pos += FIO_BUFFER_SIZE;
00095 fread(_fio.buffer = _fio.buffer_start, 1, FIO_BUFFER_SIZE, _fio.cur_fh);
00096 }
00097 return *_fio.buffer++;
00098 }
00099
00100 void FioSkipBytes(int n)
00101 {
00102 for (;;) {
00103 int m = min(_fio.buffer_end - _fio.buffer, n);
00104 _fio.buffer += m;
00105 n -= m;
00106 if (n == 0) break;
00107 FioReadByte();
00108 n--;
00109 }
00110 }
00111
00112 uint16 FioReadWord()
00113 {
00114 byte b = FioReadByte();
00115 return (FioReadByte() << 8) | b;
00116 }
00117
00118 uint32 FioReadDword()
00119 {
00120 uint b = FioReadWord();
00121 return (FioReadWord() << 16) | b;
00122 }
00123
00124 void FioReadBlock(void *ptr, uint size)
00125 {
00126 FioSeekTo(FioGetPos(), SEEK_SET);
00127 _fio.pos += size;
00128 fread(ptr, 1, size, _fio.cur_fh);
00129 }
00130
00131 static inline void FioCloseFile(int slot)
00132 {
00133 if (_fio.handles[slot] != NULL) {
00134 fclose(_fio.handles[slot]);
00135
00136 free(_fio.shortnames[slot]);
00137 _fio.shortnames[slot] = NULL;
00138
00139 _fio.handles[slot] = NULL;
00140 #if defined(LIMITED_FDS)
00141 _fio.open_handles--;
00142 #endif
00143 }
00144 }
00145
00146 void FioCloseAll()
00147 {
00148 int i;
00149
00150 for (i = 0; i != lengthof(_fio.handles); i++)
00151 FioCloseFile(i);
00152 }
00153
00154 #if defined(LIMITED_FDS)
00155 static void FioFreeHandle()
00156 {
00157
00158 if (_fio.open_handles + 1 == LIMITED_FDS) {
00159 uint i, count;
00160 int slot;
00161
00162 count = UINT_MAX;
00163 slot = -1;
00164
00165 for (i = 0; i < lengthof(_fio.handles); i++) {
00166 if (_fio.handles[i] != NULL && _fio.usage_count[i] < count) {
00167 count = _fio.usage_count[i];
00168 slot = i;
00169 }
00170 }
00171 assert(slot != -1);
00172 DEBUG(misc, 6, "Closing filehandler '%s' in slot '%d' because of fd-limit", _fio.filenames[slot], slot);
00173 FioCloseFile(slot);
00174 }
00175 }
00176 #endif
00177
00178 void FioOpenFile(int slot, const char *filename)
00179 {
00180 FILE *f;
00181
00182 #if defined(LIMITED_FDS)
00183 FioFreeHandle();
00184 #endif
00185 f = FioFOpenFile(filename);
00186 if (f == NULL) error("Cannot open file '%s'", filename);
00187 uint32 pos = ftell(f);
00188
00189 FioCloseFile(slot);
00190 _fio.handles[slot] = f;
00191 _fio.filenames[slot] = filename;
00192
00193
00194 const char *t = strrchr(filename, PATHSEPCHAR);
00195 _fio.shortnames[slot] = strdup(t == NULL ? filename : t);
00196 char *t2 = strrchr(_fio.shortnames[slot], '.');
00197 if (t2 != NULL) *t2 = '\0';
00198 strtolower(_fio.shortnames[slot]);
00199
00200 #if defined(LIMITED_FDS)
00201 _fio.usage_count[slot] = 0;
00202 _fio.open_handles++;
00203 #endif
00204 FioSeekToFile(slot, pos);
00205 }
00206
00207 const char *_subdirs[NUM_SUBDIRS] = {
00208 "",
00209 "save" PATHSEP,
00210 "save" PATHSEP "autosave" PATHSEP,
00211 "scenario" PATHSEP,
00212 "scenario" PATHSEP "heightmap" PATHSEP,
00213 "gm" PATHSEP,
00214 "data" PATHSEP,
00215 "lang" PATHSEP
00216 };
00217
00218 const char *_searchpaths[NUM_SEARCHPATHS];
00219 TarList _tar_list;
00220 TarFileList _tar_filelist;
00221
00228 bool FioCheckFileExists(const char *filename, Subdirectory subdir)
00229 {
00230 FILE *f = FioFOpenFile(filename, "rb", subdir);
00231 if (f == NULL) return false;
00232
00233 FioFCloseFile(f);
00234 return true;
00235 }
00236
00240 void FioFCloseFile(FILE *f)
00241 {
00242 fclose(f);
00243 }
00244
00245 char *FioGetFullPath(char *buf, size_t buflen, Searchpath sp, Subdirectory subdir, const char *filename)
00246 {
00247 assert(subdir < NUM_SUBDIRS);
00248 assert(sp < NUM_SEARCHPATHS);
00249
00250 snprintf(buf, buflen, "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename);
00251 return buf;
00252 }
00253
00254 char *FioFindFullPath(char *buf, size_t buflen, Subdirectory subdir, const char *filename)
00255 {
00256 Searchpath sp;
00257 assert(subdir < NUM_SUBDIRS);
00258
00259 FOR_ALL_SEARCHPATHS(sp) {
00260 FioGetFullPath(buf, buflen, sp, subdir, filename);
00261 if (FileExists(buf)) break;
00262 }
00263
00264 return buf;
00265 }
00266
00267 char *FioAppendDirectory(char *buf, size_t buflen, Searchpath sp, Subdirectory subdir)
00268 {
00269 assert(subdir < NUM_SUBDIRS);
00270 assert(sp < NUM_SEARCHPATHS);
00271
00272 snprintf(buf, buflen, "%s%s", _searchpaths[sp], _subdirs[subdir]);
00273 return buf;
00274 }
00275
00276 char *FioGetDirectory(char *buf, size_t buflen, Subdirectory subdir)
00277 {
00278 Searchpath sp;
00279
00280
00281 FOR_ALL_SEARCHPATHS(sp) {
00282 char *ret = FioAppendDirectory(buf, buflen, sp, subdir);
00283 if (FileExists(buf)) return ret;
00284 }
00285
00286
00287 ttd_strlcpy(buf, _personal_dir, buflen);
00288
00289 return buf;
00290 }
00291
00292 FILE *FioFOpenFileSp(const char *filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize)
00293 {
00294 #if defined(WIN32) && defined(UNICODE)
00295
00296
00297
00298
00299 wchar_t Lmode[5];
00300 MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, lengthof(Lmode));
00301 #endif
00302 FILE *f = NULL;
00303 char buf[MAX_PATH];
00304
00305 if (subdir == NO_DIRECTORY) {
00306 ttd_strlcpy(buf, filename, lengthof(buf));
00307 } else {
00308 snprintf(buf, lengthof(buf), "%s%s%s", _searchpaths[sp], _subdirs[subdir], filename);
00309 }
00310
00311 #if defined(WIN32)
00312 if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf)) == INVALID_FILE_ATTRIBUTES) return NULL;
00313 #endif
00314
00315 f = fopen(buf, mode);
00316 #if !defined(WIN32)
00317 if (f == NULL) {
00318 strtolower(buf + ((subdir == NO_DIRECTORY) ? 0 : strlen(_searchpaths[sp]) - 1));
00319 f = fopen(buf, mode);
00320 }
00321 #endif
00322 if (f != NULL && filesize != NULL) {
00323
00324 fseek(f, 0, SEEK_END);
00325 *filesize = ftell(f);
00326 fseek(f, 0, SEEK_SET);
00327 }
00328 return f;
00329 }
00330
00331 FILE *FioFOpenFileTar(TarFileListEntry *entry, size_t *filesize)
00332 {
00333 FILE *f = fopen(entry->tar_filename, "rb");
00334 assert(f != NULL);
00335
00336 fseek(f, entry->position, SEEK_SET);
00337 if (filesize != NULL) *filesize = entry->size;
00338 return f;
00339 }
00340
00342 FILE *FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize)
00343 {
00344 FILE *f = NULL;
00345 Searchpath sp;
00346
00347 assert(subdir < NUM_SUBDIRS || subdir == NO_DIRECTORY);
00348
00349 FOR_ALL_SEARCHPATHS(sp) {
00350 f = FioFOpenFileSp(filename, mode, sp, subdir, filesize);
00351 if (f != NULL || subdir == NO_DIRECTORY) break;
00352 }
00353
00354
00355 if (f == NULL && subdir == DATA_DIR && mode[0] == 'r') {
00356
00357 char *lcfilename = strdup(filename);
00358 strtolower(lcfilename);
00359 TarFileList::iterator it = _tar_filelist.find(lcfilename);
00360 free(lcfilename);
00361 if (it != _tar_filelist.end()) {
00362 f = FioFOpenFileTar(&((*it).second), filesize);
00363 }
00364 }
00365
00366
00367
00368 if (f == NULL && subdir != NO_DIRECTORY) {
00369 f = FioFOpenFile(filename, mode, NO_DIRECTORY, filesize);
00370 }
00371
00372 return f;
00373 }
00374
00379 void FioCreateDirectory(const char *name)
00380 {
00381 #if defined(WIN32) || defined(WINCE)
00382 CreateDirectory(OTTD2FS(name), NULL);
00383 #elif defined(OS2) && !defined(__INNOTEK_LIBC__)
00384 mkdir(OTTD2FS(name));
00385 #elif defined(__MORPHOS__) || defined(__AMIGAOS__)
00386 char buf[MAX_PATH];
00387 ttd_strlcpy(buf, name, MAX_PATH);
00388
00389 size_t len = strlen(name) - 1;
00390 if (buf[len] == '/') {
00391 buf[len] = '\0';
00392 }
00393
00394 mkdir(OTTD2FS(buf), 0755);
00395 #else
00396 mkdir(OTTD2FS(name), 0755);
00397 #endif
00398 }
00399
00406 void AppendPathSeparator(char *buf, size_t buflen)
00407 {
00408 size_t s = strlen(buf);
00409
00410
00411 if (s != 0 && buf[s - 1] != PATHSEPCHAR && s + 2 < buflen) {
00412 buf[s] = PATHSEPCHAR;
00413 buf[s + 1] = '\0';
00414 }
00415 }
00416
00423 char *BuildWithFullPath(const char *dir)
00424 {
00425 char *dest = MallocT<char>(MAX_PATH);
00426 ttd_strlcpy(dest, dir, MAX_PATH);
00427
00428
00429 const char *s = strchr(dest, PATHSEPCHAR);
00430
00431
00432 if (s == NULL || dest != s) {
00433 getcwd(dest, MAX_PATH);
00434 AppendPathSeparator(dest, MAX_PATH);
00435 ttd_strlcat(dest, dir, MAX_PATH);
00436 }
00437 AppendPathSeparator(dest, MAX_PATH);
00438
00439 return dest;
00440 }
00441
00442 static bool TarListAddFile(const char *filename)
00443 {
00444
00445 typedef struct TarHeader {
00446 char name[100];
00447 char mode[8];
00448 char uid[8];
00449 char gid[8];
00450 char size[12];
00451 char mtime[12];
00452 char chksum[8];
00453 char typeflag;
00454 char linkname[100];
00455 char magic[6];
00456 char version[2];
00457 char uname[32];
00458 char gname[32];
00459 char devmajor[8];
00460 char devminor[8];
00461 char prefix[155];
00462
00463 char unused[12];
00464 } TarHeader;
00465
00466
00467 TarList::iterator it = _tar_list.find(filename);
00468 if (it != _tar_list.end()) return false;
00469
00470 FILE *f = fopen(filename, "rb");
00471 assert(f != NULL);
00472
00473 const char *dupped_filename = strdup(filename);
00474 _tar_list[filename].filename = dupped_filename;
00475
00476 TarHeader th;
00477 char buf[sizeof(th.name) + 1], *end;
00478 char name[sizeof(th.prefix) + 1 + sizeof(th.name) + 1];
00479 int num = 0, pos = 0;
00480
00481
00482 char empty[512];
00483 memset(&empty[0], 0, sizeof(empty));
00484
00485 for (;;) {
00486 size_t num_bytes_read = fread(&th, 1, 512, f);
00487 if (num_bytes_read != 512) break;
00488 pos += num_bytes_read;
00489
00490
00491 if (strncmp(th.magic, "ustar", 5) != 0 && memcmp(&th.magic, &empty[0], 512 - offsetof(TarHeader, magic)) != 0) {
00492
00493 if (memcmp(&th, &empty[0], 512) == 0) continue;
00494
00495 DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename);
00496 return false;
00497 }
00498
00499 name[0] = '\0';
00500 int len = 0;
00501
00502
00503 if (th.prefix[0] != '\0') {
00504 memcpy(name, th.prefix, sizeof(th.prefix));
00505 name[sizeof(th.prefix)] = '\0';
00506 len = strlen(name);
00507 name[len] = PATHSEPCHAR;
00508 len++;
00509 }
00510
00511
00512 memcpy(&name[len], th.name, sizeof(th.name));
00513 name[len + sizeof(th.name)] = '\0';
00514
00515
00516 memcpy(buf, th.size, sizeof(th.size));
00517 buf[sizeof(th.size)] = '\0';
00518 int skip = strtol(buf, &end, 8);
00519
00520
00521 if (skip == 0) continue;
00522
00523
00524 TarFileListEntry entry;
00525 entry.tar_filename = dupped_filename;
00526 entry.size = skip;
00527 entry.position = pos;
00528
00529 strtolower(name);
00530
00531
00532 #if (PATHSEPCHAR != '/')
00533 for (char *n = name; *n != '\0'; n++) if (*n == '/') *n = PATHSEPCHAR;
00534 #endif
00535
00536 DEBUG(misc, 6, "Found file in tar: %s (%d bytes, %d offset)", name, skip, pos);
00537 if (_tar_filelist.insert(TarFileList::value_type(name, entry)).second) num++;
00538
00539
00540 skip = Align(skip, 512);
00541 fseek(f, skip, SEEK_CUR);
00542 pos += skip;
00543 }
00544
00545 DEBUG(misc, 1, "Found tar '%s' with %d new files", filename, num);
00546 fclose(f);
00547
00548 return true;
00549 }
00550
00551 static int ScanPathForTarFiles(const char *path, int basepath_length)
00552 {
00553 extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
00554
00555 uint num = 0;
00556 struct stat sb;
00557 struct dirent *dirent;
00558 DIR *dir;
00559
00560 if (path == NULL || (dir = ttd_opendir(path)) == NULL) return 0;
00561
00562 while ((dirent = readdir(dir)) != NULL) {
00563 const char *d_name = FS2OTTD(dirent->d_name);
00564 char filename[MAX_PATH];
00565
00566 if (!FiosIsValidFile(path, dirent, &sb)) continue;
00567
00568 snprintf(filename, lengthof(filename), "%s%s", path, d_name);
00569
00570 if (sb.st_mode & S_IFDIR) {
00571
00572 if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
00573 AppendPathSeparator(filename, lengthof(filename));
00574 num += ScanPathForTarFiles(filename, basepath_length);
00575 } else if (sb.st_mode & S_IFREG) {
00576
00577 char *ext = strrchr(filename, '.');
00578
00579
00580 if (ext == NULL) continue;
00581 if (strcasecmp(ext, ".tar") != 0) continue;
00582
00583 if (TarListAddFile(filename)) num++;
00584 }
00585 }
00586
00587 closedir(dir);
00588 return num;
00589 }
00590
00591 void ScanForTarFiles()
00592 {
00593 Searchpath sp;
00594 char path[MAX_PATH];
00595 uint num = 0;
00596
00597 DEBUG(misc, 1, "Scanning for tars");
00598 FOR_ALL_SEARCHPATHS(sp) {
00599 FioAppendDirectory(path, MAX_PATH, sp, DATA_DIR);
00600 num += ScanPathForTarFiles(path, strlen(path));
00601 }
00602 DEBUG(misc, 1, "Scan complete, found %d files", num);
00603 }
00604
00605 #if defined(WIN32) || defined(WINCE)
00606
00611 extern void DetermineBasePaths(const char *exe);
00612 #else
00613
00621 void ChangeWorkingDirectory(const char *exe)
00622 {
00623 #ifdef WITH_COCOA
00624 char *app_bundle = strchr(exe, '.');
00625 while (app_bundle != NULL && strncasecmp(app_bundle, ".app", 4) != 0) app_bundle = strchr(&app_bundle[1], '.');
00626
00627 if (app_bundle != NULL) app_bundle[0] = '\0';
00628 #endif
00629 char *s = strrchr(exe, PATHSEPCHAR);
00630 if (s != NULL) {
00631 *s = '\0';
00632 chdir(exe);
00633 *s = PATHSEPCHAR;
00634 }
00635 #ifdef WITH_COCOA
00636 if (app_bundle != NULL) app_bundle[0] = '.';
00637 #endif
00638 }
00639
00644 void DetermineBasePaths(const char *exe)
00645 {
00646 char tmp[MAX_PATH];
00647 #if defined(__MORPHOS__) || defined(__AMIGA__) || !defined(WITH_PERSONAL_DIR)
00648 _searchpaths[SP_PERSONAL_DIR] = NULL;
00649 #else
00650 const char *homedir = getenv("HOME");
00651
00652 if (homedir == NULL) {
00653 const struct passwd *pw = getpwuid(getuid());
00654 homedir = (pw == NULL) ? "" : pw->pw_dir;
00655 }
00656
00657 snprintf(tmp, MAX_PATH, "%s" PATHSEP "%s", homedir, PERSONAL_DIR);
00658 AppendPathSeparator(tmp, MAX_PATH);
00659
00660 _searchpaths[SP_PERSONAL_DIR] = strdup(tmp);
00661 #endif
00662
00663 #if defined(WITH_SHARED_DIR)
00664 snprintf(tmp, MAX_PATH, "%s", SHARED_DIR);
00665 AppendPathSeparator(tmp, MAX_PATH);
00666 _searchpaths[SP_SHARED_DIR] = strdup(tmp);
00667 #else
00668 _searchpaths[SP_SHARED_DIR] = NULL;
00669 #endif
00670
00671 #if defined(__MORPHOS__) || defined(__AMIGA__)
00672 _searchpaths[SP_WORKING_DIR] = NULL;
00673 #else
00674 getcwd(tmp, MAX_PATH);
00675 AppendPathSeparator(tmp, MAX_PATH);
00676 _searchpaths[SP_WORKING_DIR] = strdup(tmp);
00677 #endif
00678
00679
00680 ChangeWorkingDirectory((char*)exe);
00681 getcwd(tmp, MAX_PATH);
00682 AppendPathSeparator(tmp, MAX_PATH);
00683 _searchpaths[SP_BINARY_DIR] = strdup(tmp);
00684
00685 #if defined(__MORPHOS__) || defined(__AMIGA__)
00686 _searchpaths[SP_INSTALLATION_DIR] = NULL;
00687 #else
00688 snprintf(tmp, MAX_PATH, "%s", GLOBAL_DATA_DIR);
00689 AppendPathSeparator(tmp, MAX_PATH);
00690 _searchpaths[SP_INSTALLATION_DIR] = strdup(tmp);
00691 #endif
00692 #ifdef WITH_COCOA
00693 extern void cocoaSetApplicationBundleDir();
00694 cocoaSetApplicationBundleDir();
00695 #else
00696 _searchpaths[SP_APPLICATION_BUNDLE_DIR] = NULL;
00697 #endif
00698
00699 ScanForTarFiles();
00700 }
00701 #endif
00702
00703 char *_personal_dir;
00704
00711 void DeterminePaths(const char *exe)
00712 {
00713 DetermineBasePaths(exe);
00714
00715 Searchpath sp;
00716 FOR_ALL_SEARCHPATHS(sp) DEBUG(misc, 4, "%s added as search path", _searchpaths[sp]);
00717
00718 if (_config_file != NULL) {
00719 _personal_dir = strdup(_config_file);
00720 char *end = strrchr(_personal_dir , PATHSEPCHAR);
00721 if (end == NULL) {
00722 _personal_dir[0] = '\0';
00723 } else {
00724 end[1] = '\0';
00725 }
00726 } else {
00727 char personal_dir[MAX_PATH];
00728 FioFindFullPath(personal_dir, lengthof(personal_dir), BASE_DIR, "openttd.cfg");
00729
00730 if (FileExists(personal_dir)) {
00731 char *end = strrchr(personal_dir, PATHSEPCHAR);
00732 if (end != NULL) end[1] = '\0';
00733 _personal_dir = strdup(personal_dir);
00734 _config_file = str_fmt("%sopenttd.cfg", _personal_dir);
00735 } else {
00736 static const Searchpath new_openttd_cfg_order[] = {
00737 SP_PERSONAL_DIR, SP_BINARY_DIR, SP_WORKING_DIR, SP_SHARED_DIR, SP_INSTALLATION_DIR
00738 };
00739
00740 for (uint i = 0; i < lengthof(new_openttd_cfg_order); i++) {
00741 if (IsValidSearchPath(new_openttd_cfg_order[i])) {
00742 _personal_dir = strdup(_searchpaths[new_openttd_cfg_order[i]]);
00743 _config_file = str_fmt("%sopenttd.cfg", _personal_dir);
00744 break;
00745 }
00746 }
00747 }
00748 }
00749
00750 DEBUG(misc, 3, "%s found as personal directory", _personal_dir);
00751
00752 _highscore_file = str_fmt("%shs.dat", _personal_dir);
00753 _log_file = str_fmt("%sopenttd.log", _personal_dir);
00754
00755 char *save_dir = str_fmt("%s%s", _personal_dir, FioGetSubdirectory(SAVE_DIR));
00756 char *autosave_dir = str_fmt("%s%s", _personal_dir, FioGetSubdirectory(AUTOSAVE_DIR));
00757
00758
00759 #if !defined(__MORPHOS__) && !defined(__AMIGA__) && defined(WITH_PERSONAL_DIR)
00760 FioCreateDirectory(_personal_dir);
00761 #endif
00762
00763 FioCreateDirectory(save_dir);
00764 FioCreateDirectory(autosave_dir);
00765
00766 free(save_dir);
00767 free(autosave_dir);
00768 }
00769
00774 void SanitizeFilename(char *filename)
00775 {
00776 for (; *filename != '\0'; filename++) {
00777 switch (*filename) {
00778
00779
00780 case ':': case '\\': case '*': case '?': case '/':
00781 case '<': case '>': case '|': case '"':
00782 *filename = '_';
00783 break;
00784 }
00785 }
00786 }
00787
00788 void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize)
00789 {
00790 FILE *in;
00791 byte *mem;
00792 size_t len;
00793
00794 in = fopen(filename, "rb");
00795 if (in == NULL) return NULL;
00796
00797 fseek(in, 0, SEEK_END);
00798 len = ftell(in);
00799 fseek(in, 0, SEEK_SET);
00800 if (len > maxsize || (mem = MallocT<byte>(len + 1)) == NULL) {
00801 fclose(in);
00802 return NULL;
00803 }
00804 mem[len] = 0;
00805 if (fread(mem, len, 1, in) != 1) {
00806 fclose(in);
00807 free(mem);
00808 return NULL;
00809 }
00810 fclose(in);
00811
00812 *lenp = len;
00813 return mem;
00814 }