|
OpenTTD Source
14.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 std::string &path);
39 extern bool FiosIsValidFile(
const std::string &path,
const struct dirent *ent,
struct stat *sb);
40 extern bool FiosIsHiddenFile(
const struct dirent *ent);
41 extern void FiosGetDrives(
FileList &file_list);
44 extern std::string GetOldSaveGameName(
const std::string &file);
55 if ((_savegame_sort_order & SORT_BY_NAME) == 0 && (*this).mtime != other.mtime) {
56 r = this->mtime - other.mtime;
60 if (r == 0)
return false;
61 return (_savegame_sort_order & SORT_DESCENDING) ? r > 0 : r < 0;
75 switch (abstract_filetype) {
104 for (
const auto &it : *
this) {
106 if (file == item->name)
return item;
107 if (file == item->title)
return item;
112 int i = std::strtol(file.data(), &endptr, 10);
113 if (file.data() == endptr || *endptr !=
'\0') i = -1;
115 if (
IsInsideMM(i, 0, this->size()))
return &this->at(i);
119 std::string long_file(file);
121 for (
const auto &it : *
this) {
123 if (long_file == item->name)
return item;
124 if (long_file == item->title)
return item;
145 switch (item->type) {
146 case FIOS_TYPE_DRIVE:
148 assert(_fios_path !=
nullptr);
149 *_fios_path = std::string{ item->title, 0, 1 } +
":" PATHSEP;
153 case FIOS_TYPE_INVALID:
156 case FIOS_TYPE_PARENT: {
157 assert(_fios_path !=
nullptr);
158 auto s = _fios_path->find_last_of(PATHSEPCHAR);
159 if (s != std::string::npos && s != 0) {
160 _fios_path->erase(s);
163 s = _fios_path->find_last_of(PATHSEPCHAR);
164 if (s != std::string::npos) {
165 _fios_path->erase(s + 1);
171 assert(_fios_path !=
nullptr);
172 *_fios_path += item->name;
173 *_fios_path += PATHSEP;
176 case FIOS_TYPE_DIRECT:
177 assert(_fios_path !=
nullptr);
178 *_fios_path = item->name;
182 case FIOS_TYPE_OLDFILE:
183 case FIOS_TYPE_SCENARIO:
184 case FIOS_TYPE_OLD_SCENARIO:
200 static std::string
FiosMakeFilename(
const std::string *path,
const char *name,
const char *ext)
204 if (path !=
nullptr) {
207 if (!buf.empty() && buf.back() == PATHSEPCHAR) buf.pop_back();
211 const char *period = strrchr(name,
'.');
214 return buf + PATHSEP + name + ext;
224 const char *extension = (_game_mode == GM_EDITOR) ?
".scn" :
".sav";
236 std::string ext(
".");
250 return unlink(filename.c_str()) == 0;
253 typedef std::tuple<FiosType, std::string> FiosGetTypeAndNameProc(
SaveLoadOperation fop,
const std::string &filename,
const std::string_view ext);
273 bool AddFile(
const std::string &filename,
size_t basepath_length,
const std::string &tar_filename)
override;
283 auto sep = filename.rfind(
'.');
284 if (sep == std::string::npos)
return false;
285 std::string ext = filename.substr(sep);
288 if (type == FIOS_TYPE_INVALID)
return false;
291 if (filename == fios.name)
return false;
297 HANDLE fh = CreateFile(
OTTD2FS(filename).c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
nullptr, OPEN_EXISTING, 0,
nullptr);
299 if (fh != INVALID_HANDLE_VALUE) {
301 ULARGE_INTEGER ft_int64;
303 if (GetFileTime(fh,
nullptr,
nullptr, &ft) != 0) {
304 ft_int64.HighPart = ft.dwHighDateTime;
305 ft_int64.LowPart = ft.dwLowDateTime;
308 fios->mtime = ft_int64.QuadPart / 10000000ULL - 11644473600ULL;
316 if (stat(filename.c_str(), &sb) == 0) {
317 fios->mtime = sb.st_mtime;
324 fios->name = filename;
328 auto ps = filename.rfind(PATHSEPCHAR);
329 fios->title =
StrMakeValid(filename.substr((ps == std::string::npos ? 0 : ps + 1)));
349 struct dirent *dirent;
356 assert(_fios_path !=
nullptr);
359 if (show_dirs && !FiosIsRoot(*_fios_path)) {
361 fios->type = FIOS_TYPE_PARENT;
365 fios->title =
GetString(STR_SAVELOAD_PARENT_DIRECTORY);
369 if (show_dirs && (dir =
ttd_opendir(_fios_path->c_str())) !=
nullptr) {
370 while ((dirent = readdir(dir)) !=
nullptr) {
371 std::string d_name =
FS2OTTD(dirent->d_name);
374 if (FiosIsValidFile(*_fios_path, dirent, &sb) && S_ISDIR(sb.st_mode) &&
376 d_name !=
"." && d_name !=
"..") {
378 fios->type = FIOS_TYPE_DIR;
382 fios->title =
GetString(STR_SAVELOAD_DIRECTORY);
390 SortingBits order = _savegame_sort_order;
391 _savegame_sort_order = SORT_BY_NAME | SORT_ASCENDING;
393 _savegame_sort_order = order;
402 scanner.
Scan(
nullptr, *_fios_path,
false);
425 if (f ==
nullptr)
return {};
428 size_t read = fread(title, 1,
lengthof(title), f);
459 return { FIOS_TYPE_OLDFILE, GetOldSaveGameName(file) };
463 return { FIOS_TYPE_INVALID, {} };
475 static std::optional<std::string> fios_save_path;
477 if (!fios_save_path) fios_save_path = FioFindDirectory(
SAVE_DIR);
479 _fios_path = &(*fios_save_path);
506 return { FIOS_TYPE_OLD_SCENARIO, GetOldSaveGameName(file) };
510 return { FIOS_TYPE_INVALID, {} };
522 static std::optional<std::string> fios_scn_path;
525 if (!fios_scn_path) fios_scn_path = FioFindDirectory(
SCENARIO_DIR);
527 _fios_path = &(*fios_scn_path);
534 std::tuple<FiosType, std::string> FiosGetHeightmapListCallback(
SaveLoadOperation,
const std::string &file,
const std::string_view ext)
549 if (type == FIOS_TYPE_INVALID)
return { FIOS_TYPE_INVALID, {} };
551 TarFileList::iterator it = _tar_filelist[
SCENARIO_DIR].find(file);
562 if (buf.compare(0, buf.size(), it->second.tar_filename, 0, buf.size()) == 0) {
568 if (!match)
return { FIOS_TYPE_INVALID, {} };
582 static std::optional<std::string> fios_hmap_path;
584 if (!fios_hmap_path) fios_hmap_path = FioFindDirectory(
HEIGHTMAP_DIR);
586 _fios_path = &(*fios_hmap_path);
599 static std::optional<std::string> fios_screenshot_path;
601 if (!fios_screenshot_path) fios_screenshot_path = FioFindDirectory(
SCREENSHOT_DIR);
603 return fios_screenshot_path->c_str();
614 return this->scenid == other.
scenid && this->md5sum == other.
md5sum;
619 return !(*
this == other);
638 if (this->scanned && !rescan)
return;
641 this->scanned =
true;
644 bool AddFile(
const std::string &filename,
size_t,
const std::string &)
override
647 if (f ==
nullptr)
return false;
650 int fret = fscanf(f,
"%u", &
id.scenid);
652 if (fret != 1)
return false;
653 id.filename = filename;
656 uint8_t buffer[1024];
663 if (f ==
nullptr)
return false;
666 while ((len = fread(buffer, 1, (size >
sizeof(buffer)) ?
sizeof(buffer) : size, f)) != 0 && size != 0) {
668 checksum.Append(buffer, len);
670 checksum.Finish(
id.md5sum);
693 if (md5sum ? (
id.md5sum == ci->
md5sum)
695 return id.filename.c_str();
727 static std::optional<std::string> _autosave_path;
728 if (!_autosave_path) _autosave_path = FioFindDirectory(
AUTOSAVE_DIR);
730 static std::string _prefix;
733 static FiosGetTypeAndNameProc *proc = [](
SaveLoadOperation,
const std::string &file,
const std::string_view ext) {
734 if (
StrEqualsIgnoreCase(ext,
".sav") && file.starts_with(_prefix))
return std::tuple(FIOS_TYPE_FILE, std::string{});
735 return std::tuple(FIOS_TYPE_INVALID, std::string{});
739 _prefix = *_autosave_path + this->prefix;
744 scanner.
Scan(
".sav", _autosave_path->c_str(),
false);
747 if (list.begin() != list.end()) {
748 SortingBits order = _savegame_sort_order;
749 _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
750 std::sort(list.begin(), list.end());
751 _savegame_sort_order = order;
753 std::string_view name = list.begin()->title;
754 std::from_chars(name.data() + this->prefix.size(), name.data() + name.size(), this->number);
765 return fmt::format(
"{}{}.sav", this->prefix, this->number);
774 return fmt::format(
"-{}.sav", this->prefix);
bool StrStartsWithIgnoreCase(std::string_view str, const std::string_view prefix)
Check whether the given string starts with the given prefix, ignoring case.
FiosFileScanner(SaveLoadOperation fop, FiosGetTypeAndNameProc *callback_proc, FileList &file_list)
Create the scanner.
MD5Hash md5sum
MD5 checksum of file.
@ FT_SCENARIO
old or new scenario
@ SAVE_DIR
Base directory for all savegames.
constexpr bool IsInsideMM(const T x, const size_t min, const size_t max) noexcept
Checks if a value is in an interval.
DIR * ttd_opendir(const char *path)
A wrapper around opendir() which will convert the string from OPENTTD encoding to that of the filesys...
const char * FiosGetScreenshotDir()
Get the directory for screenshots.
void ScanScenarios()
Force a (re)scan of the scenarios.
FiosNumberedSaveName(const std::string &prefix)
Constructs FiosNumberedSaveName.
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.
static void StrMakeValid(T &dst, const char *str, const char *last, StringValidationSettings settings)
Copies the valid (UTF-8) characters from str up to last to the dst.
@ HEIGHTMAP_DIR
Subdirectory of scenario for heightmaps.
int StrNaturalCompare(std::string_view s1, std::string_view s2, bool ignore_garbage_at_front)
Compares two strings using case insensitive natural sort.
@ AUTOSAVE_DIR
Subdirectory of save for autosaves.
ClientSettings _settings_client
The current settings for this game.
std::string FiosGetCurrentPath()
Get the current path/working directory.
MD5Hash md5sum
The MD5 checksum.
List of file information.
SaveLoadOperation fop
The kind of file we are looking for.
bool scanned
Whether we've already scanned.
const FiosItem * FindItem(const std::string_view file)
Find file information of a file by its name from the file list.
bool include(Container &container, typename Container::const_reference &item)
Helper function to append an item to a container if it is not already contained.
AbstractFileType
The different abstract types of files that the system knows about.
FileList & file_list
Destination of the found files.
@ 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.
std::string FS2OTTD(const std::wstring &name)
Convert to OpenTTD's encoding from a wide string.
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.
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.
Container for all important information about a piece of content.
Deals with finding 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.
static std::string FiosMakeFilename(const std::string *path, const char *name, const char *ext)
Construct a filename from its components in destination buffer buf.
std::tuple< FiosType, std::string > FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext)
Callback for FiosGetFileList.
@ SCENARIO_DIR
Base directory for all scenarios.
Subdirectory subdir
The current sub directory we are searching through.
void FiosGetSavegameList(SaveLoadOperation fop, bool show_dirs, FileList &file_list)
Get a list of savegames.
byte max_num_autosaves
controls how many autosavegames are made before the game starts to overwrite (names them 0 to max_num...
@ FT_SAVEGAME
old or new savegame
uint32_t scenid
ID for the scenario (generated by content).
ScenarioScanner()
Initialise.
void FiosGetScenarioList(SaveLoadOperation fop, bool show_dirs, FileList &file_list)
Get a list of scenarios.
static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAndNameProc *callback_proc, Subdirectory subdir, FileList &file_list)
Fill the list of the files in a directory, according to some arbitrary rule.
@ NO_DIRECTORY
A path without any base directory.
std::tuple< FiosType, std::string > FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const std::string_view ext)
Callback for FiosGetFileList.
std::string GetString(StringID string)
Resolve the given StringID into a std::string with all the associated DParam lookups and formatting.
bool StrEqualsIgnoreCase(const std::string_view str1, const std::string_view str2)
Compares two string( view)s for equality, while ignoring the case of the characters.
bool AddFile(const std::string &filename, size_t, const std::string &) override
Add a file with the given filename.
@ FT_HEIGHTMAP
heightmap file
Subdirectory
The different kinds of subdirectories OpenTTD uses.
void SetDParamStr(size_t n, const char *str)
This function is used to "bind" a C string to a OpenTTD dparam slot.
void FiosGetHeightmapList(SaveLoadOperation fop, bool show_dirs, FileList &file_list)
Get a list of heightmaps.
FiosType
Elements of a file system that are recognized.
bool FiosBrowseTo(const FiosItem *item)
Browse to a new path based on the passed item, starting at #_fios_path.
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.
#define lengthof(x)
Return the length of an fixed size array.
Helper for scanning for files with a given name.
static ScenarioScanner _scanner
Scanner for scenarios.
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 Extension()
Generate an extension for a savegame name.
std::string FiosMakeSavegameName(const char *name)
Make a save game or scenario filename from a name.
static std::string GetFileTitle(const std::string &file, 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...
Scanner to find the unique IDs of scenarios.
const char * FindScenario(const ContentInfo *ci, bool md5sum)
Find a given scenario based on its unique ID.
std::string Filename()
Generate a savegame name and number according to _settings_client.gui.max_num_autosaves.
void BuildFileList(AbstractFileType abstract_filetype, SaveLoadOperation fop, bool show_dirs)
Construct a file list with the given kind of files, for the stated purpose.
std::wstring OTTD2FS(const std::string &name)
Convert from OpenTTD's encoding to a wide string.
uint32_t unique_id
Unique ID; either GRF ID or shortname.
std::string filename
filename of the file.
GUISettings gui
settings related to the GUI
void FioFCloseFile(FILE *f)
Close a file in a safe way.
FiosGetTypeAndNameProc * callback_proc
Callback to check whether the file may be added.
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.