27 #include "table/strings.h"
32 static char *_fios_path;
33 static const char *_fios_path_last;
34 SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
37 extern bool FiosIsRoot(
const char *path);
38 extern bool FiosIsValidFile(
const char *path,
const struct dirent *ent,
struct stat *sb);
39 extern bool FiosIsHiddenFile(
const struct dirent *ent);
40 extern void FiosGetDrives(
FileList &file_list);
41 extern bool FiosGetDiskFreeSpace(
const char *path, uint64 *tot);
44 extern void GetOldSaveGameName(
const char *file,
char *title,
const char *last);
56 if ((_savegame_sort_order & SORT_BY_NAME) == 0 && da->mtime != db->mtime) {
57 r = da->mtime < db->mtime ? -1 : 1;
59 r = strcasecmp(da->title, db->title);
62 if (_savegame_sort_order & SORT_DESCENDING) r = -r;
81 switch (abstract_filetype) {
111 if (strcmp(file, item->name) == 0)
return item;
112 if (strcmp(file, item->title) == 0)
return item;
117 int i = strtol(file, &endptr, 10);
118 if (file == endptr || *endptr !=
'\0') i = -1;
124 char long_file[MAX_PATH];
127 if (strcmp(long_file, item->name) == 0)
return item;
128 if (strcmp(long_file, item->title) == 0)
return item;
144 return FiosGetDiskFreeSpace(*path, total_free) ? STR_SAVELOAD_BYTES_FREE : STR_ERROR_UNABLE_TO_READ_DRIVE;
154 switch (item->type) {
155 case FIOS_TYPE_DRIVE:
157 seprintf(_fios_path, _fios_path_last, PATHSEP
"");
158 #elif defined(WIN32) || defined(__OS2__)
159 seprintf(_fios_path, _fios_path_last,
"%c:" PATHSEP, item->title[0]);
163 case FIOS_TYPE_INVALID:
166 case FIOS_TYPE_PARENT: {
168 char *s = strrchr(_fios_path, PATHSEPCHAR);
169 if (s != NULL && s != _fios_path) {
172 s = strrchr(_fios_path, PATHSEPCHAR);
175 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
177 }
else if ((s = strrchr(_fios_path,
':')) != NULL) {
185 strecat(_fios_path, item->name, _fios_path_last);
186 strecat(_fios_path, PATHSEP, _fios_path_last);
189 case FIOS_TYPE_DIRECT:
190 seprintf(_fios_path, _fios_path_last,
"%s", item->name);
194 case FIOS_TYPE_OLDFILE:
195 case FIOS_TYPE_SCENARIO:
196 case FIOS_TYPE_OLD_SCENARIO:
213 static void FiosMakeFilename(
char *buf,
const char *path,
const char *name,
const char *ext,
const char *last)
218 period = strrchr(name,
'.');
219 if (period != NULL && strcasecmp(period, ext) == 0) ext =
"";
220 #if defined(__MORPHOS__) || defined(__AMIGAOS__)
222 unsigned char sepchar = path[(strlen(path) - 1)];
224 if (sepchar !=
':' && sepchar !=
'/') {
225 seprintf(buf, last,
"%s" PATHSEP
"%s%s", path, name, ext);
227 seprintf(buf, last,
"%s%s%s", path, name, ext);
230 seprintf(buf, last,
"%s%s", name, ext);
233 seprintf(buf, last,
"%s" PATHSEP
"%s%s", path, name, ext);
245 const char *extension = (_game_mode == GM_EDITOR) ?
".scn" :
".sav";
275 return unlink(filename) == 0;
278 typedef FiosType fios_getlist_callback_proc(
SaveLoadOperation fop,
const char *filename,
const char *ext,
char *title,
const char *last);
295 fop(fop), callback_proc(callback_proc), file_list(file_list)
298 bool AddFile(
const char *filename,
size_t basepath_length,
const char *tar_filename);
309 const char *ext = strrchr(filename,
'.');
310 if (ext == NULL)
return false;
313 fios_title[0] =
'\0';
316 if (type == FIOS_TYPE_INVALID)
return false;
319 if (strcmp(fios->name, filename) == 0)
return false;
325 if (_tstat(
OTTD2FS(filename), &sb) == 0) {
328 if (stat(filename, &sb) == 0) {
330 fios->mtime = sb.st_mtime;
339 const char *t = fios_title;
341 t = strrchr(filename, PATHSEPCHAR);
342 t = (t == NULL) ? filename : (t + 1);
361 struct dirent *dirent;
365 char d_name[
sizeof(fios->name)];
370 if (!FiosIsRoot(_fios_path)) {
371 fios = file_list.
Append();
372 fios->type = FIOS_TYPE_PARENT;
375 strecpy(fios->title,
".. (Parent directory)",
lastof(fios->title));
380 while ((dirent = readdir(dir)) != NULL) {
384 if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) &&
385 (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
386 strcmp(d_name,
".") != 0 && strcmp(d_name,
"..") != 0) {
387 fios = file_list.
Append();
388 fios->type = FIOS_TYPE_DIR;
391 seprintf(fios->title,
lastof(fios->title),
"%s" PATHSEP
" (Directory)", d_name);
400 SortingBits order = _savegame_sort_order;
401 _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
403 _savegame_sort_order = order;
407 sort_start = file_list.
Length();
412 scanner.
Scan(NULL, _fios_path,
false);
414 scanner.
Scan(NULL, subdir,
true,
true);
420 FiosGetDrives(file_list);
440 if (f == NULL)
return;
442 size_t read = fread(title, 1, last - title, f);
443 assert(title + read <= last);
469 if (ext == NULL)
return FIOS_TYPE_INVALID;
471 if (strcasecmp(ext,
".sav") == 0) {
473 return FIOS_TYPE_FILE;
477 if (strcasecmp(ext,
".ss1") == 0 || strcasecmp(ext,
".sv1") == 0 ||
478 strcasecmp(ext,
".sv2") == 0) {
479 if (title != NULL) GetOldSaveGameName(file, title, last);
480 return FIOS_TYPE_OLDFILE;
484 return FIOS_TYPE_INVALID;
495 static char *fios_save_path = NULL;
496 static char *fios_save_path_last = NULL;
498 if (fios_save_path == NULL) {
499 fios_save_path = MallocT<char>(MAX_PATH);
500 fios_save_path_last = fios_save_path + MAX_PATH - 1;
501 FioGetDirectory(fios_save_path, fios_save_path_last,
SAVE_DIR);
504 _fios_path = fios_save_path;
505 _fios_path_last = fios_save_path_last;
527 if (strcasecmp(ext,
".scn") == 0) {
529 return FIOS_TYPE_SCENARIO;
533 if (strcasecmp(ext,
".sv0") == 0 || strcasecmp(ext,
".ss0") == 0 ) {
534 GetOldSaveGameName(file, title, last);
535 return FIOS_TYPE_OLD_SCENARIO;
539 return FIOS_TYPE_INVALID;
550 static char *fios_scn_path = NULL;
551 static char *fios_scn_path_last = NULL;
554 if (fios_scn_path == NULL) {
555 fios_scn_path = MallocT<char>(MAX_PATH);
556 fios_scn_path_last = fios_scn_path + MAX_PATH - 1;
557 FioGetDirectory(fios_scn_path, fios_scn_path_last,
SCENARIO_DIR);
560 _fios_path = fios_scn_path;
561 _fios_path_last = fios_scn_path_last;
563 char base_path[MAX_PATH];
580 if (strcasecmp(ext,
".png") == 0) type = FIOS_TYPE_PNG;
583 if (strcasecmp(ext,
".bmp") == 0) type = FIOS_TYPE_BMP;
585 if (type == FIOS_TYPE_INVALID)
return FIOS_TYPE_INVALID;
587 TarFileList::iterator it = _tar_filelist[
SCENARIO_DIR].find(file);
600 if (strncmp(buf, it->second.tar_filename, strlen(buf)) == 0) {
606 if (!match)
return FIOS_TYPE_INVALID;
621 static char *fios_hmap_path = NULL;
622 static char *fios_hmap_path_last = NULL;
624 if (fios_hmap_path == NULL) {
625 fios_hmap_path = MallocT<char>(MAX_PATH);
626 fios_hmap_path_last = fios_hmap_path + MAX_PATH - 1;
627 FioGetDirectory(fios_hmap_path, fios_hmap_path_last,
HEIGHTMAP_DIR);
630 _fios_path = fios_hmap_path;
631 _fios_path_last = fios_hmap_path_last;
633 char base_path[MAX_PATH];
637 FiosGetFileList(fop, &FiosGetHeightmapListCallback, subdir, file_list);
646 static char *fios_screenshot_path = NULL;
648 if (fios_screenshot_path == NULL) {
649 fios_screenshot_path = MallocT<char>(MAX_PATH);
650 FioGetDirectory(fios_screenshot_path, fios_screenshot_path + MAX_PATH - 1,
SCREENSHOT_DIR);
653 return fios_screenshot_path;
656 #if defined(ENABLE_NETWORK)
658 #include "3rdparty/md5/md5.h"
664 char filename[MAX_PATH];
668 return this->scenid == other.
scenid &&
669 memcmp(this->md5sum, other.
md5sum,
sizeof(this->md5sum)) == 0;
674 return !(*
this == other);
693 if (this->scanned && !rescan)
return;
696 this->scanned =
true;
699 bool AddFile(
const char *filename,
size_t basepath_length,
const char *tar_filename)
702 if (f == NULL)
return false;
705 int fret = fscanf(f,
"%i", &
id.scenid);
707 if (fret != 1)
return false;
712 char basename[MAX_PATH];
719 *strrchr(basename,
'.') =
'\0';
721 if (f == NULL)
return false;
724 while ((len = fread(buffer, 1, (size >
sizeof(buffer)) ?
sizeof(buffer) : size, f)) != 0 && size != 0) {
726 checksum.Append(buffer, len);
728 checksum.Finish(
id.md5sum);
748 _scanner.
Scan(
false);
751 if (md5sum ? (memcmp(id->md5sum, ci->
md5sum,
sizeof(id->md5sum)) == 0)