Update to 12.0-beta1
This commit is contained in:
322
src/fileio.cpp
322
src/fileio.cpp
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "fileio_func.h"
|
||||
#include "spriteloader/spriteloader.hpp"
|
||||
#include "debug.h"
|
||||
#include "fios.h"
|
||||
#include "string_func.h"
|
||||
@@ -29,192 +30,12 @@
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
/** Size of the #Fio data buffer. */
|
||||
#define FIO_BUFFER_SIZE 512
|
||||
|
||||
/** Structure for keeping several open files with just one data buffer. */
|
||||
struct Fio {
|
||||
byte *buffer, *buffer_end; ///< position pointer in local buffer and last valid byte of buffer
|
||||
byte buffer_start[FIO_BUFFER_SIZE]; ///< local buffer when read from file
|
||||
size_t pos; ///< current (system) position in file
|
||||
FILE *cur_fh; ///< current file handle
|
||||
std::string filename; ///< current filename
|
||||
std::array<FILE *, MAX_FILE_SLOTS> handles; ///< array of file handles we can have open
|
||||
std::array<std::string, MAX_FILE_SLOTS> filenames; ///< array of filenames we (should) have open
|
||||
std::array<std::string, MAX_FILE_SLOTS> shortnames;///< array of short names for spriteloader's use
|
||||
};
|
||||
|
||||
static Fio _fio; ///< #Fio instance.
|
||||
|
||||
/** Whether the working directory should be scanned. */
|
||||
static bool _do_scan_working_directory = true;
|
||||
|
||||
extern std::string _config_file;
|
||||
extern std::string _highscore_file;
|
||||
|
||||
/**
|
||||
* Get position in the current file.
|
||||
* @return Position in the file.
|
||||
*/
|
||||
size_t FioGetPos()
|
||||
{
|
||||
return _fio.pos + (_fio.buffer - _fio.buffer_end);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filename associated with a slot.
|
||||
* @param slot Index of queried file.
|
||||
* @return Name of the file.
|
||||
*/
|
||||
const char *FioGetFilename(uint8 slot)
|
||||
{
|
||||
return _fio.shortnames[slot].c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Seek in the current file.
|
||||
* @param pos New position.
|
||||
* @param mode Type of seek (\c SEEK_CUR means \a pos is relative to current position, \c SEEK_SET means \a pos is absolute).
|
||||
*/
|
||||
void FioSeekTo(size_t pos, int mode)
|
||||
{
|
||||
if (mode == SEEK_CUR) pos += FioGetPos();
|
||||
_fio.buffer = _fio.buffer_end = _fio.buffer_start + FIO_BUFFER_SIZE;
|
||||
_fio.pos = pos;
|
||||
if (fseek(_fio.cur_fh, _fio.pos, SEEK_SET) < 0) {
|
||||
DEBUG(misc, 0, "Seeking in %s failed", _fio.filename.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to a different file and seek to a position.
|
||||
* @param slot Slot number of the new file.
|
||||
* @param pos New absolute position in the new file.
|
||||
*/
|
||||
void FioSeekToFile(uint8 slot, size_t pos)
|
||||
{
|
||||
FILE *f = _fio.handles[slot];
|
||||
assert(f != nullptr);
|
||||
_fio.cur_fh = f;
|
||||
_fio.filename = _fio.filenames[slot];
|
||||
FioSeekTo(pos, SEEK_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a byte from the file.
|
||||
* @return Read byte.
|
||||
*/
|
||||
byte FioReadByte()
|
||||
{
|
||||
if (_fio.buffer == _fio.buffer_end) {
|
||||
_fio.buffer = _fio.buffer_start;
|
||||
size_t size = fread(_fio.buffer, 1, FIO_BUFFER_SIZE, _fio.cur_fh);
|
||||
_fio.pos += size;
|
||||
_fio.buffer_end = _fio.buffer_start + size;
|
||||
|
||||
if (size == 0) return 0;
|
||||
}
|
||||
return *_fio.buffer++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Skip \a n bytes ahead in the file.
|
||||
* @param n Number of bytes to skip reading.
|
||||
*/
|
||||
void FioSkipBytes(int n)
|
||||
{
|
||||
for (;;) {
|
||||
int m = std::min<int>(_fio.buffer_end - _fio.buffer, n);
|
||||
_fio.buffer += m;
|
||||
n -= m;
|
||||
if (n == 0) break;
|
||||
FioReadByte();
|
||||
n--;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a word (16 bits) from the file (in low endian format).
|
||||
* @return Read word.
|
||||
*/
|
||||
uint16 FioReadWord()
|
||||
{
|
||||
byte b = FioReadByte();
|
||||
return (FioReadByte() << 8) | b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a double word (32 bits) from the file (in low endian format).
|
||||
* @return Read word.
|
||||
*/
|
||||
uint32 FioReadDword()
|
||||
{
|
||||
uint b = FioReadWord();
|
||||
return (FioReadWord() << 16) | b;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a block.
|
||||
* @param ptr Destination buffer.
|
||||
* @param size Number of bytes to read.
|
||||
*/
|
||||
void FioReadBlock(void *ptr, size_t size)
|
||||
{
|
||||
FioSeekTo(FioGetPos(), SEEK_SET);
|
||||
_fio.pos += fread(ptr, 1, size, _fio.cur_fh);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the file at the given slot number.
|
||||
* @param slot File index to close.
|
||||
*/
|
||||
static inline void FioCloseFile(int slot)
|
||||
{
|
||||
if (_fio.handles[slot] != nullptr) {
|
||||
fclose(_fio.handles[slot]);
|
||||
|
||||
_fio.shortnames[slot].clear();
|
||||
|
||||
_fio.handles[slot] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/** Close all slotted open files. */
|
||||
void FioCloseAll()
|
||||
{
|
||||
for (int i = 0; i != lengthof(_fio.handles); i++) {
|
||||
FioCloseFile(i);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a slotted file.
|
||||
* @param slot Index to assign.
|
||||
* @param filename Name of the file at the disk.
|
||||
* @param subdir The sub directory to search this file in.
|
||||
*/
|
||||
void FioOpenFile(int slot, const std::string &filename, Subdirectory subdir)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
f = FioFOpenFile(filename, "rb", subdir);
|
||||
if (f == nullptr) usererror("Cannot open file '%s'", filename.c_str());
|
||||
long pos = ftell(f);
|
||||
if (pos < 0) usererror("Cannot read file '%s'", filename.c_str());
|
||||
|
||||
FioCloseFile(slot); // if file was opened before, close it
|
||||
_fio.handles[slot] = f;
|
||||
_fio.filenames[slot] = filename;
|
||||
|
||||
/* Store the filename without path and extension */
|
||||
auto t = filename.rfind(PATHSEPCHAR);
|
||||
std::string sn = filename.substr(t != std::string::npos ? t + 1 : 0);
|
||||
_fio.shortnames[slot] = sn.substr(0, sn.rfind('.'));
|
||||
strtolower(_fio.shortnames[slot]);
|
||||
|
||||
FioSeekToFile(slot, (size_t)pos);
|
||||
}
|
||||
|
||||
static const char * const _subdirs[] = {
|
||||
"",
|
||||
"save" PATHSEP,
|
||||
@@ -241,6 +62,7 @@ static_assert(lengthof(_subdirs) == NUM_SUBDIRS);
|
||||
* current operating system.
|
||||
*/
|
||||
std::array<std::string, NUM_SEARCHPATHS> _searchpaths;
|
||||
std::vector<Searchpath> _valid_searchpaths;
|
||||
std::array<TarList, NUM_SUBDIRS> _tar_list;
|
||||
TarFileList _tar_filelist[NUM_SUBDIRS];
|
||||
|
||||
@@ -252,11 +74,31 @@ static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links
|
||||
* @param sp the search path to check
|
||||
* @return true if the search path is valid
|
||||
*/
|
||||
bool IsValidSearchPath(Searchpath sp)
|
||||
static bool IsValidSearchPath(Searchpath sp)
|
||||
{
|
||||
return sp < _searchpaths.size() && !_searchpaths[sp].empty();
|
||||
}
|
||||
|
||||
static void FillValidSearchPaths(bool only_local_path)
|
||||
{
|
||||
_valid_searchpaths.clear();
|
||||
for (Searchpath sp = SP_FIRST_DIR; sp < NUM_SEARCHPATHS; sp++) {
|
||||
if (only_local_path) {
|
||||
switch (sp) {
|
||||
case SP_WORKING_DIR: // Can be influence by "-c" option.
|
||||
case SP_BINARY_DIR: // Most likely contains all the language files.
|
||||
case SP_AUTODOWNLOAD_DIR: // Otherwise we cannot download in-game content.
|
||||
break;
|
||||
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsValidSearchPath(sp)) _valid_searchpaths.emplace_back(sp);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given file exists
|
||||
* @param filename the file to try for existence.
|
||||
@@ -279,7 +121,7 @@ bool FioCheckFileExists(const std::string &filename, Subdirectory subdir)
|
||||
*/
|
||||
bool FileExists(const std::string &filename)
|
||||
{
|
||||
return access(OTTD2FS(filename.c_str()), 0) == 0;
|
||||
return access(OTTD2FS(filename).c_str(), 0) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,10 +140,9 @@ void FioFCloseFile(FILE *f)
|
||||
*/
|
||||
std::string FioFindFullPath(Subdirectory subdir, const char *filename)
|
||||
{
|
||||
Searchpath sp;
|
||||
assert(subdir < NUM_SUBDIRS);
|
||||
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
std::string buf = FioGetDirectory(sp, subdir);
|
||||
buf += filename;
|
||||
if (FileExists(buf)) return buf;
|
||||
@@ -326,10 +167,8 @@ std::string FioGetDirectory(Searchpath sp, Subdirectory subdir)
|
||||
|
||||
std::string FioFindDirectory(Subdirectory subdir)
|
||||
{
|
||||
Searchpath sp;
|
||||
|
||||
/* Find and return the first valid directory */
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
std::string ret = FioGetDirectory(sp, subdir);
|
||||
if (FileExists(ret)) return ret;
|
||||
}
|
||||
@@ -358,7 +197,7 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf.c_str())) == INVALID_FILE_ATTRIBUTES) return nullptr;
|
||||
if (mode[0] == 'r' && GetFileAttributes(OTTD2FS(buf).c_str()) == INVALID_FILE_ATTRIBUTES) return nullptr;
|
||||
#endif
|
||||
|
||||
f = fopen(buf.c_str(), mode);
|
||||
@@ -406,11 +245,10 @@ FILE *FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize)
|
||||
FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
|
||||
{
|
||||
FILE *f = nullptr;
|
||||
Searchpath sp;
|
||||
|
||||
assert(subdir < NUM_SUBDIRS || subdir == NO_DIRECTORY);
|
||||
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
f = FioFOpenFileSp(filename, mode, sp, subdir, filesize);
|
||||
if (f != nullptr || subdir == NO_DIRECTORY) break;
|
||||
}
|
||||
@@ -506,11 +344,11 @@ void FioCreateDirectory(const std::string &name)
|
||||
/* Ignore directory creation errors; they'll surface later on, and most
|
||||
* of the time they are 'directory already exists' errors anyhow. */
|
||||
#if defined(_WIN32)
|
||||
CreateDirectory(OTTD2FS(name.c_str()), nullptr);
|
||||
CreateDirectory(OTTD2FS(name).c_str(), nullptr);
|
||||
#elif defined(OS2) && !defined(__INNOTEK_LIBC__)
|
||||
mkdir(OTTD2FS(name.c_str()));
|
||||
mkdir(OTTD2FS(name).c_str());
|
||||
#else
|
||||
mkdir(OTTD2FS(name.c_str()), 0755);
|
||||
mkdir(OTTD2FS(name).c_str(), 0755);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -580,7 +418,7 @@ uint TarScanner::DoScan(Subdirectory sd)
|
||||
|
||||
/* static */ uint TarScanner::DoScan(TarScanner::Mode mode)
|
||||
{
|
||||
DEBUG(misc, 1, "Scanning for tars");
|
||||
Debug(misc, 1, "Scanning for tars");
|
||||
TarScanner fs;
|
||||
uint num = 0;
|
||||
if (mode & TarScanner::BASESET) {
|
||||
@@ -601,7 +439,7 @@ uint TarScanner::DoScan(Subdirectory sd)
|
||||
num += fs.DoScan(SCENARIO_DIR);
|
||||
num += fs.DoScan(HEIGHTMAP_DIR);
|
||||
}
|
||||
DEBUG(misc, 1, "Scan complete, found %d files", num);
|
||||
Debug(misc, 1, "Scan complete, found {} files", num);
|
||||
return num;
|
||||
}
|
||||
|
||||
@@ -680,7 +518,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
/* If we have only zeros in the block, it can be an end-of-file indicator */
|
||||
if (memcmp(&th, &empty[0], 512) == 0) continue;
|
||||
|
||||
DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename.c_str());
|
||||
Debug(misc, 0, "The file '{}' isn't a valid tar-file", filename);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
@@ -703,9 +541,6 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
switch (th.typeflag) {
|
||||
case '\0':
|
||||
case '0': { // regular file
|
||||
/* Ignore empty files */
|
||||
if (skip == 0) break;
|
||||
|
||||
if (strlen(name) == 0) break;
|
||||
|
||||
/* Store this entry in the list */
|
||||
@@ -717,7 +552,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
/* Convert to lowercase and our PATHSEPCHAR */
|
||||
SimplifyFileName(name);
|
||||
|
||||
DEBUG(misc, 6, "Found file in tar: %s (" PRINTF_SIZE " bytes, " PRINTF_SIZE " offset)", name, skip, pos);
|
||||
Debug(misc, 6, "Found file in tar: {} ({} bytes, {} offset)", name, skip, pos);
|
||||
if (_tar_filelist[this->subdir].insert(TarFileList::value_type(name, entry)).second) num++;
|
||||
|
||||
break;
|
||||
@@ -736,7 +571,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
|
||||
/* Only allow relative links */
|
||||
if (link[0] == PATHSEPCHAR) {
|
||||
DEBUG(misc, 1, "Ignoring absolute link in tar: %s -> %s", name, link);
|
||||
Debug(misc, 1, "Ignoring absolute link in tar: {} -> {}", name, link);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -762,7 +597,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
} else if (strcmp(pos, "..") == 0) {
|
||||
/* level up */
|
||||
if (dest[0] == '\0') {
|
||||
DEBUG(misc, 1, "Ignoring link pointing outside of data directory: %s -> %s", name, link);
|
||||
Debug(misc, 1, "Ignoring link pointing outside of data directory: {} -> {}", name, link);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -778,7 +613,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
}
|
||||
|
||||
if (destpos >= lastof(dest)) {
|
||||
DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename.c_str());
|
||||
Debug(misc, 0, "The length of a link in tar-file '{}' is too large (malformed?)", filename);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
@@ -787,7 +622,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
}
|
||||
|
||||
/* Store links in temporary list */
|
||||
DEBUG(misc, 6, "Found link in tar: %s -> %s", name, dest);
|
||||
Debug(misc, 6, "Found link in tar: {} -> {}", name, dest);
|
||||
links.insert(TarLinkList::value_type(name, dest));
|
||||
|
||||
break;
|
||||
@@ -798,7 +633,7 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
SimplifyFileName(name);
|
||||
|
||||
/* Store the first directory name we detect */
|
||||
DEBUG(misc, 6, "Found dir in tar: %s", name);
|
||||
Debug(misc, 6, "Found dir in tar: {}", name);
|
||||
if (_tar_list[this->subdir][filename].empty()) _tar_list[this->subdir][filename] = name;
|
||||
break;
|
||||
|
||||
@@ -810,14 +645,14 @@ bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, co
|
||||
/* Skip to the next block.. */
|
||||
skip = Align(skip, 512);
|
||||
if (fseek(f, skip, SEEK_CUR) < 0) {
|
||||
DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename.c_str());
|
||||
Debug(misc, 0, "The file '{}' can't be read as a valid tar-file", filename);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
pos += skip;
|
||||
}
|
||||
|
||||
DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename.c_str(), num);
|
||||
Debug(misc, 1, "Found tar '{}' with {} new files", filename, num);
|
||||
fclose(f);
|
||||
|
||||
/* Resolve file links and store directory links.
|
||||
@@ -855,7 +690,7 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
|
||||
|
||||
/* The file doesn't have a sub directory! */
|
||||
if (dirname.empty()) {
|
||||
DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename.c_str());
|
||||
Debug(misc, 1, "Extracting {} failed; archive rejected, the contents must be in a sub directory", tar_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -865,7 +700,7 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
|
||||
if (p == std::string::npos) return false;
|
||||
|
||||
filename.replace(p + 1, std::string::npos, dirname);
|
||||
DEBUG(misc, 8, "Extracting %s to directory %s", tar_filename.c_str(), filename.c_str());
|
||||
Debug(misc, 8, "Extracting {} to directory {}", tar_filename, filename);
|
||||
FioCreateDirectory(filename);
|
||||
|
||||
for (TarFileList::iterator it2 = _tar_filelist[subdir].begin(); it2 != _tar_filelist[subdir].end(); it2++) {
|
||||
@@ -873,20 +708,20 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
|
||||
|
||||
filename.replace(p + 1, std::string::npos, it2->first);
|
||||
|
||||
DEBUG(misc, 9, " extracting %s", filename.c_str());
|
||||
Debug(misc, 9, " extracting {}", filename);
|
||||
|
||||
/* First open the file in the .tar. */
|
||||
size_t to_copy = 0;
|
||||
std::unique_ptr<FILE, FileDeleter> in(FioFOpenFileTar(it2->second, &to_copy));
|
||||
if (!in) {
|
||||
DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename.c_str(), tar_filename.c_str());
|
||||
Debug(misc, 6, "Extracting {} failed; could not open {}", filename, tar_filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Now open the 'output' file. */
|
||||
std::unique_ptr<FILE, FileDeleter> out(fopen(filename.c_str(), "wb"));
|
||||
if (!out) {
|
||||
DEBUG(misc, 6, "Extracting %s failed; could not open %s", filename.c_str(), filename.c_str());
|
||||
Debug(misc, 6, "Extracting {} failed; could not open {}", filename, filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -899,12 +734,12 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
|
||||
}
|
||||
|
||||
if (to_copy != 0) {
|
||||
DEBUG(misc, 6, "Extracting %s failed; still %i bytes to copy", filename.c_str(), (int)to_copy);
|
||||
Debug(misc, 6, "Extracting {} failed; still {} bytes to copy", filename, to_copy);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUG(misc, 9, " extraction successful");
|
||||
Debug(misc, 9, " extraction successful");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -940,7 +775,7 @@ static bool ChangeWorkingDirectoryToExecutable(const char *exe)
|
||||
if (s != nullptr) {
|
||||
*s = '\0';
|
||||
if (chdir(tmp) != 0) {
|
||||
DEBUG(misc, 0, "Directory with the binary does not exist?");
|
||||
Debug(misc, 0, "Directory with the binary does not exist?");
|
||||
} else {
|
||||
success = true;
|
||||
}
|
||||
@@ -987,7 +822,7 @@ static std::string GetHomeDir()
|
||||
find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
return std::string(path.Path());
|
||||
#else
|
||||
const char *home_env = getenv("HOME"); // Stack var, shouldn't be freed
|
||||
const char *home_env = std::getenv("HOME"); // Stack var, shouldn't be freed
|
||||
if (home_env != nullptr) return std::string(home_env);
|
||||
|
||||
const struct passwd *pw = getpwuid(getuid());
|
||||
@@ -1005,7 +840,7 @@ void DetermineBasePaths(const char *exe)
|
||||
std::string tmp;
|
||||
const std::string homedir = GetHomeDir();
|
||||
#ifdef USE_XDG
|
||||
const char *xdg_data_home = getenv("XDG_DATA_HOME");
|
||||
const char *xdg_data_home = std::getenv("XDG_DATA_HOME");
|
||||
if (xdg_data_home != nullptr) {
|
||||
tmp = xdg_data_home;
|
||||
tmp += PATHSEP;
|
||||
@@ -1099,7 +934,7 @@ void DetermineBasePaths(const char *exe)
|
||||
if (cwd[0] != '\0') {
|
||||
/* Go back to the current working directory. */
|
||||
if (chdir(cwd) != 0) {
|
||||
DEBUG(misc, 0, "Failed to return to working directory!");
|
||||
Debug(misc, 0, "Failed to return to working directory!");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1126,15 +961,17 @@ std::string _personal_dir;
|
||||
* fill all other paths (save dir, autosave dir etc) and
|
||||
* make the save and scenario directories.
|
||||
* @param exe the path from the current path to the executable
|
||||
* @param only_local_path Whether we shouldn't fill searchpaths with global folders.
|
||||
*/
|
||||
void DeterminePaths(const char *exe)
|
||||
void DeterminePaths(const char *exe, bool only_local_path)
|
||||
{
|
||||
DetermineBasePaths(exe);
|
||||
FillValidSearchPaths(only_local_path);
|
||||
|
||||
#ifdef USE_XDG
|
||||
std::string config_home;
|
||||
const std::string homedir = GetHomeDir();
|
||||
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
|
||||
const char *xdg_config_home = std::getenv("XDG_CONFIG_HOME");
|
||||
if (xdg_config_home != nullptr) {
|
||||
config_home = xdg_config_home;
|
||||
config_home += PATHSEP;
|
||||
@@ -1148,10 +985,9 @@ void DeterminePaths(const char *exe)
|
||||
AppendPathSeparator(config_home);
|
||||
#endif
|
||||
|
||||
Searchpath sp;
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue;
|
||||
DEBUG(misc, 4, "%s added as search path", _searchpaths[sp].c_str());
|
||||
Debug(misc, 4, "{} added as search path", _searchpaths[sp]);
|
||||
}
|
||||
|
||||
std::string config_dir;
|
||||
@@ -1184,19 +1020,30 @@ void DeterminePaths(const char *exe)
|
||||
_config_file = config_dir + "openttd.cfg";
|
||||
}
|
||||
|
||||
DEBUG(misc, 3, "%s found as config directory", config_dir.c_str());
|
||||
Debug(misc, 3, "{} found as config directory", config_dir);
|
||||
|
||||
_highscore_file = config_dir + "hs.dat";
|
||||
extern std::string _hotkeys_file;
|
||||
_hotkeys_file = config_dir + "hotkeys.cfg";
|
||||
extern std::string _windows_file;
|
||||
_windows_file = config_dir + "windows.cfg";
|
||||
extern std::string _private_file;
|
||||
_private_file = config_dir + "private.cfg";
|
||||
extern std::string _secrets_file;
|
||||
_secrets_file = config_dir + "secrets.cfg";
|
||||
|
||||
#ifdef USE_XDG
|
||||
if (config_dir == config_home) {
|
||||
/* We are using the XDG configuration home for the config file,
|
||||
* then store the rest in the XDG data home folder. */
|
||||
_personal_dir = _searchpaths[SP_PERSONAL_DIR_XDG];
|
||||
if (only_local_path) {
|
||||
/* In case of XDG and we only want local paths and we detected that
|
||||
* the user either manually indicated the XDG path or didn't use
|
||||
* "-c" option, we change the working-dir to the XDG personal-dir,
|
||||
* as this is most likely what the user is expecting. */
|
||||
_searchpaths[SP_WORKING_DIR] = _searchpaths[SP_PERSONAL_DIR_XDG];
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
@@ -1209,7 +1056,7 @@ void DeterminePaths(const char *exe)
|
||||
FioCreateDirectory(_personal_dir);
|
||||
#endif
|
||||
|
||||
DEBUG(misc, 3, "%s found as personal directory", _personal_dir.c_str());
|
||||
Debug(misc, 3, "{} found as personal directory", _personal_dir);
|
||||
|
||||
static const Subdirectory default_subdirs[] = {
|
||||
SAVE_DIR, AUTOSAVE_DIR, SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR, SCREENSHOT_DIR
|
||||
@@ -1221,7 +1068,9 @@ void DeterminePaths(const char *exe)
|
||||
|
||||
/* If we have network we make a directory for the autodownloading of content */
|
||||
_searchpaths[SP_AUTODOWNLOAD_DIR] = _personal_dir + "content_download" PATHSEP;
|
||||
Debug(misc, 4, "{} added as search path", _searchpaths[SP_AUTODOWNLOAD_DIR]);
|
||||
FioCreateDirectory(_searchpaths[SP_AUTODOWNLOAD_DIR]);
|
||||
FillValidSearchPaths(only_local_path);
|
||||
|
||||
/* Create the directory for each of the types of content */
|
||||
const Subdirectory dirs[] = { SCENARIO_DIR, HEIGHTMAP_DIR, BASESET_DIR, NEWGRF_DIR, AI_DIR, AI_LIBRARY_DIR, GAME_DIR, GAME_LIBRARY_DIR };
|
||||
@@ -1259,7 +1108,7 @@ void SanitizeFilename(char *filename)
|
||||
* @return Pointer to new memory containing the loaded data, or \c nullptr if loading failed.
|
||||
* @note If \a maxsize less than the length of the file, loading fails.
|
||||
*/
|
||||
std::unique_ptr<char> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize)
|
||||
std::unique_ptr<char[]> ReadFileToMem(const std::string &filename, size_t &lenp, size_t maxsize)
|
||||
{
|
||||
FILE *in = fopen(filename.c_str(), "rb");
|
||||
if (in == nullptr) return nullptr;
|
||||
@@ -1271,10 +1120,7 @@ std::unique_ptr<char> ReadFileToMem(const std::string &filename, size_t &lenp, s
|
||||
fseek(in, 0, SEEK_SET);
|
||||
if (len > maxsize) return nullptr;
|
||||
|
||||
/* std::unique_ptr assumes new/delete unless a custom deleter is supplied.
|
||||
* As we don't want to have to carry that deleter all over the place, use
|
||||
* new directly to allocate the memory instead of malloc. */
|
||||
std::unique_ptr<char> mem(static_cast<char *>(::operator new(len + 1)));
|
||||
std::unique_ptr<char[]> mem = std::make_unique<char[]>(len + 1);
|
||||
|
||||
mem.get()[len] = 0;
|
||||
if (fread(mem.get(), len, 1, in) != 1) return nullptr;
|
||||
@@ -1318,7 +1164,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s
|
||||
if (path == nullptr || (dir = ttd_opendir(path)) == nullptr) return 0;
|
||||
|
||||
while ((dirent = readdir(dir)) != nullptr) {
|
||||
const char *d_name = FS2OTTD(dirent->d_name);
|
||||
std::string d_name = FS2OTTD(dirent->d_name);
|
||||
|
||||
if (!FiosIsValidFile(path, dirent, &sb)) continue;
|
||||
|
||||
@@ -1328,7 +1174,7 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s
|
||||
if (S_ISDIR(sb.st_mode)) {
|
||||
/* Directory */
|
||||
if (!recursive) continue;
|
||||
if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
|
||||
if (d_name == "." || d_name == "..") continue;
|
||||
AppendPathSeparator(filename);
|
||||
num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive);
|
||||
} else if (S_ISREG(sb.st_mode)) {
|
||||
@@ -1348,12 +1194,12 @@ static uint ScanPath(FileScanner *fs, const char *extension, const char *path, s
|
||||
* @param extension the extension of files to search for.
|
||||
* @param tar the tar to search in.
|
||||
*/
|
||||
static uint ScanTar(FileScanner *fs, const char *extension, TarFileList::iterator tar)
|
||||
static uint ScanTar(FileScanner *fs, const char *extension, const TarFileList::value_type &tar)
|
||||
{
|
||||
uint num = 0;
|
||||
const auto &filename = (*tar).first;
|
||||
const auto &filename = tar.first;
|
||||
|
||||
if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, 0, (*tar).second.tar_filename)) num++;
|
||||
if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, 0, tar.second.tar_filename)) num++;
|
||||
|
||||
return num;
|
||||
}
|
||||
@@ -1371,11 +1217,9 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r
|
||||
{
|
||||
this->subdir = sd;
|
||||
|
||||
Searchpath sp;
|
||||
TarFileList::iterator tar;
|
||||
uint num = 0;
|
||||
|
||||
FOR_ALL_SEARCHPATHS(sp) {
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
/* Don't search in the working directory */
|
||||
if (sp == SP_WORKING_DIR && !_do_scan_working_directory) continue;
|
||||
|
||||
@@ -1384,7 +1228,7 @@ uint FileScanner::Scan(const char *extension, Subdirectory sd, bool tars, bool r
|
||||
}
|
||||
|
||||
if (tars && sd != NO_DIRECTORY) {
|
||||
FOR_ALL_TARS(tar, sd) {
|
||||
for (const auto &tar : _tar_filelist[sd]) {
|
||||
num += ScanTar(this, extension, tar);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user