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