00001
00002
00007 #include "stdafx.h"
00008 #include "openttd.h"
00009 #include "variables.h"
00010 #include "heightmap.h"
00011 #include "fios.h"
00012 #include "fileio.h"
00013 #include "core/alloc_func.hpp"
00014 #include "functions.h"
00015 #include "string_func.h"
00016 #include <sys/types.h>
00017 #include <sys/stat.h>
00018
00019 #ifdef WIN32
00020 # include <tchar.h>
00021 # include <io.h>
00022 # define access _taccess
00023 # define unlink _tunlink
00024 #else
00025 # include <unistd.h>
00026 #endif
00027
00028 #include "table/strings.h"
00029
00030
00031 int _fios_num;
00032
00033 static char *_fios_path;
00034 static FiosItem *_fios_items;
00035 SmallFiosItem _file_to_saveload;
00036 static int _fios_count, _fios_alloc;
00037
00038
00039 extern bool FiosIsRoot(const char *path);
00040 extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
00041 extern bool FiosIsHiddenFile(const struct dirent *ent);
00042 extern void FiosGetDrives();
00043 extern bool FiosGetDiskFreeSpace(const char *path, uint32 *tot);
00044
00045
00046 extern void GetOldSaveGameName(char *title, const char *path, const char *file);
00047
00052 FiosItem *FiosAlloc()
00053 {
00054 if (_fios_count == _fios_alloc) {
00055 _fios_alloc += 256;
00056 _fios_items = ReallocT(_fios_items, _fios_alloc);
00057 }
00058 return &_fios_items[_fios_count++];
00059 }
00060
00067 int CDECL compare_FiosItems(const void *a, const void *b)
00068 {
00069 const FiosItem *da = (const FiosItem *)a;
00070 const FiosItem *db = (const FiosItem *)b;
00071 int r;
00072
00073 if (_savegame_sort_order & SORT_BY_NAME) {
00074 r = strcasecmp(da->title, db->title);
00075 } else {
00076 r = da->mtime < db->mtime ? -1 : 1;
00077 }
00078
00079 if (_savegame_sort_order & SORT_DESCENDING) r = -r;
00080 return r;
00081 }
00082
00086 void FiosFreeSavegameList()
00087 {
00088 free(_fios_items);
00089 _fios_items = NULL;
00090 _fios_alloc = _fios_count = 0;
00091 }
00092
00100 StringID FiosGetDescText(const char **path, uint32 *total_free)
00101 {
00102 *path = _fios_path;
00103 return FiosGetDiskFreeSpace(*path, total_free) ? STR_4005_BYTES_FREE : STR_4006_UNABLE_TO_READ_DRIVE;
00104 }
00105
00106
00107
00108
00109 char *FiosBrowseTo(const FiosItem *item)
00110 {
00111 char *s;
00112 char *path = _fios_path;
00113
00114 switch (item->type) {
00115 #if defined(WINCE)
00116 case FIOS_TYPE_DRIVE: sprintf(path, PATHSEP ""); break;
00117 #elif defined(WIN32) || defined(__OS2__)
00118 case FIOS_TYPE_DRIVE: sprintf(path, "%c:" PATHSEP, item->title[0]); break;
00119 #endif
00120
00121 case FIOS_TYPE_PARENT:
00122
00123 s = strrchr(path, PATHSEPCHAR);
00124 if (s != NULL && s != path) {
00125 s[0] = '\0';
00126 }
00127 s = strrchr(path, PATHSEPCHAR);
00128 if (s != NULL) s[1] = '\0';
00129 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
00130
00131 else if ((s = strrchr(path, ':')) != NULL) s[1] = '\0';
00132 #endif
00133 break;
00134
00135 case FIOS_TYPE_DIR:
00136 strcat(path, item->name);
00137 strcat(path, PATHSEP);
00138 break;
00139
00140 case FIOS_TYPE_DIRECT:
00141 sprintf(path, "%s", item->name);
00142 break;
00143
00144 case FIOS_TYPE_FILE:
00145 case FIOS_TYPE_OLDFILE:
00146 case FIOS_TYPE_SCENARIO:
00147 case FIOS_TYPE_OLD_SCENARIO:
00148 case FIOS_TYPE_PNG:
00149 case FIOS_TYPE_BMP:
00150 {
00151 static char str_buffr[512];
00152 snprintf(str_buffr, lengthof(str_buffr), "%s%s", path, item->name);
00153 return str_buffr;
00154 }
00155 }
00156
00157 return NULL;
00158 }
00159
00160 void FiosMakeSavegameName(char *buf, const char *name, size_t size)
00161 {
00162 const char *extension, *period;
00163
00164 extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav";
00165
00166
00167 period = strrchr(name, '.');
00168 if (period != NULL && strcasecmp(period, extension) == 0) extension = "";
00169 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
00170 if (_fios_path != NULL) {
00171 unsigned char sepchar = _fios_path[(strlen(_fios_path) - 1)];
00172
00173 if (sepchar != ':' && sepchar != '/') {
00174 snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00175 } else {
00176 snprintf(buf, size, "%s%s%s", _fios_path, name, extension);
00177 }
00178 } else {
00179 snprintf(buf, size, "%s%s", name, extension);
00180 }
00181 #else
00182 snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00183 #endif
00184 }
00185
00186 #if defined(WIN32)
00187 # define unlink _tunlink
00188 #endif
00189
00190 bool FiosDelete(const char *name)
00191 {
00192 char filename[512];
00193
00194 FiosMakeSavegameName(filename, name, lengthof(filename));
00195 return unlink(OTTD2FS(filename)) == 0;
00196 }
00197
00198 bool FileExists(const char *filename)
00199 {
00200 #if defined(WINCE)
00201
00202 HANDLE hand = CreateFile(OTTD2FS(filename), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
00203 if (hand == INVALID_HANDLE_VALUE) return 1;
00204 CloseHandle(hand);
00205 return 0;
00206 #else
00207 return access(OTTD2FS(filename), 0) == 0;
00208 #endif
00209 }
00210
00211 typedef byte fios_getlist_callback_proc(int mode, const char *filename, const char *ext, char *title);
00212
00217 static FiosItem *FiosGetFileList(int mode, fios_getlist_callback_proc *callback_proc)
00218 {
00219 struct stat sb;
00220 struct dirent *dirent;
00221 DIR *dir;
00222 FiosItem *fios;
00223 int sort_start;
00224 char d_name[sizeof(fios->name)];
00225
00226
00227 if (!FiosIsRoot(_fios_path) && mode != SLD_NEW_GAME) {
00228 fios = FiosAlloc();
00229 fios->type = FIOS_TYPE_PARENT;
00230 fios->mtime = 0;
00231 ttd_strlcpy(fios->name, "..", lengthof(fios->name));
00232 ttd_strlcpy(fios->title, ".. (Parent directory)", lengthof(fios->title));
00233 }
00234
00235
00236 if (mode != SLD_NEW_GAME && (dir = ttd_opendir(_fios_path)) != NULL) {
00237 while ((dirent = readdir(dir)) != NULL) {
00238 ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
00239
00240
00241 if (FiosIsValidFile(_fios_path, dirent, &sb) && (sb.st_mode & S_IFDIR) &&
00242 (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
00243 strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
00244 fios = FiosAlloc();
00245 fios->type = FIOS_TYPE_DIR;
00246 fios->mtime = 0;
00247 ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
00248 snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name);
00249 str_validate(fios->title);
00250 }
00251 }
00252 closedir(dir);
00253 }
00254
00255
00256 {
00257 byte order = _savegame_sort_order;
00258 _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
00259 qsort(_fios_items, _fios_count, sizeof(FiosItem), compare_FiosItems);
00260 _savegame_sort_order = order;
00261 }
00262
00263
00264 sort_start = _fios_count;
00265
00266
00267 dir = ttd_opendir(_fios_path);
00268 if (dir != NULL) {
00269 while ((dirent = readdir(dir)) != NULL) {
00270 char fios_title[64];
00271 char *t;
00272 ttd_strlcpy(d_name, FS2OTTD(dirent->d_name), sizeof(d_name));
00273
00274 if (!FiosIsValidFile(_fios_path, dirent, &sb) || !(sb.st_mode & S_IFREG) || FiosIsHiddenFile(dirent)) continue;
00275
00276
00277 if ((t = strrchr(d_name, '.')) == NULL) continue;
00278 fios_title[0] = '\0';
00279
00280 byte type = callback_proc(mode, d_name, t, fios_title);
00281 if (type != FIOS_TYPE_INVALID) {
00282 fios = FiosAlloc();
00283 fios->mtime = sb.st_mtime;
00284 fios->type = type;
00285 ttd_strlcpy(fios->name, d_name, lengthof(fios->name));
00286
00287
00288
00289 t = (fios_title[0] == '\0') ? *t = '\0', d_name : fios_title;
00290 ttd_strlcpy(fios->title, t, lengthof(fios->title));
00291 str_validate(fios->title);
00292 }
00293 }
00294 closedir(dir);
00295 }
00296
00297 qsort(_fios_items + sort_start, _fios_count - sort_start, sizeof(FiosItem), compare_FiosItems);
00298
00299
00300 if (mode != SLD_NEW_GAME) FiosGetDrives();
00301
00302 _fios_num = _fios_count;
00303 return _fios_items;
00304 }
00305
00316 byte FiosGetSavegameListCallback(int mode, const char *file, const char *ext, char *title)
00317 {
00318
00319
00320
00321
00322
00323 if (strcasecmp(ext, ".sav") == 0) return FIOS_TYPE_FILE;
00324
00325 if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
00326 if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
00327 strcasecmp(ext, ".sv2") == 0) {
00328 if (title != NULL) GetOldSaveGameName(title, _fios_path, file);
00329 return FIOS_TYPE_OLDFILE;
00330 }
00331 }
00332
00333 return FIOS_TYPE_INVALID;
00334 }
00335
00342 FiosItem *FiosGetSavegameList(int mode)
00343 {
00344 static char *_fios_save_path = NULL;
00345
00346 if (_fios_save_path == NULL) {
00347 _fios_save_path = MallocT<char>(MAX_PATH);
00348 FioGetDirectory(_fios_save_path, MAX_PATH, SAVE_DIR);
00349 }
00350
00351 _fios_path = _fios_save_path;
00352
00353 return FiosGetFileList(mode, &FiosGetSavegameListCallback);
00354 }
00355
00366 static byte FiosGetScenarioListCallback(int mode, const char *file, const char *ext, char *title)
00367 {
00368
00369
00370
00371
00372 if (strcasecmp(ext, ".scn") == 0) return FIOS_TYPE_SCENARIO;
00373
00374 if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
00375 if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
00376 GetOldSaveGameName(title, _fios_path, file);
00377 return FIOS_TYPE_OLD_SCENARIO;
00378 }
00379 }
00380
00381 return FIOS_TYPE_INVALID;
00382 }
00383
00390 FiosItem *FiosGetScenarioList(int mode)
00391 {
00392 static char *_fios_scn_path = NULL;
00393
00394
00395 if (_fios_scn_path == NULL) {
00396 _fios_scn_path = MallocT<char>(MAX_PATH);
00397 FioGetDirectory(_fios_scn_path, MAX_PATH, SCENARIO_DIR);
00398 }
00399
00400 _fios_path = _fios_scn_path;
00401
00402 return FiosGetFileList(mode, &FiosGetScenarioListCallback);
00403 }
00404
00405 static byte FiosGetHeightmapListCallback(int mode, const char *file, const char *ext, char *title)
00406 {
00407
00408
00409
00410
00411
00412 #ifdef WITH_PNG
00413 if (strcasecmp(ext, ".png") == 0) return FIOS_TYPE_PNG;
00414 #endif
00415
00416 if (strcasecmp(ext, ".bmp") == 0) return FIOS_TYPE_BMP;
00417
00418 return FIOS_TYPE_INVALID;
00419 }
00420
00421
00422 FiosItem *FiosGetHeightmapList(int mode)
00423 {
00424 static char *_fios_hmap_path = NULL;
00425
00426 if (_fios_hmap_path == NULL) {
00427 _fios_hmap_path = MallocT<char>(MAX_PATH);
00428 FioGetDirectory(_fios_hmap_path, MAX_PATH, HEIGHTMAP_DIR);
00429 }
00430
00431 _fios_path = _fios_hmap_path;
00432
00433 return FiosGetFileList(mode, &FiosGetHeightmapListCallback);
00434 }