|
OpenTTD Source
1.11.0-beta1
|
Go to the documentation of this file.
14 #include "3rdparty/md5/md5.h"
29 #include "table/strings.h"
34 static std::string *_fios_path =
nullptr;
35 SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
38 extern bool FiosIsRoot(
const char *path);
39 extern bool FiosIsValidFile(
const char *path,
const struct dirent *ent,
struct stat *sb);
40 extern bool FiosIsHiddenFile(
const struct dirent *ent);
41 extern void FiosGetDrives(
FileList &file_list);
42 extern bool FiosGetDiskFreeSpace(
const char *path, uint64 *tot);
45 extern void GetOldSaveGameName(
const std::string &file,
char *title,
const char *last);
56 if ((_savegame_sort_order & SORT_BY_NAME) == 0 && (*this).mtime != other.mtime) {
57 r = (*this).mtime - other.mtime;
59 r =
strnatcmp((*this).title, other.title);
61 if (r == 0)
return false;
62 return (_savegame_sort_order & SORT_DESCENDING) ? r > 0 : r < 0;
80 switch (abstract_filetype) {
110 if (strcmp(file, item->name) == 0)
return item;
111 if (strcmp(file, item->title) == 0)
return item;
116 int i = strtol(file, &endptr, 10);
117 if (file == endptr || *endptr !=
'\0') i = -1;
123 char long_file[MAX_PATH];
126 if (strcmp(long_file, item->name) == 0)
return item;
127 if (strcmp(long_file, item->title) == 0)
return item;
142 *path = _fios_path->c_str();
143 return FiosGetDiskFreeSpace(*path, total_free) ? STR_SAVELOAD_BYTES_FREE : STR_ERROR_UNABLE_TO_READ_DRIVE;
153 switch (item->type) {
154 case FIOS_TYPE_DRIVE:
155 #if defined(_WIN32) || defined(__OS2__)
156 assert(_fios_path !=
nullptr);
157 *_fios_path = std::string{ item->title[0] } +
":" PATHSEP;
161 case FIOS_TYPE_INVALID:
164 case FIOS_TYPE_PARENT: {
165 assert(_fios_path !=
nullptr);
166 auto s = _fios_path->find_last_of(PATHSEPCHAR);
167 if (s != std::string::npos && s != 0) {
168 _fios_path->erase(s);
171 s = _fios_path->find_last_of(PATHSEPCHAR);
172 if (s != std::string::npos) {
173 _fios_path->erase(s + 1);
179 assert(_fios_path !=
nullptr);
180 *_fios_path += item->name;
181 *_fios_path += PATHSEP;
184 case FIOS_TYPE_DIRECT:
185 assert(_fios_path !=
nullptr);
186 *_fios_path = item->name;
190 case FIOS_TYPE_OLDFILE:
191 case FIOS_TYPE_SCENARIO:
192 case FIOS_TYPE_OLD_SCENARIO:
208 static std::string
FiosMakeFilename(
const std::string *path,
const char *name,
const char *ext)
212 if (path !=
nullptr) {
215 if (!buf.empty() && buf.back() == PATHSEPCHAR) buf.pop_back();
219 const char *period = strrchr(name,
'.');
220 if (period !=
nullptr && strcasecmp(period, ext) == 0) ext =
"";
222 return buf + PATHSEP + name + ext;
234 const char *extension = (_game_mode == GM_EDITOR) ?
".scn" :
".sav";
246 std::string ext(
".");
260 return unlink(filename.c_str()) == 0;
263 typedef FiosType fios_getlist_callback_proc(
SaveLoadOperation fop,
const std::string &filename,
const char *ext,
char *title,
const char *last);
283 bool AddFile(
const std::string &filename,
size_t basepath_length,
const std::string &tar_filename)
override;
294 auto sep = filename.rfind(
'.');
295 if (sep == std::string::npos)
return false;
296 std::string ext = filename.substr(sep);
299 fios_title[0] =
'\0';
302 if (type == FIOS_TYPE_INVALID)
return false;
305 if (filename == fios->name)
return false;
311 HANDLE fh = CreateFile(
OTTD2FS(filename.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, OPEN_EXISTING, 0,
nullptr);
313 if (fh != INVALID_HANDLE_VALUE) {
315 ULARGE_INTEGER ft_int64;
317 if (GetFileTime(fh,
nullptr,
nullptr, &ft) != 0) {
318 ft_int64.HighPart = ft.dwHighDateTime;
319 ft_int64.LowPart = ft.dwLowDateTime;
322 fios->mtime = ft_int64.QuadPart / 10000000ULL - 11644473600ULL;
330 if (stat(filename.c_str(), &sb) == 0) {
331 fios->mtime = sb.st_mtime;
341 const char *t = fios_title;
343 auto ps = filename.rfind(PATHSEPCHAR);
344 t = filename.c_str() + (ps == std::string::npos ? 0 : ps + 1);
363 struct dirent *dirent;
367 char d_name[
sizeof(fios->name)];
371 assert(_fios_path !=
nullptr);
374 if (!FiosIsRoot(_fios_path->c_str())) {
376 fios->type = FIOS_TYPE_PARENT;
379 strecpy(fios->title,
".. (Parent directory)",
lastof(fios->title));
383 if ((dir =
ttd_opendir(_fios_path->c_str())) !=
nullptr) {
384 while ((dirent = readdir(dir)) !=
nullptr) {
388 if (FiosIsValidFile(_fios_path->c_str(), dirent, &sb) && S_ISDIR(sb.st_mode) &&
389 (!FiosIsHiddenFile(dirent) || strncasecmp(d_name, PERSONAL_DIR, strlen(d_name)) == 0) &&
390 strcmp(d_name,
".") != 0 && strcmp(d_name,
"..") != 0) {
392 fios->type = FIOS_TYPE_DIR;
395 seprintf(fios->title,
lastof(fios->title),
"%s" PATHSEP
" (Directory)", d_name);
404 SortingBits order = _savegame_sort_order;
405 _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
407 _savegame_sort_order = order;
416 scanner.
Scan(
nullptr, _fios_path->c_str(),
false);
439 std::string buf = file;
443 if (f ==
nullptr)
return;
445 size_t read = fread(title, 1, last - title, f);
446 assert(title + read <= last);
472 if (ext ==
nullptr)
return FIOS_TYPE_INVALID;
474 if (strcasecmp(ext,
".sav") == 0) {
476 return FIOS_TYPE_FILE;
480 if (strcasecmp(ext,
".ss1") == 0 || strcasecmp(ext,
".sv1") == 0 ||
481 strcasecmp(ext,
".sv2") == 0) {
482 if (title !=
nullptr) GetOldSaveGameName(file, title, last);
483 return FIOS_TYPE_OLDFILE;
487 return FIOS_TYPE_INVALID;
498 static std::optional<std::string> fios_save_path;
500 if (!fios_save_path) fios_save_path = FioFindDirectory(
SAVE_DIR);
502 _fios_path = &(*fios_save_path);
524 if (strcasecmp(ext,
".scn") == 0) {
526 return FIOS_TYPE_SCENARIO;
530 if (strcasecmp(ext,
".sv0") == 0 || strcasecmp(ext,
".ss0") == 0 ) {
531 GetOldSaveGameName(file, title, last);
532 return FIOS_TYPE_OLD_SCENARIO;
536 return FIOS_TYPE_INVALID;
547 static std::optional<std::string> fios_scn_path;
550 if (!fios_scn_path) fios_scn_path = FioFindDirectory(
SCENARIO_DIR);
552 _fios_path = &(*fios_scn_path);
559 static FiosType FiosGetHeightmapListCallback(
SaveLoadOperation fop,
const std::string &file,
const char *ext,
char *title,
const char *last)
569 if (strcasecmp(ext,
".png") == 0) type = FIOS_TYPE_PNG;
572 if (strcasecmp(ext,
".bmp") == 0) type = FIOS_TYPE_BMP;
574 if (type == FIOS_TYPE_INVALID)
return FIOS_TYPE_INVALID;
576 TarFileList::iterator it = _tar_filelist[
SCENARIO_DIR].find(file);
588 if (buf.compare(0, buf.size(), it->second.tar_filename, 0, buf.size()) == 0) {
594 if (!match)
return FIOS_TYPE_INVALID;
609 static std::optional<std::string> fios_hmap_path;
611 if (!fios_hmap_path) fios_hmap_path = FioFindDirectory(
HEIGHTMAP_DIR);
613 _fios_path = &(*fios_hmap_path);
626 static std::optional<std::string> fios_screenshot_path;
628 if (!fios_screenshot_path) fios_screenshot_path = FioFindDirectory(
SCREENSHOT_DIR);
630 return fios_screenshot_path->c_str();
637 char filename[MAX_PATH];
641 return this->scenid == other.
scenid &&
642 memcmp(this->md5sum, other.
md5sum,
sizeof(this->md5sum)) == 0;
647 return !(*
this == other);
666 if (this->scanned && !rescan)
return;
669 this->scanned =
true;
672 bool AddFile(
const std::string &filename,
size_t basepath_length,
const std::string &tar_filename)
override
675 if (f ==
nullptr)
return false;
678 int fret = fscanf(f,
"%u", &
id.scenid);
680 if (fret != 1)
return false;
691 if (f ==
nullptr)
return false;
694 while ((len = fread(buffer, 1, (size >
sizeof(buffer)) ?
sizeof(buffer) : size, f)) != 0 && size != 0) {
696 checksum.Append(buffer, len);
698 checksum.Finish(
id.md5sum);
721 if (md5sum ? (memcmp(
id.md5sum, ci->
md5sum,
sizeof(
id.md5sum)) == 0)
@ FT_SCENARIO
old or new scenario
static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last)
Callback for FiosGetFileList.
StringID FiosGetDescText(const char **path, uint64 *total_free)
Get descriptive texts.
@ SAVE_DIR
Base directory for all savegames.
const FiosItem * End() const
Get a pointer behind the last file information.
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...
void Compact()
Compact the list down to the smallest block size boundary.
const char * FiosGetScreenshotDir()
Get the directory for screenshots.
void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list)
Get a list of scenarios.
void ScanScenarios()
Force a (re)scan of the scenarios.
SaveLoadOperation
Operation performed on the file.
@ SCREENSHOT_DIR
Subdirectory for all screenshots.
Searchpath
Types of searchpaths OpenTTD might use.
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.
bool include(std::vector< T > &vec, const T &item)
Helper function to append an item to a vector if it is not already contained Consider using std::set,...
@ HEIGHTMAP_DIR
Subdirectory of scenario for heightmaps.
#define FOR_ALL_SEARCHPATHS(sp)
Iterator for all the search paths.
List of file information.
SaveLoadOperation fop
The kind of file we are looking for.
bool scanned
Whether we've already scanned.
void Clear()
Remove all items from the list.
void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list)
Get a list of heightmaps.
static bool IsInsideMM(const T x, const size_t min, const size_t max)
Checks if a value is in an interval.
AbstractFileType
The different abstract types of files that the system knows about.
static void GetFileTitle(const std::string &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...
FileList & file_list
Destination of the found files.
const TCHAR * OTTD2FS(const char *name, bool console_cp)
Convert from OpenTTD's encoding to that of the local environment.
@ SLO_LOAD
File is being loaded.
@ SLO_SAVE
File is being saved.
std::string FiosMakeHeightmapName(const char *name)
Construct a filename for a height map.
bool FiosDelete(const char *name)
Delete a file.
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override
Try to add a fios item set with the given filename.
const FiosItem * Get(size_t index) const
Get a pointer to the indicated file information.
void Scan(bool rescan)
Scan, but only if it's needed.
FILE * FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
uint32 scenid
ID for the scenario (generated by content).
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop)
Construct a file list with the given kind of files, for the stated purpose.
Container for all important information about a piece of content.
Deals with finding savegames.
byte md5sum[16]
The MD5 checksum.
std::vector< FiosItem > files
The list of files.
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.
const char * FiosBrowseTo(const FiosItem *item)
Browse to a new path based on the passed item, starting at #_fios_path.
const FiosItem * FindItem(const char *file)
Find file information of a file by its name from the file list.
static std::string FiosMakeFilename(const std::string *path, const char *name, const char *ext)
Construct a filename from its components in destination buffer buf.
@ SCENARIO_DIR
Base directory for all scenarios.
Subdirectory subdir
The current sub directory we are searching through.
static bool StrEmpty(const char *s)
Check if a string buffer is empty.
@ FT_SAVEGAME
old or new savegame
fios_getlist_callback_proc * callback_proc
Callback to check whether the file may be added.
FiosItem * Append()
Construct a new entry in the file list.
ScenarioScanner()
Initialise.
uint32 StringID
Numeric value that represents a string, independent of the selected language.
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last)
Callback for FiosGetFileList.
void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list)
Get a list of savegames.
@ NO_DIRECTORY
A path without any base directory.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
@ FT_HEIGHTMAP
heightmap file
Subdirectory
The different kinds of subdirectories OpenTTD uses.
FiosType
Elements of a file system that are recognized.
uint32 unique_id
Unique ID; either GRF ID or shortname.
Basic data to distinguish a scenario.
const char * GetCurrentScreenshotExtension()
Get filename extension of current screenshot file format.
Scanner to scan for a particular type of FIOS file.
Helper for scanning for files with a given name.
static ScenarioScanner _scanner
Scanner for scenarios.
bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override
Add a file with the given filename.
int strnatcmp(const char *s1, const char *s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
uint8 md5sum[16]
MD5 checksum of file.
const FiosItem * Begin() const
Get a pointer to the first file information.
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==().
std::string FiosMakeSavegameName(const char *name)
Make a save game or scenario filename from a name.
FiosFileScanner(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, FileList &file_list)
Create the scanner.
char * strecpy(char *dst, const char *src, const char *last)
Copies characters from one buffer to another.
static DIR * ttd_opendir(const char *path)
A wrapper around opendir() which will convert the string from OPENTTD encoding to that of the filesys...
Scanner to find the unique IDs of scenarios.
const char * FS2OTTD(const TCHAR *name)
Convert to OpenTTD's encoding from that of the local environment.
const char * FindScenario(const ContentInfo *ci, bool md5sum)
Find a given scenario based on its unique ID.
#define lastof(x)
Get the last element of an fixed size array.
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 FioFCloseFile(FILE *f)
Close a file in a safe way.
size_t Length() const
Get the number of files in the list.
bool HasScenario(const ContentInfo *ci, bool md5sum)
Check whether we've got a given scenario based on its unique ID.
bool operator<(const FiosItem &other) const
Compare two FiosItem's.