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;
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:
156 #if defined(_WIN32) || defined(__OS2__) 157 seprintf(_fios_path, _fios_path_last,
"%c:" PATHSEP, item->title[0]);
161 case FIOS_TYPE_INVALID:
164 case FIOS_TYPE_PARENT: {
166 char *s = strrchr(_fios_path, PATHSEPCHAR);
167 if (s != NULL && s != _fios_path) {
170 s = strrchr(_fios_path, PATHSEPCHAR);
173 #if defined(__MORPHOS__) || defined(__AMIGAOS__) 175 }
else if ((s = strrchr(_fios_path,
':')) != NULL) {
183 strecat(_fios_path, item->name, _fios_path_last);
184 strecat(_fios_path, PATHSEP, _fios_path_last);
187 case FIOS_TYPE_DIRECT:
188 seprintf(_fios_path, _fios_path_last,
"%s", item->name);
192 case FIOS_TYPE_OLDFILE:
193 case FIOS_TYPE_SCENARIO:
194 case FIOS_TYPE_OLD_SCENARIO:
211 static void FiosMakeFilename(
char *buf,
const char *path,
const char *name,
const char *ext,
const char *last)
216 period = strrchr(name,
'.');
217 if (period != NULL && strcasecmp(period, ext) == 0) ext =
"";
218 #if defined(__MORPHOS__) || defined(__AMIGAOS__) 220 unsigned char sepchar = path[(strlen(path) - 1)];
222 if (sepchar !=
':' && sepchar !=
'/') {
223 seprintf(buf, last,
"%s" PATHSEP
"%s%s", path, name, ext);
225 seprintf(buf, last,
"%s%s%s", path, name, ext);
228 seprintf(buf, last,
"%s%s", name, ext);
231 seprintf(buf, last,
"%s" PATHSEP
"%s%s", path, name, ext);
243 const char *extension = (_game_mode == GM_EDITOR) ?
".scn" :
".sav";
273 return unlink(filename) == 0;
276 typedef FiosType fios_getlist_callback_proc(
SaveLoadOperation fop,
const char *filename,
const char *ext,
char *title,
const char *last);
283 fios_getlist_callback_proc *callback_proc;
293 fop(fop), callback_proc(callback_proc), file_list(file_list)
296 bool AddFile(
const char *filename,
size_t basepath_length,
const char *tar_filename);
307 const char *ext = strrchr(filename,
'.');
308 if (ext == NULL)
return false;
311 fios_title[0] =
'\0';
313 FiosType type = this->callback_proc(this->fop, filename, ext, fios_title,
lastof(fios_title));
314 if (type == FIOS_TYPE_INVALID)
return false;
316 for (
const FiosItem *fios = file_list.Begin(); fios != file_list.End(); fios++) {
317 if (strcmp(fios->name, filename) == 0)
return false;
320 FiosItem *fios = file_list.Append();
323 HANDLE fh = CreateFile(
OTTD2FS(filename), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, OPEN_EXISTING, 0,
nullptr);
325 if (fh != INVALID_HANDLE_VALUE) {
327 ULARGE_INTEGER ft_int64;
329 if (GetFileTime(fh,
nullptr,
nullptr, &ft) != 0) {
330 ft_int64.HighPart = ft.dwHighDateTime;
331 ft_int64.LowPart = ft.dwLowDateTime;
334 fios->mtime = ft_int64.QuadPart / 10000000ULL - 11644473600ULL;
342 if (stat(filename, &sb) == 0) {
343 fios->mtime = sb.st_mtime;
353 const char *t = fios_title;
355 t = strrchr(filename, PATHSEPCHAR);
356 t = (t == NULL) ? filename : (t + 1);
375 struct dirent *dirent;
379 char d_name[
sizeof(fios->name)];
384 if (!FiosIsRoot(_fios_path)) {
385 fios = file_list.
Append();
386 fios->type = FIOS_TYPE_PARENT;
389 strecpy(fios->title,
".. (Parent directory)",
lastof(fios->title));
394 while ((dirent = readdir(dir)) != NULL) {
398 if (FiosIsValidFile(_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) &&
399 (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
400 strcmp(d_name,
".") != 0 && strcmp(d_name,
"..") != 0) {
401 fios = file_list.
Append();
402 fios->type = FIOS_TYPE_DIR;
405 seprintf(fios->title,
lastof(fios->title),
"%s" PATHSEP
" (Directory)", d_name);
414 SortingBits order = _savegame_sort_order;
415 _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
417 _savegame_sort_order = order;
421 sort_start = file_list.
Length();
426 scanner.
Scan(NULL, _fios_path,
false);
428 scanner.
Scan(NULL, subdir,
true,
true);
434 FiosGetDrives(file_list);
454 if (f == NULL)
return;
456 size_t read = fread(title, 1, last - title, f);
457 assert(title + read <= last);
483 if (ext == NULL)
return FIOS_TYPE_INVALID;
485 if (strcasecmp(ext,
".sav") == 0) {
487 return FIOS_TYPE_FILE;
491 if (strcasecmp(ext,
".ss1") == 0 || strcasecmp(ext,
".sv1") == 0 ||
492 strcasecmp(ext,
".sv2") == 0) {
493 if (title != NULL) GetOldSaveGameName(file, title, last);
494 return FIOS_TYPE_OLDFILE;
498 return FIOS_TYPE_INVALID;
509 static char *fios_save_path = NULL;
510 static char *fios_save_path_last = NULL;
512 if (fios_save_path == NULL) {
513 fios_save_path = MallocT<char>(MAX_PATH);
514 fios_save_path_last = fios_save_path + MAX_PATH - 1;
515 FioGetDirectory(fios_save_path, fios_save_path_last,
SAVE_DIR);
518 _fios_path = fios_save_path;
519 _fios_path_last = fios_save_path_last;
541 if (strcasecmp(ext,
".scn") == 0) {
543 return FIOS_TYPE_SCENARIO;
547 if (strcasecmp(ext,
".sv0") == 0 || strcasecmp(ext,
".ss0") == 0 ) {
548 GetOldSaveGameName(file, title, last);
549 return FIOS_TYPE_OLD_SCENARIO;
553 return FIOS_TYPE_INVALID;
564 static char *fios_scn_path = NULL;
565 static char *fios_scn_path_last = NULL;
568 if (fios_scn_path == NULL) {
569 fios_scn_path = MallocT<char>(MAX_PATH);
570 fios_scn_path_last = fios_scn_path + MAX_PATH - 1;
571 FioGetDirectory(fios_scn_path, fios_scn_path_last,
SCENARIO_DIR);
574 _fios_path = fios_scn_path;
575 _fios_path_last = fios_scn_path_last;
577 char base_path[MAX_PATH];
584 static FiosType FiosGetHeightmapListCallback(
SaveLoadOperation fop,
const char *file,
const char *ext,
char *title,
const char *last)
594 if (strcasecmp(ext,
".png") == 0) type = FIOS_TYPE_PNG;
597 if (strcasecmp(ext,
".bmp") == 0) type = FIOS_TYPE_BMP;
599 if (type == FIOS_TYPE_INVALID)
return FIOS_TYPE_INVALID;
601 TarFileList::iterator it = _tar_filelist[
SCENARIO_DIR].find(file);
614 if (strncmp(buf, it->second.tar_filename, strlen(buf)) == 0) {
620 if (!match)
return FIOS_TYPE_INVALID;
635 static char *fios_hmap_path = NULL;
636 static char *fios_hmap_path_last = NULL;
638 if (fios_hmap_path == NULL) {
639 fios_hmap_path = MallocT<char>(MAX_PATH);
640 fios_hmap_path_last = fios_hmap_path + MAX_PATH - 1;
641 FioGetDirectory(fios_hmap_path, fios_hmap_path_last,
HEIGHTMAP_DIR);
644 _fios_path = fios_hmap_path;
645 _fios_path_last = fios_hmap_path_last;
647 char base_path[MAX_PATH];
651 FiosGetFileList(fop, &FiosGetHeightmapListCallback, subdir, file_list);
660 static char *fios_screenshot_path = NULL;
662 if (fios_screenshot_path == NULL) {
663 fios_screenshot_path = MallocT<char>(MAX_PATH);
664 FioGetDirectory(fios_screenshot_path, fios_screenshot_path + MAX_PATH - 1,
SCREENSHOT_DIR);
667 return fios_screenshot_path;
670 #if defined(ENABLE_NETWORK) 672 #include "3rdparty/md5/md5.h" 678 char filename[MAX_PATH];
682 return this->scenid == other.
scenid &&
683 memcmp(this->md5sum, other.
md5sum,
sizeof(this->md5sum)) == 0;
688 return !(*
this == other);
707 if (this->scanned && !rescan)
return;
710 this->scanned =
true;
713 bool AddFile(
const char *filename,
size_t basepath_length,
const char *tar_filename)
716 if (f == NULL)
return false;
719 int fret = fscanf(f,
"%i", &
id.scenid);
721 if (fret != 1)
return false;
726 char basename[MAX_PATH];
733 *strrchr(basename,
'.') =
'\0';
735 if (f == NULL)
return false;
738 while ((len = fread(buffer, 1, (size >
sizeof(buffer)) ?
sizeof(buffer) : size, f)) != 0 && size != 0) {
740 checksum.Append(buffer, len);
742 checksum.Finish(
id.md5sum);
762 _scanner.
Scan(
false);
765 if (md5sum ? (memcmp(id->md5sum, ci->
md5sum,
sizeof(id->md5sum)) == 0)
FiosType
Elements of a file system that are recognized.
bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
Try to add a fios item set with the given filename.
AbstractFileType
The different abstract types of files that the system knows about.
Basic data to distinguish a scenario.
uint32 unique_id
Unique ID; either GRF ID or shortname.
Scanner to find the unique IDs of scenarios.
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
Callback for FiosGetFileList.
static char * strecat(char *dst, const char *src, const char *last)
Appends characters from one string to another.
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD's encoding from that of the local environment.
Subdirectory
The different kinds of subdirectories OpenTTD uses.
void FioFCloseFile(FILE *f)
Close a file in a safe way.
Structs, typedefs and macros used for TAR file handling.
void Clear()
Remove all items from the list.
static bool IsInsideMM(const T x, const uint min, const uint max)
Checks if a value is in an interval.
uint8 md5sum[16]
MD5 checksum of file.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
uint Scan(const char *extension, Subdirectory sd, bool tars=true, bool recursive=true)
Scan for files with the given extension in the given search path.
#define FOR_ALL_SEARCHPATHS(sp)
Iterator for all the search paths.
Subdirectory of scenario for heightmaps.
Subdirectory for all screenshots.
const T * Begin() const
Get the pointer to the first item (const)
const FiosItem * Begin() const
Get a pointer to the first file information.
void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list)
Get a list of savegames.
Functions for Standard In/Out file operations.
#define lastof(x)
Get the last element of an fixed size array.
Simple vector template class.
Functions to make screenshots.
Searchpath
Types of searchpaths OpenTTD might use.
uint32 scenid
ID for the scenario (generated by content).
void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list)
Get a list of scenarios.
const T * End() const
Get the pointer behind the last valid item (const)
Deals with finding savegames.
StringID FiosGetDescText(const char **path, uint64 *total_free)
Get descriptive texts.
Helper for scanning for files with a given name.
const FiosItem * FindItem(const char *file)
Find file information of a file by its name from the file list.
SmallVector< FiosItem, 32 > files
The list of files.
bool HasScenario(const ContentInfo *ci, bool md5sum)
Check whether we've got a given scenario based on its unique ID.
FiosFileScanner(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, FileList &file_list)
Create the scanner.
uint Length() const
Get the number of files in the list.
Functions related to low-level strings.
Base directory for all scenarios.
bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
Add a file with the given filename.
const FiosItem * End() const
Get a pointer behind the last file information.
const char * FindScenario(const ContentInfo *ci, bool md5sum)
Find a given scenario based on its unique ID.
static ScenarioScanner _scanner
Scanner for scenarios.
bool scanned
Whether we've already scanned.
void FiosMakeSavegameName(char *buf, const char *name, const char *last)
Make a save game or scenario filename from a name.
uint Length() const
Get the number of items in the list.
bool operator!=(const MultiMapIterator< Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare > &iter1, const MultiMapIterator< Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare > &iter2)
Inverse of operator==().
void str_validate(char *str, const char *last, StringValidationSettings settings)
Scans the string for valid characters and if it finds invalid ones, replaces them with a question mar...
static void FiosMakeFilename(char *buf, const char *path, const char *name, const char *ext, const char *last)
Construct a filename from its components in destination buffer buf.
FILE * FioFOpenFile(const char *filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
A path without any base directory.
Definition of base types and functions in a cross-platform compatible way.
A number of safeguards to prevent using unsafe methods.
void Scan(bool rescan)
Scan, but only if it's needed.
void ScanScenarios()
Force a (re)scan of the scenarios.
Base directory for all savegames.
bool operator==(const MultiMapIterator< Tmap_iter1, Tlist_iter1, Tkey, Tvalue1, Tcompare > &iter1, const MultiMapIterator< Tmap_iter2, Tlist_iter2, Tkey, Tvalue2, Tcompare > &iter2)
Compare two MultiMap iterators.
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Construct a file list with the given kind of files, for the stated purpose.
const FiosItem * Get(uint index) const
Get a pointer to the indicated file information.
FileList & file_list
Destination of the found files.
Part of the network protocol handling content distribution.
static void GetFileTitle(const char *file, char *title, const char *last, Subdirectory subdir)
Get the title of a file, which (if exists) is stored in a file named the same as the data file but wi...
int CDECL CompareFiosItems(const FiosItem *da, const FiosItem *db)
Compare two FiosItem's.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
byte md5sum[16]
The MD5 checksum.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD's encoding to that of the local environment.
SaveLoadOperation
Operation performed on the file.
void Compact()
Compact the list down to the smallest block size boundary.
bool FiosDelete(const char *name)
Delete a file.
void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list)
Get a list of heightmaps.
static void FiosGetFileList(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, Subdirectory subdir, FileList &file_list)
Fill the list of the files in a directory, according to some arbitrary rule.
void FiosMakeHeightmapName(char *buf, const char *name, const char *last)
Construct a filename for a height map.
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
Declarations for savegames operations.
List of file information.
const char * FiosBrowseTo(const FiosItem *item)
Browse to a new path based on the passed item, starting at #_fios_path.
static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
Callback for FiosGetFileList.
Scanner to scan for a particular type of FIOS file.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
const char * GetCurrentScreenshotExtension()
Get filename extension of current screenshot file format.
static DIR * ttd_opendir(const char *path)
A wrapper around opendir() which will convert the string from OPENTTD encoding to that of the filesys...
SaveLoadOperation fop
The kind of file we are looking for.
FiosItem * Append()
Construct a new entry in the file list.
ScenarioScanner()
Initialise.
const char * FiosGetScreenshotDir()
Get the directory for screenshots.
static void QSortT(T *base, uint num, int(CDECL *comparator)(const T *, const T *), bool desc=false)
Type safe qsort()
Container for all important information about a piece of content.