00001
00002
00007 #include "stdafx.h"
00008 #include "openttd.h"
00009 #include "fios.h"
00010 #include "fileio_func.h"
00011 #include "string_func.h"
00012 #include <sys/stat.h>
00013
00014 #ifdef WIN32
00015 # include <tchar.h>
00016 # ifndef UNICODE
00017 # include <io.h>
00018 # endif
00019 # define access _taccess
00020 # define unlink _tunlink
00021 #else
00022 # include <unistd.h>
00023 #endif
00024
00025 #include "table/strings.h"
00026
00027
00028 SmallVector<FiosItem, 32> _fios_items;
00029 static char *_fios_path;
00030 SmallFiosItem _file_to_saveload;
00031
00032
00033 extern bool FiosIsRoot(const char *path);
00034 extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
00035 extern bool FiosIsHiddenFile(const struct dirent *ent);
00036 extern void FiosGetDrives();
00037 extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot);
00038
00039
00040 extern void GetOldSaveGameName(const char *path, const char *file, char *title, const char *last);
00041
00048 int CDECL compare_FiosItems(const void *a, const void *b)
00049 {
00050 const FiosItem *da = (const FiosItem *)a;
00051 const FiosItem *db = (const FiosItem *)b;
00052 int r;
00053
00054 if (_savegame_sort_order & SORT_BY_NAME) {
00055 r = strcasecmp(da->title, db->title);
00056 } else {
00057 r = da->mtime < db->mtime ? -1 : 1;
00058 }
00059
00060 if (_savegame_sort_order & SORT_DESCENDING) r = -r;
00061 return r;
00062 }
00063
00065 void FiosFreeSavegameList()
00066 {
00067 _fios_items.Clear();
00068 _fios_items.Compact();
00069 };
00070
00078 StringID FiosGetDescText(const char **path, uint64 *total_free)
00079 {
00080 *path = _fios_path;
00081 return FiosGetDiskFreeSpace(*path, total_free) ? STR_4005_BYTES_FREE : STR_4006_UNABLE_TO_READ_DRIVE;
00082 }
00083
00084
00085
00086
00087 char *FiosBrowseTo(const FiosItem *item)
00088 {
00089 char *path = _fios_path;
00090
00091 switch (item->type) {
00092 case FIOS_TYPE_DRIVE:
00093 #if defined(WINCE)
00094 snprintf(path, MAX_PATH, PATHSEP "");
00095 #elif defined(WIN32) || defined(__OS2__)
00096 snprintf(path, MAX_PATH, "%c:" PATHSEP, item->title[0]);
00097 #endif
00098
00099 case FIOS_TYPE_INVALID:
00100 break;
00101
00102 case FIOS_TYPE_PARENT: {
00103
00104 char *s = strrchr(path, PATHSEPCHAR);
00105 if (s != NULL && s != path) {
00106 s[0] = '\0';
00107 }
00108 s = strrchr(path, PATHSEPCHAR);
00109 if (s != NULL) s[1] = '\0';
00110 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
00111
00112 else if ((s = strrchr(path, ':')) != NULL) s[1] = '\0';
00113 #endif
00114 break;
00115 }
00116
00117 case FIOS_TYPE_DIR:
00118 strcat(path, item->name);
00119 strcat(path, PATHSEP);
00120 break;
00121
00122 case FIOS_TYPE_DIRECT:
00123 snprintf(path, MAX_PATH, "%s", item->name);
00124 break;
00125
00126 case FIOS_TYPE_FILE:
00127 case FIOS_TYPE_OLDFILE:
00128 case FIOS_TYPE_SCENARIO:
00129 case FIOS_TYPE_OLD_SCENARIO:
00130 case FIOS_TYPE_PNG:
00131 case FIOS_TYPE_BMP:
00132 {
00133 static char str_buffr[512];
00134 snprintf(str_buffr, lengthof(str_buffr), "%s%s", path, item->name);
00135 return str_buffr;
00136 }
00137 }
00138
00139 return NULL;
00140 }
00141
00142 void FiosMakeSavegameName(char *buf, const char *name, size_t size)
00143 {
00144 const char *extension, *period;
00145
00146 extension = (_game_mode == GM_EDITOR) ? ".scn" : ".sav";
00147
00148
00149 period = strrchr(name, '.');
00150 if (period != NULL && strcasecmp(period, extension) == 0) extension = "";
00151 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
00152 if (_fios_path != NULL) {
00153 unsigned char sepchar = _fios_path[(strlen(_fios_path) - 1)];
00154
00155 if (sepchar != ':' && sepchar != '/') {
00156 snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00157 } else {
00158 snprintf(buf, size, "%s%s%s", _fios_path, name, extension);
00159 }
00160 } else {
00161 snprintf(buf, size, "%s%s", name, extension);
00162 }
00163 #else
00164 snprintf(buf, size, "%s" PATHSEP "%s%s", _fios_path, name, extension);
00165 #endif
00166 }
00167
00168 #if defined(WIN32)
00169 # define unlink _tunlink
00170 #endif
00171
00172 bool FiosDelete(const char *name)
00173 {
00174 char filename[512];
00175
00176 FiosMakeSavegameName(filename, name, lengthof(filename));
00177 return unlink(OTTD2FS(filename)) == 0;
00178 }
00179
00180 bool FileExists(const char *filename)
00181 {
00182 #if defined(WINCE)
00183
00184 HANDLE hand = CreateFile(OTTD2FS(filename), 0, 0, NULL, OPEN_EXISTING, 0, NULL);
00185 if (hand == INVALID_HANDLE_VALUE) return 1;
00186 CloseHandle(hand);
00187 return 0;
00188 #else
00189 return access(OTTD2FS(filename), 0) == 0;
00190 #endif
00191 }
00192
00193 typedef FiosType fios_getlist_callback_proc(SaveLoadDialogMode mode, const char *filename, const char *ext, char *title, const char *last);
00194
00199 static FiosItem *FiosGetFileList(SaveLoadDialogMode mode, fios_getlist_callback_proc *callback_proc)
00200 {
00201 struct stat sb;
00202 struct dirent *dirent;
00203 DIR *dir;
00204 FiosItem *fios;
00205 int sort_start;
00206 char d_name[sizeof(fios->name)];
00207
00208 _fios_items.Clear();
00209
00210
00211 if (!FiosIsRoot(_fios_path) && mode != SLD_NEW_GAME) {
00212 fios = _fios_items.Append();
00213 fios->type = FIOS_TYPE_PARENT;
00214 fios->mtime = 0;
00215 strecpy(fios->name, "..", lastof(fios->name));
00216 strecpy(fios->title, ".. (Parent directory)", lastof(fios->title));
00217 }
00218
00219
00220 if (mode != SLD_NEW_GAME && (dir = ttd_opendir(_fios_path)) != NULL) {
00221 while ((dirent = readdir(dir)) != NULL) {
00222 strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name));
00223
00224
00225 if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) &&
00226 (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
00227 strcmp(d_name, ".") != 0 && strcmp(d_name, "..") != 0) {
00228 fios = _fios_items.Append();
00229 fios->type = FIOS_TYPE_DIR;
00230 fios->mtime = 0;
00231 strecpy(fios->name, d_name, lastof(fios->name));
00232 snprintf(fios->title, lengthof(fios->title), "%s" PATHSEP " (Directory)", d_name);
00233 str_validate(fios->title);
00234 }
00235 }
00236 closedir(dir);
00237 }
00238
00239
00240 {
00241 byte order = _savegame_sort_order;
00242 _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
00243 qsort(_fios_items.Begin(), _fios_items.Length(), sizeof(FiosItem), compare_FiosItems);
00244 _savegame_sort_order = order;
00245 }
00246
00247
00248 sort_start = _fios_items.Length();
00249
00250
00251 dir = ttd_opendir(_fios_path);
00252 if (dir != NULL) {
00253 while ((dirent = readdir(dir)) != NULL) {
00254 char fios_title[64];
00255 char *t;
00256 strecpy(d_name, FS2OTTD(dirent->d_name), lastof(d_name));
00257
00258 if (!FiosIsValidFile(_fios_path, dirent, &sb) || !S_ISREG(sb.st_mode) || FiosIsHiddenFile(dirent)) continue;
00259
00260
00261 if ((t = strrchr(d_name, '.')) == NULL) continue;
00262 fios_title[0] = '\0';
00263
00264 FiosType type = callback_proc(mode, d_name, t, fios_title, lastof(fios_title));
00265 if (type != FIOS_TYPE_INVALID) {
00266 fios = _fios_items.Append();
00267 fios->mtime = sb.st_mtime;
00268 fios->type = type;
00269 strecpy(fios->name, d_name, lastof(fios->name));
00270
00271
00272
00273 t = (fios_title[0] == '\0') ? *t = '\0', d_name : fios_title;
00274 strecpy(fios->title, t, lastof(fios->title));
00275 str_validate(fios->title);
00276 }
00277 }
00278 closedir(dir);
00279 }
00280
00281 qsort(_fios_items.Get(sort_start), _fios_items.Length() - sort_start, sizeof(FiosItem), compare_FiosItems);
00282
00283
00284 if (mode != SLD_NEW_GAME) FiosGetDrives();
00285
00286 _fios_items.Compact();
00287
00288 return _fios_items.Begin();
00289 }
00290
00302 FiosType FiosGetSavegameListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
00303 {
00304
00305
00306
00307
00308
00309 if (strcasecmp(ext, ".sav") == 0) return FIOS_TYPE_FILE;
00310
00311 if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO) {
00312 if (strcasecmp(ext, ".ss1") == 0 || strcasecmp(ext, ".sv1") == 0 ||
00313 strcasecmp(ext, ".sv2") == 0) {
00314 if (title != NULL) GetOldSaveGameName(_fios_path, file, title, last);
00315 return FIOS_TYPE_OLDFILE;
00316 }
00317 }
00318
00319 return FIOS_TYPE_INVALID;
00320 }
00321
00328 void FiosGetSavegameList(SaveLoadDialogMode mode)
00329 {
00330 static char *fios_save_path = NULL;
00331
00332 if (fios_save_path == NULL) {
00333 fios_save_path = MallocT<char>(MAX_PATH);
00334 FioGetDirectory(fios_save_path, MAX_PATH, SAVE_DIR);
00335 }
00336
00337 _fios_path = fios_save_path;
00338
00339 FiosGetFileList(mode, &FiosGetSavegameListCallback);
00340 }
00341
00353 static FiosType FiosGetScenarioListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
00354 {
00355
00356
00357
00358
00359 if (strcasecmp(ext, ".scn") == 0) return FIOS_TYPE_SCENARIO;
00360
00361 if (mode == SLD_LOAD_GAME || mode == SLD_LOAD_SCENARIO || mode == SLD_NEW_GAME) {
00362 if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
00363 GetOldSaveGameName(_fios_path, file, title, last);
00364 return FIOS_TYPE_OLD_SCENARIO;
00365 }
00366 }
00367
00368 return FIOS_TYPE_INVALID;
00369 }
00370
00377 void FiosGetScenarioList(SaveLoadDialogMode mode)
00378 {
00379 static char *fios_scn_path = NULL;
00380
00381
00382 if (fios_scn_path == NULL) {
00383 fios_scn_path = MallocT<char>(MAX_PATH);
00384 FioGetDirectory(fios_scn_path, MAX_PATH, SCENARIO_DIR);
00385 }
00386
00387 _fios_path = fios_scn_path;
00388
00389 FiosGetFileList(mode, &FiosGetScenarioListCallback);
00390 }
00391
00392 static FiosType FiosGetHeightmapListCallback(SaveLoadDialogMode mode, const char *file, const char *ext, char *title, const char *last)
00393 {
00394
00395
00396
00397
00398
00399 #ifdef WITH_PNG
00400 if (strcasecmp(ext, ".png") == 0) return FIOS_TYPE_PNG;
00401 #endif
00402
00403 if (strcasecmp(ext, ".bmp") == 0) return FIOS_TYPE_BMP;
00404
00405 return FIOS_TYPE_INVALID;
00406 }
00407
00408
00409 void FiosGetHeightmapList(SaveLoadDialogMode mode)
00410 {
00411 static char *fios_hmap_path = NULL;
00412
00413 if (fios_hmap_path == NULL) {
00414 fios_hmap_path = MallocT<char>(MAX_PATH);
00415 FioGetDirectory(fios_hmap_path, MAX_PATH, HEIGHTMAP_DIR);
00416 }
00417
00418 _fios_path = fios_hmap_path;
00419
00420 FiosGetFileList(mode, &FiosGetHeightmapListCallback);
00421 }