mirror of https://github.com/OpenTTD/OpenTTD
Codechange: Replace all FILE * with FileHandle RAII class. (#12718)
This removes the need to manually ensure all files are closed.pull/12941/head
parent
3784a3d3d6
commit
908ee7292b
|
@ -34,11 +34,11 @@ static const uint ICON_MAX_RECURSE = 10; ///< Maximum number of recursion
|
|||
return aliases;
|
||||
}
|
||||
|
||||
FILE *_iconsole_output_file;
|
||||
std::optional<FileHandle> _iconsole_output_file;
|
||||
|
||||
void IConsoleInit()
|
||||
{
|
||||
_iconsole_output_file = nullptr;
|
||||
_iconsole_output_file = std::nullopt;
|
||||
_redirect_console_to_client = INVALID_CLIENT_ID;
|
||||
_redirect_console_to_admin = INVALID_ADMIN_ID;
|
||||
|
||||
|
@ -49,13 +49,12 @@ void IConsoleInit()
|
|||
|
||||
static void IConsoleWriteToLogFile(const std::string &string)
|
||||
{
|
||||
if (_iconsole_output_file != nullptr) {
|
||||
if (_iconsole_output_file.has_value()) {
|
||||
/* if there is an console output file ... also print it there */
|
||||
try {
|
||||
fmt::print(_iconsole_output_file, "{}{}\n", GetLogPrefix(), string);
|
||||
fmt::print(*_iconsole_output_file, "{}{}\n", GetLogPrefix(), string);
|
||||
} catch (const std::system_error &) {
|
||||
fclose(_iconsole_output_file);
|
||||
_iconsole_output_file = nullptr;
|
||||
_iconsole_output_file.reset();
|
||||
IConsolePrint(CC_ERROR, "Cannot write to console log file; closing the log file.");
|
||||
}
|
||||
}
|
||||
|
@ -63,10 +62,9 @@ static void IConsoleWriteToLogFile(const std::string &string)
|
|||
|
||||
bool CloseConsoleLogIfActive()
|
||||
{
|
||||
if (_iconsole_output_file != nullptr) {
|
||||
if (_iconsole_output_file.has_value()) {
|
||||
IConsolePrint(CC_INFO, "Console log file closed.");
|
||||
fclose(_iconsole_output_file);
|
||||
_iconsole_output_file = nullptr;
|
||||
_iconsole_output_file.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -1130,15 +1130,14 @@ DEF_CONSOLE_CMD(ConExec)
|
|||
|
||||
if (argc < 2) return false;
|
||||
|
||||
FILE *script_file = FioFOpenFile(argv[1], "r", BASE_DIR);
|
||||
auto script_file = FioFOpenFile(argv[1], "r", BASE_DIR);
|
||||
|
||||
if (script_file == nullptr) {
|
||||
if (!script_file.has_value()) {
|
||||
if (argc == 2 || atoi(argv[2]) != 0) IConsolePrint(CC_ERROR, "Script file '{}' not found.", argv[1]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_script_current_depth == 11) {
|
||||
FioFCloseFile(script_file);
|
||||
IConsolePrint(CC_ERROR, "Maximum 'exec' depth reached; script A is calling script B is calling script C ... more than 10 times.");
|
||||
return true;
|
||||
}
|
||||
|
@ -1147,7 +1146,7 @@ DEF_CONSOLE_CMD(ConExec)
|
|||
uint script_depth = _script_current_depth;
|
||||
|
||||
char cmdline[ICON_CMDLN_SIZE];
|
||||
while (fgets(cmdline, sizeof(cmdline), script_file) != nullptr) {
|
||||
while (fgets(cmdline, sizeof(cmdline), *script_file) != nullptr) {
|
||||
/* Remove newline characters from the executing script */
|
||||
for (char *cmdptr = cmdline; *cmdptr != '\0'; cmdptr++) {
|
||||
if (*cmdptr == '\n' || *cmdptr == '\r') {
|
||||
|
@ -1163,12 +1162,11 @@ DEF_CONSOLE_CMD(ConExec)
|
|||
if (_script_current_depth == script_depth - 1) break;
|
||||
}
|
||||
|
||||
if (ferror(script_file)) {
|
||||
if (ferror(*script_file) != 0) {
|
||||
IConsolePrint(CC_ERROR, "Encountered error while trying to read from script file '{}'.", argv[1]);
|
||||
}
|
||||
|
||||
if (_script_current_depth == script_depth) _script_current_depth--;
|
||||
FioFCloseFile(script_file);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1222,7 +1220,7 @@ extern void ShowFramerateWindow();
|
|||
|
||||
DEF_CONSOLE_CMD(ConScript)
|
||||
{
|
||||
extern FILE *_iconsole_output_file;
|
||||
extern std::optional<FileHandle> _iconsole_output_file;
|
||||
|
||||
if (argc == 0) {
|
||||
IConsolePrint(CC_HELP, "Start or stop logging console output to a file. Usage: 'script <filename>'.");
|
||||
|
@ -1233,8 +1231,8 @@ DEF_CONSOLE_CMD(ConScript)
|
|||
if (!CloseConsoleLogIfActive()) {
|
||||
if (argc < 2) return false;
|
||||
|
||||
_iconsole_output_file = fopen(argv[1], "ab");
|
||||
if (_iconsole_output_file == nullptr) {
|
||||
_iconsole_output_file = FileHandle::Open(argv[1], "ab");
|
||||
if (!_iconsole_output_file.has_value()) {
|
||||
IConsolePrint(CC_ERROR, "Could not open console log file '{}'.", argv[1]);
|
||||
} else {
|
||||
IConsolePrint(CC_INFO, "Console log output started to '{}'.", argv[1]);
|
||||
|
|
|
@ -190,15 +190,14 @@ bool CrashLog::WriteCrashLog()
|
|||
{
|
||||
this->crashlog_filename = this->CreateFileName(".json.log");
|
||||
|
||||
FILE *file = FioFOpenFile(this->crashlog_filename, "w", NO_DIRECTORY);
|
||||
if (file == nullptr) return false;
|
||||
auto file = FioFOpenFile(this->crashlog_filename, "w", NO_DIRECTORY);
|
||||
if (!file.has_value()) return false;
|
||||
|
||||
std::string survey_json = this->survey.dump(4);
|
||||
|
||||
size_t len = survey_json.size();
|
||||
size_t written = fwrite(survey_json.data(), 1, len, file);
|
||||
size_t written = fwrite(survey_json.data(), 1, len, *file);
|
||||
|
||||
FioFCloseFile(file);
|
||||
return len == written;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,18 +109,18 @@ void DumpDebugFacilityNames(std::back_insert_iterator<std::string> &output_itera
|
|||
void DebugPrint(const char *category, int level, const std::string &message)
|
||||
{
|
||||
if (strcmp(category, "desync") == 0 && level != 0) {
|
||||
static FILE *f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
|
||||
if (f == nullptr) return;
|
||||
static auto f = FioFOpenFile("commands-out.log", "wb", AUTOSAVE_DIR);
|
||||
if (!f.has_value()) return;
|
||||
|
||||
fmt::print(f, "{}{}\n", GetLogPrefix(true), message);
|
||||
fflush(f);
|
||||
fmt::print(*f, "{}{}\n", GetLogPrefix(true), message);
|
||||
fflush(*f);
|
||||
#ifdef RANDOM_DEBUG
|
||||
} else if (strcmp(category, "random") == 0) {
|
||||
static FILE *f = FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR);
|
||||
if (f == nullptr) return;
|
||||
static auto f = FioFOpenFile("random-out.log", "wb", AUTOSAVE_DIR);
|
||||
if (!f.has_value()) return;
|
||||
|
||||
fmt::print(f, "{}\n", message);
|
||||
fflush(f);
|
||||
fmt::print(*f, "{}\n", message);
|
||||
fflush(*f);
|
||||
#endif
|
||||
} else {
|
||||
fmt::print(stderr, "{}dbg: [{}:{}] {}\n", GetLogPrefix(true), category, level, message);
|
||||
|
|
|
@ -11,8 +11,8 @@
|
|||
#include "fileio_func.h"
|
||||
#include "debug.h"
|
||||
|
||||
std::string _log_file; ///< File to reroute output of a forked OpenTTD to
|
||||
std::unique_ptr<FILE, FileDeleter> _log_fd; ///< File to reroute output of a forked OpenTTD to
|
||||
std::string _log_file; ///< Filename to reroute output of a forked OpenTTD to
|
||||
std::optional<FileHandle> _log_fd; ///< File to reroute output of a forked OpenTTD to
|
||||
|
||||
#if defined(UNIX)
|
||||
|
||||
|
@ -31,17 +31,17 @@ void DedicatedFork()
|
|||
|
||||
case 0: { // We're the child
|
||||
/* Open the log-file to log all stuff too */
|
||||
_log_fd.reset(fopen(_log_file.c_str(), "a"));
|
||||
if (!_log_fd) {
|
||||
_log_fd = FileHandle::Open(_log_file, "a");
|
||||
if (!_log_fd.has_value()) {
|
||||
perror("Unable to open logfile");
|
||||
exit(1);
|
||||
}
|
||||
/* Redirect stdout and stderr to log-file */
|
||||
if (dup2(fileno(_log_fd.get()), fileno(stdout)) == -1) {
|
||||
if (dup2(fileno(*_log_fd), fileno(stdout)) == -1) {
|
||||
perror("Rerouting stdout");
|
||||
exit(1);
|
||||
}
|
||||
if (dup2(fileno(_log_fd.get()), fileno(stderr)) == -1) {
|
||||
if (dup2(fileno(*_log_fd), fileno(stderr)) == -1) {
|
||||
perror("Rerouting stderr");
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -134,8 +134,7 @@ bool DriverFactoryBase::SelectDriverImpl(const std::string &name, Driver::Type t
|
|||
}
|
||||
|
||||
/* Write empty file to note we are attempting hardware acceleration. */
|
||||
auto f = FioFOpenFile(HWACCELERATION_TEST_FILE, "w", BASE_DIR);
|
||||
FioFCloseFile(f);
|
||||
FioFOpenFile(HWACCELERATION_TEST_FILE, "w", BASE_DIR);
|
||||
}
|
||||
|
||||
Driver *oldd = *GetActiveDriver(type);
|
||||
|
|
112
src/fileio.cpp
112
src/fileio.cpp
|
@ -120,11 +120,8 @@ static void FillValidSearchPaths(bool only_local_path)
|
|||
*/
|
||||
bool FioCheckFileExists(const std::string &filename, Subdirectory subdir)
|
||||
{
|
||||
FILE *f = FioFOpenFile(filename, "rb", subdir);
|
||||
if (f == nullptr) return false;
|
||||
|
||||
FioFCloseFile(f);
|
||||
return true;
|
||||
auto f = FioFOpenFile(filename, "rb", subdir);
|
||||
return f.has_value();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,14 +135,6 @@ bool FileExists(const std::string &filename)
|
|||
return std::filesystem::exists(OTTD2FS(filename), ec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a file in a safe way.
|
||||
*/
|
||||
void FioFCloseFile(FILE *f)
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a path to the filename in one of the search directories.
|
||||
* @param subdir Subdirectory to try.
|
||||
|
@ -191,7 +180,7 @@ std::string FioFindDirectory(Subdirectory subdir)
|
|||
return _personal_dir;
|
||||
}
|
||||
|
||||
static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize)
|
||||
static std::optional<FileHandle> FioFOpenFileSp(const std::string &filename, const char *mode, Searchpath sp, Subdirectory subdir, size_t *filesize)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* fopen is implemented as a define with ellipses for
|
||||
|
@ -201,7 +190,6 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc
|
|||
wchar_t Lmode[5];
|
||||
MultiByteToWideChar(CP_ACP, 0, mode, -1, Lmode, static_cast<int>(std::size(Lmode)));
|
||||
#endif
|
||||
FILE *f = nullptr;
|
||||
std::string buf;
|
||||
|
||||
if (subdir == NO_DIRECTORY) {
|
||||
|
@ -210,17 +198,17 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc
|
|||
buf = _searchpaths[sp] + _subdirs[subdir] + filename;
|
||||
}
|
||||
|
||||
f = fopen(buf.c_str(), mode);
|
||||
auto f = FileHandle::Open(buf, mode);
|
||||
#if !defined(_WIN32)
|
||||
if (f == nullptr && strtolower(buf, subdir == NO_DIRECTORY ? 0 : _searchpaths[sp].size() - 1) ) {
|
||||
f = fopen(buf.c_str(), mode);
|
||||
if (!f.has_value() && strtolower(buf, subdir == NO_DIRECTORY ? 0 : _searchpaths[sp].size() - 1) ) {
|
||||
f = FileHandle::Open(buf, mode);
|
||||
}
|
||||
#endif
|
||||
if (f != nullptr && filesize != nullptr) {
|
||||
if (f.has_value() && filesize != nullptr) {
|
||||
/* Find the size of the file */
|
||||
fseek(f, 0, SEEK_END);
|
||||
*filesize = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
fseek(*f, 0, SEEK_END);
|
||||
*filesize = ftell(*f);
|
||||
fseek(*f, 0, SEEK_SET);
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
@ -232,14 +220,13 @@ static FILE *FioFOpenFileSp(const std::string &filename, const char *mode, Searc
|
|||
* @return File handle of the opened file, or \c nullptr if the file is not available.
|
||||
* @note The file is read from within the tar file, and may not return \c EOF after reading the whole file.
|
||||
*/
|
||||
FILE *FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize)
|
||||
static std::optional<FileHandle> FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize)
|
||||
{
|
||||
FILE *f = fopen(entry.tar_filename.c_str(), "rb");
|
||||
if (f == nullptr) return f;
|
||||
auto f = FileHandle::Open(entry.tar_filename, "rb");
|
||||
if (!f.has_value()) return std::nullopt;
|
||||
|
||||
if (fseek(f, entry.position, SEEK_SET) < 0) {
|
||||
fclose(f);
|
||||
return nullptr;
|
||||
if (fseek(*f, entry.position, SEEK_SET) < 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (filesize != nullptr) *filesize = entry.size;
|
||||
|
@ -252,19 +239,18 @@ FILE *FioFOpenFileTar(const TarFileListEntry &entry, size_t *filesize)
|
|||
* @param subdir Subdirectory to open.
|
||||
* @return File handle of the opened file, or \c nullptr if the file is not available.
|
||||
*/
|
||||
FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
|
||||
std::optional<FileHandle> FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize)
|
||||
{
|
||||
FILE *f = nullptr;
|
||||
|
||||
std::optional<FileHandle> f = std::nullopt;
|
||||
assert(subdir < NUM_SUBDIRS || subdir == NO_DIRECTORY);
|
||||
|
||||
for (Searchpath sp : _valid_searchpaths) {
|
||||
f = FioFOpenFileSp(filename, mode, sp, subdir, filesize);
|
||||
if (f != nullptr || subdir == NO_DIRECTORY) break;
|
||||
if (f.has_value() || subdir == NO_DIRECTORY) break;
|
||||
}
|
||||
|
||||
/* We can only use .tar in case of data-dir, and read-mode */
|
||||
if (f == nullptr && mode[0] == 'r' && subdir != NO_DIRECTORY) {
|
||||
if (!f.has_value() && mode[0] == 'r' && subdir != NO_DIRECTORY) {
|
||||
/* Filenames in tars are always forced to be lowercase */
|
||||
std::string resolved_name = filename;
|
||||
strtolower(resolved_name);
|
||||
|
@ -275,7 +261,7 @@ FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory s
|
|||
std::string token;
|
||||
while (std::getline(ss, token, PATHSEPCHAR)) {
|
||||
if (token == "..") {
|
||||
if (tokens.size() < 2) return nullptr;
|
||||
if (tokens.size() < 2) return std::nullopt;
|
||||
tokens.pop_back();
|
||||
} else if (token == ".") {
|
||||
/* Do nothing. "." means current folder, but you can create tar files with "." in the path.
|
||||
|
@ -303,11 +289,11 @@ FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory s
|
|||
|
||||
/* Sometimes a full path is given. To support
|
||||
* the 'subdirectory' must be 'removed'. */
|
||||
if (f == nullptr && subdir != NO_DIRECTORY) {
|
||||
if (!f.has_value() && subdir != NO_DIRECTORY) {
|
||||
switch (subdir) {
|
||||
case BASESET_DIR:
|
||||
f = FioFOpenFile(filename, mode, OLD_GM_DIR, filesize);
|
||||
if (f != nullptr) break;
|
||||
if (f.has_value()) break;
|
||||
[[fallthrough]];
|
||||
case NEWGRF_DIR:
|
||||
f = FioFOpenFile(filename, mode, OLD_DATA_DIR, filesize);
|
||||
|
@ -480,12 +466,13 @@ bool TarScanner::AddFile(const std::string &filename, size_t, [[maybe_unused]] c
|
|||
TarList::iterator it = _tar_list[this->subdir].find(filename);
|
||||
if (it != _tar_list[this->subdir].end()) return false;
|
||||
|
||||
FILE *f = fopen(filename.c_str(), "rb");
|
||||
auto of = FileHandle::Open(filename, "rb");
|
||||
/* Although the file has been found there can be
|
||||
* a number of reasons we cannot open the file.
|
||||
* Most common case is when we simply have not
|
||||
* been given read access. */
|
||||
if (f == nullptr) return false;
|
||||
if (!of.has_value()) return false;
|
||||
auto &f = *of;
|
||||
|
||||
_tar_list[this->subdir][filename] = std::string{};
|
||||
|
||||
|
@ -510,7 +497,6 @@ bool TarScanner::AddFile(const std::string &filename, size_t, [[maybe_unused]] c
|
|||
if (memcmp(&th, &empty[0], 512) == 0) continue;
|
||||
|
||||
Debug(misc, 0, "The file '{}' isn't a valid tar-file", filename);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -584,14 +570,12 @@ bool TarScanner::AddFile(const std::string &filename, size_t, [[maybe_unused]] c
|
|||
skip = Align(skip, 512);
|
||||
if (fseek(f, skip, SEEK_CUR) < 0) {
|
||||
Debug(misc, 0, "The file '{}' can't be read as a valid tar-file", filename);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
pos += skip;
|
||||
}
|
||||
|
||||
Debug(misc, 4, "Found tar '{}' with {} new files", filename, num);
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -638,15 +622,15 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
|
|||
|
||||
/* 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) {
|
||||
auto in = FioFOpenFileTar(it2.second, &to_copy);
|
||||
if (!in.has_value()) {
|
||||
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) {
|
||||
auto out = FileHandle::Open(filename, "wb");
|
||||
if (!out.has_value()) {
|
||||
Debug(misc, 6, "Extracting {} failed; could not open {}", filename, filename);
|
||||
return false;
|
||||
}
|
||||
|
@ -655,8 +639,8 @@ bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
|
|||
char buffer[4096];
|
||||
size_t read;
|
||||
for (; to_copy != 0; to_copy -= read) {
|
||||
read = fread(buffer, 1, std::min(to_copy, lengthof(buffer)), in.get());
|
||||
if (read <= 0 || fwrite(buffer, 1, read, out.get()) != read) break;
|
||||
read = fread(buffer, 1, std::min(to_copy, lengthof(buffer)), *in);
|
||||
if (read <= 0 || fwrite(buffer, 1, read, *out) != read) break;
|
||||
}
|
||||
|
||||
if (to_copy != 0) {
|
||||
|
@ -1040,20 +1024,18 @@ void SanitizeFilename(std::string &filename)
|
|||
*/
|
||||
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;
|
||||
auto in = FileHandle::Open(filename, "rb");
|
||||
if (!in.has_value()) return nullptr;
|
||||
|
||||
FileCloser fc(in);
|
||||
|
||||
fseek(in, 0, SEEK_END);
|
||||
size_t len = ftell(in);
|
||||
fseek(in, 0, SEEK_SET);
|
||||
fseek(*in, 0, SEEK_END);
|
||||
size_t len = ftell(*in);
|
||||
fseek(*in, 0, SEEK_SET);
|
||||
if (len > maxsize) return nullptr;
|
||||
|
||||
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;
|
||||
if (fread(mem.get(), len, 1, *in) != 1) return nullptr;
|
||||
|
||||
lenp = len;
|
||||
return mem;
|
||||
|
@ -1177,3 +1159,23 @@ uint FileScanner::Scan(const std::string_view extension, const std::string &dire
|
|||
AppendPathSeparator(path);
|
||||
return ScanPath(this, extension, OTTD2FS(path), path.size(), recursive);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open an RAII file handle if possible.
|
||||
* The canonical RAII-way is for FileHandle to open the file and throw an exception on failure, but we don't want that.
|
||||
* @param filename UTF-8 encoded filename to open.
|
||||
* @param mode Mode to open file.
|
||||
* @return FileHandle, or std::nullopt on failure.
|
||||
*/
|
||||
std::optional<FileHandle> FileHandle::Open(const std::string &filename, const std::string &mode)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* Windows also requires mode to be wchar_t. */
|
||||
auto f = _wfopen(OTTD2FS(filename).c_str(), OTTD2FS(mode).c_str());
|
||||
#else
|
||||
auto f = fopen(filename.c_str(), mode.c_str());
|
||||
#endif /* _WIN32 */
|
||||
|
||||
if (f == nullptr) return std::nullopt;
|
||||
return FileHandle(f);
|
||||
}
|
||||
|
|
|
@ -13,8 +13,7 @@
|
|||
#include "core/enum_type.hpp"
|
||||
#include "fileio_type.h"
|
||||
|
||||
void FioFCloseFile(FILE *f);
|
||||
FILE *FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr);
|
||||
std::optional<FileHandle> FioFOpenFile(const std::string &filename, const char *mode, Subdirectory subdir, size_t *filesize = nullptr);
|
||||
bool FioCheckFileExists(const std::string &filename, Subdirectory subdir);
|
||||
std::string FioFindFullPath(Subdirectory subdir, const std::string &filename);
|
||||
std::string FioGetDirectory(Searchpath sp, Subdirectory subdir);
|
||||
|
@ -81,24 +80,4 @@ public:
|
|||
|
||||
DECLARE_ENUM_AS_BIT_SET(TarScanner::Mode)
|
||||
|
||||
/** Auto-close a file upon scope exit. */
|
||||
class FileCloser {
|
||||
FILE *f;
|
||||
|
||||
public:
|
||||
FileCloser(FILE *_f) : f(_f) {}
|
||||
~FileCloser()
|
||||
{
|
||||
fclose(f);
|
||||
}
|
||||
};
|
||||
|
||||
/** Helper to manage a FILE with a \c std::unique_ptr. */
|
||||
struct FileDeleter {
|
||||
void operator()(FILE *f)
|
||||
{
|
||||
if (f) fclose(f);
|
||||
}
|
||||
};
|
||||
|
||||
#endif /* FILEIO_FUNC_H */
|
||||
|
|
|
@ -150,4 +150,33 @@ enum Searchpath : unsigned {
|
|||
|
||||
DECLARE_POSTFIX_INCREMENT(Searchpath)
|
||||
|
||||
class FileHandle {
|
||||
public:
|
||||
static std::optional<FileHandle> Open(const std::string &filename, const std::string &mode);
|
||||
|
||||
inline void Close() { this->f.reset(); }
|
||||
|
||||
inline operator FILE *()
|
||||
{
|
||||
assert(this->f != nullptr);
|
||||
return this->f.get();
|
||||
}
|
||||
|
||||
private:
|
||||
/** Helper to close a FILE * with a \c std::unique_ptr. */
|
||||
struct FileDeleter {
|
||||
void operator ()(FILE *f)
|
||||
{
|
||||
if (f != nullptr) fclose(f);
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<FILE, FileDeleter> f;
|
||||
|
||||
FileHandle(FILE *f) : f(f) { assert(this->f != nullptr); }
|
||||
};
|
||||
|
||||
/* Ensure has_value() is used consistently. */
|
||||
template <> constexpr std::optional<FileHandle>::operator bool() const noexcept = delete;
|
||||
|
||||
#endif /* FILEIO_TYPE_H */
|
||||
|
|
20
src/fios.cpp
20
src/fios.cpp
|
@ -385,12 +385,11 @@ static void FiosGetFileList(SaveLoadOperation fop, bool show_dirs, FiosGetTypeAn
|
|||
*/
|
||||
static std::string GetFileTitle(const std::string &file, Subdirectory subdir)
|
||||
{
|
||||
FILE *f = FioFOpenFile(file + ".title", "r", subdir);
|
||||
if (f == nullptr) return {};
|
||||
auto f = FioFOpenFile(file + ".title", "r", subdir);
|
||||
if (!f.has_value()) return {};
|
||||
|
||||
char title[80];
|
||||
size_t read = fread(title, 1, lengthof(title), f);
|
||||
FioFCloseFile(f);
|
||||
size_t read = fread(title, 1, lengthof(title), *f);
|
||||
|
||||
assert(read <= lengthof(title));
|
||||
return StrMakeValid({title, read});
|
||||
|
@ -607,12 +606,11 @@ public:
|
|||
|
||||
bool AddFile(const std::string &filename, size_t, const std::string &) override
|
||||
{
|
||||
FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR);
|
||||
if (f == nullptr) return false;
|
||||
auto f = FioFOpenFile(filename, "r", SCENARIO_DIR);
|
||||
if (!f.has_value()) return false;
|
||||
|
||||
ScenarioIdentifier id;
|
||||
int fret = fscanf(f, "%u", &id.scenid);
|
||||
FioFCloseFile(f);
|
||||
int fret = fscanf(*f, "%u", &id.scenid);
|
||||
if (fret != 1) return false;
|
||||
id.filename = filename;
|
||||
|
||||
|
@ -624,17 +622,15 @@ public:
|
|||
* This is safe as we check on extension which
|
||||
* must always exist. */
|
||||
f = FioFOpenFile(filename.substr(0, filename.rfind('.')), "rb", SCENARIO_DIR, &size);
|
||||
if (f == nullptr) return false;
|
||||
if (!f.has_value()) return false;
|
||||
|
||||
/* calculate md5sum */
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, *f)) != 0 && size != 0) {
|
||||
size -= len;
|
||||
checksum.Append(buffer, len);
|
||||
}
|
||||
checksum.Finish(id.md5sum);
|
||||
|
||||
FioFCloseFile(f);
|
||||
|
||||
include(*this, id);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -49,10 +49,8 @@ void CDECL StrgenFatalI(const std::string &msg)
|
|||
LanguageStrings ReadRawLanguageStrings(const std::string &file)
|
||||
{
|
||||
size_t to_read;
|
||||
FILE *fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read);
|
||||
if (fh == nullptr) return LanguageStrings();
|
||||
|
||||
FileCloser fhClose(fh);
|
||||
auto fh = FioFOpenFile(file, "rb", GAME_DIR, &to_read);
|
||||
if (!fh.has_value()) return LanguageStrings();
|
||||
|
||||
auto pos = file.rfind(PATHSEPCHAR);
|
||||
if (pos == std::string::npos) return LanguageStrings();
|
||||
|
@ -64,7 +62,7 @@ LanguageStrings ReadRawLanguageStrings(const std::string &file)
|
|||
LanguageStrings ret(langname.substr(0, langname.find('.')));
|
||||
|
||||
char buffer[2048];
|
||||
while (to_read != 0 && fgets(buffer, sizeof(buffer), fh) != nullptr) {
|
||||
while (to_read != 0 && fgets(buffer, sizeof(buffer), *fh) != nullptr) {
|
||||
size_t len = strlen(buffer);
|
||||
|
||||
/* Remove trailing spaces/newlines from the string. */
|
||||
|
|
|
@ -418,12 +418,10 @@ void GraphicsSet::CopyCompatibleConfig(const GraphicsSet &src)
|
|||
/* static */ MD5File::ChecksumResult GraphicsSet::CheckMD5(const MD5File *file, Subdirectory subdir)
|
||||
{
|
||||
size_t size = 0;
|
||||
FILE *f = FioFOpenFile(file->filename, "rb", subdir, &size);
|
||||
if (f == nullptr) return MD5File::CR_NO_FILE;
|
||||
auto f = FioFOpenFile(file->filename, "rb", subdir, &size);
|
||||
if (!f.has_value()) return MD5File::CR_NO_FILE;
|
||||
|
||||
size_t max = GRFGetSizeOfDataSection(f);
|
||||
|
||||
FioFCloseFile(f);
|
||||
size_t max = GRFGetSizeOfDataSection(*f);
|
||||
|
||||
return file->CheckMD5(subdir, max);
|
||||
}
|
||||
|
@ -441,9 +439,8 @@ void GraphicsSet::CopyCompatibleConfig(const GraphicsSet &src)
|
|||
MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir, size_t max_size) const
|
||||
{
|
||||
size_t size;
|
||||
FILE *f = FioFOpenFile(this->filename, "rb", subdir, &size);
|
||||
|
||||
if (f == nullptr) return CR_NO_FILE;
|
||||
auto f = FioFOpenFile(this->filename, "rb", subdir, &size);
|
||||
if (!f.has_value()) return CR_NO_FILE;
|
||||
|
||||
size = std::min(size, max_size);
|
||||
|
||||
|
@ -452,13 +449,11 @@ MD5File::ChecksumResult MD5File::CheckMD5(Subdirectory subdir, size_t max_size)
|
|||
MD5Hash digest;
|
||||
size_t len;
|
||||
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, *f)) != 0 && size != 0) {
|
||||
size -= len;
|
||||
checksum.Append(buffer, len);
|
||||
}
|
||||
|
||||
FioFCloseFile(f);
|
||||
|
||||
checksum.Finish(digest);
|
||||
return this->hash == digest ? CR_MATCH : CR_MISMATCH;
|
||||
}
|
||||
|
|
|
@ -136,12 +136,11 @@ static void ReadHeightmapPNGImageData(std::span<uint8_t> map, png_structp png_pt
|
|||
*/
|
||||
static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector<uint8_t> *map)
|
||||
{
|
||||
FILE *fp;
|
||||
png_structp png_ptr = nullptr;
|
||||
png_infop info_ptr = nullptr;
|
||||
|
||||
fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR);
|
||||
if (fp == nullptr) {
|
||||
auto fp = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR);
|
||||
if (!fp.has_value()) {
|
||||
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
@ -149,19 +148,17 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
|
|||
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (png_ptr == nullptr) {
|
||||
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR);
|
||||
fclose(fp);
|
||||
return false;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == nullptr || setjmp(png_jmpbuf(png_ptr))) {
|
||||
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_MISC, WL_ERROR);
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
||||
png_init_io(png_ptr, fp);
|
||||
png_init_io(png_ptr, *fp);
|
||||
|
||||
/* Allocate memory and read image, without alpha or 16-bit samples
|
||||
* (result is either 8-bit indexed/grayscale or 24-bit RGB) */
|
||||
|
@ -172,7 +169,6 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
|
|||
* (this should have been taken care of by stripping alpha and 16-bit samples on load) */
|
||||
if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) {
|
||||
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_PNGMAP_IMAGE_TYPE, WL_ERROR);
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
@ -182,7 +178,6 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
|
|||
|
||||
if (!IsValidHeightmapDimension(width, height)) {
|
||||
ShowErrorMessage(STR_ERROR_PNGMAP, STR_ERROR_HEIGHTMAP_TOO_LARGE, WL_ERROR);
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return false;
|
||||
}
|
||||
|
@ -195,7 +190,6 @@ static bool ReadHeightmapPNG(const char *filename, uint *x, uint *y, std::vector
|
|||
*x = width;
|
||||
*y = height;
|
||||
|
||||
fclose(fp);
|
||||
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
|
||||
return true;
|
||||
}
|
||||
|
@ -263,15 +257,15 @@ static void ReadHeightmapBMPImageData(std::span<uint8_t> map, const BmpInfo &inf
|
|||
*/
|
||||
static bool ReadHeightmapBMP(const char *filename, uint *x, uint *y, std::vector<uint8_t> *map)
|
||||
{
|
||||
BmpInfo info{};
|
||||
BmpData data{};
|
||||
|
||||
if (!FioCheckFileExists(filename, HEIGHTMAP_DIR)) {
|
||||
auto f = FioFOpenFile(filename, "rb", HEIGHTMAP_DIR);
|
||||
if (!f.has_value()) {
|
||||
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_PNGMAP_FILE_NOT_FOUND, WL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
RandomAccessFile file(filename, HEIGHTMAP_DIR);
|
||||
BmpInfo info{};
|
||||
BmpData data{};
|
||||
|
||||
if (!BmpReadHeader(file, info, data)) {
|
||||
ShowErrorMessage(STR_ERROR_BMPMAP, STR_ERROR_BMPMAP_IMAGE_TYPE, WL_ERROR);
|
||||
|
|
|
@ -122,18 +122,19 @@ int8_t SaveHighScoreValueNetwork()
|
|||
/** Save HighScore table to file */
|
||||
void SaveToHighScore()
|
||||
{
|
||||
std::unique_ptr<FILE, FileDeleter> fp(fopen(_highscore_file.c_str(), "wb"));
|
||||
if (fp == nullptr) return;
|
||||
auto ofp = FileHandle::Open(_highscore_file, "wb");
|
||||
if (!ofp.has_value()) return;
|
||||
auto &fp = *ofp;
|
||||
|
||||
/* Does not iterate through the complete array!. */
|
||||
for (int i = 0; i < SP_SAVED_HIGHSCORE_END; i++) {
|
||||
for (HighScore &hs : _highscore_table[i]) {
|
||||
/* This code is weird and old fashioned to keep compatibility with the old high score files. */
|
||||
uint8_t name_length = ClampTo<uint8_t>(hs.name.size());
|
||||
if (fwrite(&name_length, sizeof(name_length), 1, fp.get()) != 1 || // Write the string length of the name
|
||||
fwrite(hs.name.data(), name_length, 1, fp.get()) > 1 || // Yes... could be 0 bytes too
|
||||
fwrite(&hs.score, sizeof(hs.score), 1, fp.get()) != 1 ||
|
||||
fwrite(" ", 2, 1, fp.get()) != 1) { // Used to be hs.title, not saved anymore; compatibility
|
||||
if (fwrite(&name_length, sizeof(name_length), 1, fp) != 1 || // Write the string length of the name
|
||||
fwrite(hs.name.data(), name_length, 1, fp) > 1 || // Yes... could be 0 bytes too
|
||||
fwrite(&hs.score, sizeof(hs.score), 1, fp) != 1 ||
|
||||
fwrite(" ", 2, 1, fp) != 1) { // Used to be hs.title, not saved anymore; compatibility
|
||||
Debug(misc, 1, "Could not save highscore.");
|
||||
return;
|
||||
}
|
||||
|
@ -146,8 +147,9 @@ void LoadFromHighScore()
|
|||
{
|
||||
std::fill(_highscore_table.begin(), _highscore_table.end(), HighScores{});
|
||||
|
||||
std::unique_ptr<FILE, FileDeleter> fp(fopen(_highscore_file.c_str(), "rb"));
|
||||
if (fp == nullptr) return;
|
||||
auto ofp = FileHandle::Open(_highscore_file, "rb");
|
||||
if (!ofp.has_value()) return;
|
||||
auto &fp = *ofp;
|
||||
|
||||
/* Does not iterate through the complete array!. */
|
||||
for (int i = 0; i < SP_SAVED_HIGHSCORE_END; i++) {
|
||||
|
@ -156,10 +158,10 @@ void LoadFromHighScore()
|
|||
uint8_t name_length;
|
||||
char buffer[std::numeric_limits<decltype(name_length)>::max() + 1];
|
||||
|
||||
if (fread(&name_length, sizeof(name_length), 1, fp.get()) != 1 ||
|
||||
fread(buffer, name_length, 1, fp.get()) > 1 || // Yes... could be 0 bytes too
|
||||
fread(&hs.score, sizeof(hs.score), 1, fp.get()) != 1 ||
|
||||
fseek(fp.get(), 2, SEEK_CUR) == -1) { // Used to be hs.title, not saved anymore; compatibility
|
||||
if (fread(&name_length, sizeof(name_length), 1, fp) != 1 ||
|
||||
fread(buffer, name_length, 1, fp) > 1 || // Yes... could be 0 bytes too
|
||||
fread(&hs.score, sizeof(hs.score), 1, fp) != 1 ||
|
||||
fseek(fp, 2, SEEK_CUR) == -1) { // Used to be hs.title, not saved anymore; compatibility
|
||||
Debug(misc, 1, "Highscore corrupted");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ bool IniFile::SaveToDisk(const std::string &filename)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* virtual */ FILE *IniFile::OpenFile(const std::string &filename, Subdirectory subdir, size_t *size)
|
||||
/* virtual */ std::optional<FileHandle> IniFile::OpenFile(const std::string &filename, Subdirectory subdir, size_t *size)
|
||||
{
|
||||
/* Open the text file in binary mode to prevent end-of-line translations
|
||||
* done by ftell() and friends, as defined by K&R. */
|
||||
|
|
|
@ -194,13 +194,13 @@ void IniLoadFile::LoadFromDisk(const std::string &filename, Subdirectory subdir)
|
|||
std::string comment;
|
||||
|
||||
size_t end;
|
||||
FILE *in = this->OpenFile(filename, subdir, &end);
|
||||
if (in == nullptr) return;
|
||||
auto in = this->OpenFile(filename, subdir, &end);
|
||||
if (!in.has_value()) return;
|
||||
|
||||
end += ftell(in);
|
||||
end += ftell(*in);
|
||||
|
||||
/* for each line in the file */
|
||||
while (static_cast<size_t>(ftell(in)) < end && fgets(buffer, sizeof(buffer), in)) {
|
||||
while (static_cast<size_t>(ftell(*in)) < end && fgets(buffer, sizeof(buffer), *in)) {
|
||||
char c, *s;
|
||||
/* trim whitespace from the left side */
|
||||
for (s = buffer; *s == ' ' || *s == '\t'; s++) {}
|
||||
|
@ -272,7 +272,5 @@ void IniLoadFile::LoadFromDisk(const std::string &filename, Subdirectory subdir)
|
|||
}
|
||||
|
||||
this->comment = std::move(comment);
|
||||
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,9 +71,9 @@ struct IniLoadFile {
|
|||
* @param filename Name of the INI file.
|
||||
* @param subdir The subdir to load the file from.
|
||||
* @param[out] size Size of the opened file.
|
||||
* @return File handle of the opened file, or \c nullptr.
|
||||
* @return File handle of the opened file, or \c std::nullopt.
|
||||
*/
|
||||
virtual FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) = 0;
|
||||
virtual std::optional<FileHandle> OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) = 0;
|
||||
|
||||
/**
|
||||
* Report an error about the file contents.
|
||||
|
@ -90,7 +90,7 @@ struct IniFile : IniLoadFile {
|
|||
|
||||
bool SaveToDisk(const std::string &filename);
|
||||
|
||||
FILE *OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) override;
|
||||
std::optional<FileHandle> OpenFile(const std::string &filename, Subdirectory subdir, size_t *size) override;
|
||||
void ReportFileError(const char * const pre, const char * const buffer, const char * const post) override;
|
||||
};
|
||||
|
||||
|
|
|
@ -82,23 +82,23 @@ struct DLSFile {
|
|||
std::vector<DLSWave> waves;
|
||||
|
||||
/** Try loading a DLS file into memory. */
|
||||
bool LoadFile(const wchar_t *file);
|
||||
bool LoadFile(const std::string &file);
|
||||
|
||||
private:
|
||||
/** Load an articulation structure from a DLS file. */
|
||||
bool ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out);
|
||||
bool ReadDLSArticulation(FileHandle &f, DWORD list_length, std::vector<CONNECTION> &out);
|
||||
/** Load a list of regions from a DLS file. */
|
||||
bool ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument);
|
||||
bool ReadDLSRegionList(FileHandle &f, DWORD list_length, DLSInstrument &instrument);
|
||||
/** Load a single region from a DLS file. */
|
||||
bool ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out);
|
||||
bool ReadDLSRegion(FileHandle &f, DWORD list_length, std::vector<DLSRegion> &out);
|
||||
/** Load a list of instruments from a DLS file. */
|
||||
bool ReadDLSInstrumentList(FILE *f, DWORD list_length);
|
||||
bool ReadDLSInstrumentList(FileHandle &f, DWORD list_length);
|
||||
/** Load a single instrument from a DLS file. */
|
||||
bool ReadDLSInstrument(FILE *f, DWORD list_length);
|
||||
bool ReadDLSInstrument(FileHandle &f, DWORD list_length);
|
||||
/** Load a list of waves from a DLS file. */
|
||||
bool ReadDLSWaveList(FILE *f, DWORD list_length);
|
||||
bool ReadDLSWaveList(FileHandle &f, DWORD list_length);
|
||||
/** Load a single wave from a DLS file. */
|
||||
bool ReadDLSWave(FILE *f, DWORD list_length, long offset);
|
||||
bool ReadDLSWave(FileHandle &f, DWORD list_length, long offset);
|
||||
};
|
||||
|
||||
/** A RIFF chunk header. */
|
||||
|
@ -154,7 +154,7 @@ static std::vector<IDirectMusicDownload *> _dls_downloads;
|
|||
static FMusicDriver_DMusic iFMusicDriver_DMusic;
|
||||
|
||||
|
||||
bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNECTION> &out)
|
||||
bool DLSFile::ReadDLSArticulation(FileHandle &f, DWORD list_length, std::vector<CONNECTION> &out)
|
||||
{
|
||||
while (list_length > 0) {
|
||||
ChunkHeader chunk;
|
||||
|
@ -180,7 +180,7 @@ bool DLSFile::ReadDLSArticulation(FILE *f, DWORD list_length, std::vector<CONNEC
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &out)
|
||||
bool DLSFile::ReadDLSRegion(FileHandle &f, DWORD list_length, std::vector<DLSRegion> &out)
|
||||
{
|
||||
out.push_back(DLSRegion());
|
||||
DLSRegion ®ion = out.back();
|
||||
|
@ -239,7 +239,7 @@ bool DLSFile::ReadDLSRegion(FILE *f, DWORD list_length, std::vector<DLSRegion> &
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instrument)
|
||||
bool DLSFile::ReadDLSRegionList(FileHandle &f, DWORD list_length, DLSInstrument &instrument)
|
||||
{
|
||||
while (list_length > 0) {
|
||||
ChunkHeader chunk;
|
||||
|
@ -265,7 +265,7 @@ bool DLSFile::ReadDLSRegionList(FILE *f, DWORD list_length, DLSInstrument &instr
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
|
||||
bool DLSFile::ReadDLSInstrument(FileHandle &f, DWORD list_length)
|
||||
{
|
||||
this->instruments.push_back(DLSInstrument());
|
||||
DLSInstrument &instrument = this->instruments.back();
|
||||
|
@ -309,7 +309,7 @@ bool DLSFile::ReadDLSInstrument(FILE *f, DWORD list_length)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
|
||||
bool DLSFile::ReadDLSInstrumentList(FileHandle &f, DWORD list_length)
|
||||
{
|
||||
while (list_length > 0) {
|
||||
ChunkHeader chunk;
|
||||
|
@ -337,7 +337,7 @@ bool DLSFile::ReadDLSInstrumentList(FILE *f, DWORD list_length)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length, long offset)
|
||||
bool DLSFile::ReadDLSWave(FileHandle &f, DWORD list_length, long offset)
|
||||
{
|
||||
this->waves.push_back(DLSWave());
|
||||
DLSWave &wave = this->waves.back();
|
||||
|
@ -397,7 +397,7 @@ bool DLSFile::ReadDLSWave(FILE *f, DWORD list_length, long offset)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
|
||||
bool DLSFile::ReadDLSWaveList(FileHandle &f, DWORD list_length)
|
||||
{
|
||||
long base_offset = ftell(f);
|
||||
|
||||
|
@ -429,14 +429,13 @@ bool DLSFile::ReadDLSWaveList(FILE *f, DWORD list_length)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DLSFile::LoadFile(const wchar_t *file)
|
||||
bool DLSFile::LoadFile(const std::string &file)
|
||||
{
|
||||
Debug(driver, 2, "DMusic: Try to load DLS file {}", FS2OTTD(file));
|
||||
Debug(driver, 2, "DMusic: Try to load DLS file {}", file);
|
||||
|
||||
FILE *f = _wfopen(file, L"rb");
|
||||
if (f == nullptr) return false;
|
||||
|
||||
FileCloser f_scope(f);
|
||||
auto of = FileHandle::Open(file, "rb");
|
||||
if (!of.has_value()) return false;
|
||||
auto &f = *of;
|
||||
|
||||
/* Check DLS file header. */
|
||||
ChunkHeader hdr;
|
||||
|
@ -871,7 +870,7 @@ static const char *LoadDefaultDLSFile(const char *user_dls)
|
|||
if (SUCCEEDED(RegQueryValueEx(hkDM, L"GMFilePath", nullptr, nullptr, (LPBYTE)dls_path, &buf_size))) {
|
||||
wchar_t expand_path[MAX_PATH * 2];
|
||||
ExpandEnvironmentStrings(dls_path, expand_path, static_cast<DWORD>(std::size(expand_path)));
|
||||
if (!dls_file.LoadFile(expand_path)) Debug(driver, 1, "Failed to load default GM DLS file from registry");
|
||||
if (!dls_file.LoadFile(FS2OTTD(expand_path))) Debug(driver, 1, "Failed to load default GM DLS file from registry");
|
||||
}
|
||||
RegCloseKey(hkDM);
|
||||
}
|
||||
|
@ -882,10 +881,10 @@ static const char *LoadDefaultDLSFile(const char *user_dls)
|
|||
wchar_t path[MAX_PATH];
|
||||
ExpandEnvironmentStrings(DLS_GM_FILE, path, static_cast<DWORD>(std::size(path)));
|
||||
|
||||
if (!dls_file.LoadFile(path)) return "Can't load GM DLS collection";
|
||||
if (!dls_file.LoadFile(FS2OTTD(path))) return "Can't load GM DLS collection";
|
||||
}
|
||||
} else {
|
||||
if (!dls_file.LoadFile(OTTD2FS(user_dls).c_str())) return "Can't load GM DLS collection";
|
||||
if (!dls_file.LoadFile(user_dls)) return "Can't load GM DLS collection";
|
||||
}
|
||||
|
||||
/* Get download port and allocate download IDs. */
|
||||
|
|
|
@ -70,7 +70,7 @@ public:
|
|||
* @param file file to read from at current position
|
||||
* @param len number of bytes to read
|
||||
*/
|
||||
ByteBuffer(FILE *file, size_t len)
|
||||
ByteBuffer(FileHandle &file, size_t len)
|
||||
{
|
||||
this->buf.resize(len);
|
||||
if (fread(this->buf.data(), 1, len, file) == len) {
|
||||
|
@ -186,7 +186,7 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
static bool ReadTrackChunk(FILE *file, MidiFile &target)
|
||||
static bool ReadTrackChunk(FileHandle &file, MidiFile &target)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
|
||||
|
@ -405,10 +405,9 @@ static bool FixupMidiData(MidiFile &target)
|
|||
*/
|
||||
bool MidiFile::ReadSMFHeader(const std::string &filename, SMFHeader &header)
|
||||
{
|
||||
FILE *file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR);
|
||||
if (!file) return false;
|
||||
bool result = ReadSMFHeader(file, header);
|
||||
FioFCloseFile(file);
|
||||
auto file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR);
|
||||
if (!file.has_value()) return false;
|
||||
bool result = ReadSMFHeader(*file, header);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -419,7 +418,7 @@ bool MidiFile::ReadSMFHeader(const std::string &filename, SMFHeader &header)
|
|||
* @param[out] header filled with data read
|
||||
* @return true if a header in correct format could be read from the file
|
||||
*/
|
||||
bool MidiFile::ReadSMFHeader(FILE *file, SMFHeader &header)
|
||||
bool MidiFile::ReadSMFHeader(FileHandle &file, SMFHeader &header)
|
||||
{
|
||||
/* Try to read header, fixed size */
|
||||
uint8_t buffer[14];
|
||||
|
@ -453,31 +452,26 @@ bool MidiFile::LoadFile(const std::string &filename)
|
|||
this->tempos.clear();
|
||||
this->tickdiv = 0;
|
||||
|
||||
bool success = false;
|
||||
FILE *file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR);
|
||||
if (file == nullptr) return false;
|
||||
auto file = FioFOpenFile(filename, "rb", Subdirectory::BASESET_DIR);
|
||||
if (!file.has_value()) return false;
|
||||
|
||||
SMFHeader header;
|
||||
if (!ReadSMFHeader(file, header)) goto cleanup;
|
||||
if (!ReadSMFHeader(*file, header)) return false;
|
||||
|
||||
/* Only format 0 (single-track) and format 1 (multi-track single-song) are accepted for now */
|
||||
if (header.format != 0 && header.format != 1) goto cleanup;
|
||||
if (header.format != 0 && header.format != 1) return false;
|
||||
/* Doesn't support SMPTE timecode files */
|
||||
if ((header.tickdiv & 0x8000) != 0) goto cleanup;
|
||||
if ((header.tickdiv & 0x8000) != 0) return false;
|
||||
|
||||
this->tickdiv = header.tickdiv;
|
||||
|
||||
for (; header.tracks > 0; header.tracks--) {
|
||||
if (!ReadTrackChunk(file, *this)) {
|
||||
goto cleanup;
|
||||
if (!ReadTrackChunk(*file, *this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
success = FixupMidiData(*this);
|
||||
|
||||
cleanup:
|
||||
FioFCloseFile(file);
|
||||
return success;
|
||||
return FixupMidiData(*this);
|
||||
}
|
||||
|
||||
|
||||
|
@ -873,7 +867,7 @@ void MidiFile::MoveFrom(MidiFile &other)
|
|||
other.tickdiv = 0;
|
||||
}
|
||||
|
||||
static void WriteVariableLen(FILE *f, uint32_t value)
|
||||
static void WriteVariableLen(FileHandle &f, uint32_t value)
|
||||
{
|
||||
if (value <= 0x7F) {
|
||||
uint8_t tb = value;
|
||||
|
@ -906,10 +900,9 @@ static void WriteVariableLen(FILE *f, uint32_t value)
|
|||
*/
|
||||
bool MidiFile::WriteSMF(const std::string &filename)
|
||||
{
|
||||
FILE *f = FioFOpenFile(filename, "wb", Subdirectory::NO_DIRECTORY);
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
auto of = FioFOpenFile(filename, "wb", Subdirectory::NO_DIRECTORY);
|
||||
if (!of.has_value()) return false;
|
||||
auto &f = *of;
|
||||
|
||||
/* SMF header */
|
||||
const uint8_t fileheader[] = {
|
||||
|
@ -1007,7 +1000,6 @@ bool MidiFile::WriteSMF(const std::string &filename)
|
|||
}
|
||||
|
||||
/* Fail for any other commands */
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -1023,7 +1015,6 @@ bool MidiFile::WriteSMF(const std::string &filename)
|
|||
tracksize = TO_BE32(tracksize);
|
||||
fwrite(&tracksize, 4, 1, f);
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define MUSIC_MIDIFILE_HPP
|
||||
|
||||
#include "../stdafx.h"
|
||||
#include "../fileio_type.h"
|
||||
#include "midi.h"
|
||||
|
||||
struct MusicSongInfo;
|
||||
|
@ -44,7 +45,7 @@ struct MidiFile {
|
|||
|
||||
static std::string GetSMFFile(const MusicSongInfo &song);
|
||||
static bool ReadSMFHeader(const std::string &filename, SMFHeader &header);
|
||||
static bool ReadSMFHeader(FILE *file, SMFHeader &header);
|
||||
static bool ReadSMFHeader(FileHandle &file, SMFHeader &header);
|
||||
};
|
||||
|
||||
#endif /* MUSIC_MIDIFILE_HPP */
|
||||
|
|
|
@ -1112,18 +1112,18 @@ void NetworkGameLoop()
|
|||
|
||||
#ifdef DEBUG_DUMP_COMMANDS
|
||||
/* Loading of the debug commands from -ddesync>=1 */
|
||||
static FILE *f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
|
||||
static auto f = FioFOpenFile("commands.log", "rb", SAVE_DIR);
|
||||
static TimerGameEconomy::Date next_date(0);
|
||||
static uint32_t next_date_fract;
|
||||
static CommandPacket *cp = nullptr;
|
||||
static bool check_sync_state = false;
|
||||
static uint32_t sync_state[2];
|
||||
if (f == nullptr && next_date == 0) {
|
||||
if (!f.has_value() && next_date == 0) {
|
||||
Debug(desync, 0, "Cannot open commands.log");
|
||||
next_date = TimerGameEconomy::Date(1);
|
||||
}
|
||||
|
||||
while (f != nullptr && !feof(f)) {
|
||||
while (f.has_value() && !feof(*f)) {
|
||||
if (TimerGameEconomy::date == next_date && TimerGameEconomy::date_fract == next_date_fract) {
|
||||
if (cp != nullptr) {
|
||||
NetworkSendCommand(cp->cmd, cp->err_msg, nullptr, cp->company, cp->data);
|
||||
|
@ -1156,7 +1156,7 @@ void NetworkGameLoop()
|
|||
if (cp != nullptr || check_sync_state) break;
|
||||
|
||||
char buff[4096];
|
||||
if (fgets(buff, lengthof(buff), f) == nullptr) break;
|
||||
if (fgets(buff, lengthof(buff), *f) == nullptr) break;
|
||||
|
||||
char *p = buff;
|
||||
/* Ignore the "[date time] " part of the message */
|
||||
|
@ -1225,10 +1225,9 @@ void NetworkGameLoop()
|
|||
NOT_REACHED();
|
||||
}
|
||||
}
|
||||
if (f != nullptr && feof(f)) {
|
||||
if (f.has_value() && feof(*f)) {
|
||||
Debug(desync, 0, "End of commands.log");
|
||||
fclose(f);
|
||||
f = nullptr;
|
||||
f.reset();
|
||||
}
|
||||
#endif /* DEBUG_DUMP_COMMANDS */
|
||||
if (_frame_counter >= _frame_counter_max) {
|
||||
|
|
|
@ -404,16 +404,16 @@ static bool GunzipFile(const ContentInfo *ci)
|
|||
bool ret = true;
|
||||
|
||||
/* Need to open the file with fopen() to support non-ASCII on Windows. */
|
||||
FILE *ftmp = fopen(GetFullFilename(ci, true).c_str(), "rb");
|
||||
if (ftmp == nullptr) return false;
|
||||
auto ftmp = FileHandle::Open(GetFullFilename(ci, true), "rb");
|
||||
if (!ftmp.has_value()) return false;
|
||||
/* Duplicate the handle, and close the FILE*, to avoid double-closing the handle later. */
|
||||
int fdup = dup(fileno(ftmp));
|
||||
int fdup = dup(fileno(*ftmp));
|
||||
gzFile fin = gzdopen(fdup, "rb");
|
||||
fclose(ftmp);
|
||||
ftmp.reset();
|
||||
|
||||
FILE *fout = fopen(GetFullFilename(ci, false).c_str(), "wb");
|
||||
auto fout = FileHandle::Open(GetFullFilename(ci, false), "wb");
|
||||
|
||||
if (fin == nullptr || fout == nullptr) {
|
||||
if (fin == nullptr || !fout.has_value()) {
|
||||
ret = false;
|
||||
} else {
|
||||
uint8_t buff[8192];
|
||||
|
@ -437,7 +437,7 @@ static bool GunzipFile(const ContentInfo *ci)
|
|||
if (errnum != 0 && errnum != Z_STREAM_END) ret = false;
|
||||
break;
|
||||
}
|
||||
if (read < 0 || static_cast<size_t>(read) != fwrite(buff, 1, read, fout)) {
|
||||
if (read < 0 || static_cast<size_t>(read) != fwrite(buff, 1, read, *fout)) {
|
||||
/* If gzread() returns -1, there was an error in archive */
|
||||
ret = false;
|
||||
break;
|
||||
|
@ -453,7 +453,6 @@ static bool GunzipFile(const ContentInfo *ci)
|
|||
/* Failing gzdopen does not close the passed file descriptor. */
|
||||
close(fdup);
|
||||
}
|
||||
if (fout != nullptr) fclose(fout);
|
||||
|
||||
return ret;
|
||||
#else
|
||||
|
@ -468,14 +467,14 @@ static bool GunzipFile(const ContentInfo *ci)
|
|||
* @param amount The number of bytes to write.
|
||||
* @return The number of bytes that were written.
|
||||
*/
|
||||
static inline ssize_t TransferOutFWrite(FILE *file, const char *buffer, size_t amount)
|
||||
static inline ssize_t TransferOutFWrite(std::optional<FileHandle> &file, const char *buffer, size_t amount)
|
||||
{
|
||||
return fwrite(buffer, 1, amount, file);
|
||||
return fwrite(buffer, 1, amount, *file);
|
||||
}
|
||||
|
||||
bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p)
|
||||
{
|
||||
if (this->curFile == nullptr) {
|
||||
if (!this->curFile.has_value()) {
|
||||
delete this->curInfo;
|
||||
/* When we haven't opened a file this must be our first packet with metadata. */
|
||||
this->curInfo = new ContentInfo;
|
||||
|
@ -491,12 +490,11 @@ bool ClientNetworkContentSocketHandler::Receive_SERVER_CONTENT(Packet &p)
|
|||
} else {
|
||||
/* We have a file opened, thus are downloading internal content */
|
||||
size_t toRead = p.RemainingBytesToTransfer();
|
||||
if (toRead != 0 && static_cast<size_t>(p.TransferOut(TransferOutFWrite, this->curFile)) != toRead) {
|
||||
if (toRead != 0 && static_cast<size_t>(p.TransferOut(TransferOutFWrite, std::ref(this->curFile))) != toRead) {
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
|
||||
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
|
||||
this->CloseConnection();
|
||||
fclose(this->curFile);
|
||||
this->curFile = nullptr;
|
||||
this->curFile.reset();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -524,7 +522,7 @@ bool ClientNetworkContentSocketHandler::BeforeDownload()
|
|||
if (this->curInfo->filesize != 0) {
|
||||
/* The filesize is > 0, so we are going to download it */
|
||||
std::string filename = GetFullFilename(this->curInfo, true);
|
||||
if (filename.empty() || (this->curFile = fopen(filename.c_str(), "wb")) == nullptr) {
|
||||
if (filename.empty() || !(this->curFile = FileHandle::Open(filename, "wb")).has_value()) {
|
||||
/* Unless that fails of course... */
|
||||
CloseWindowById(WC_NETWORK_STATUS_WINDOW, WN_NETWORK_STATUS_WINDOW_CONTENT_DOWNLOAD);
|
||||
ShowErrorMessage(STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD, STR_CONTENT_ERROR_COULD_NOT_DOWNLOAD_FILE_NOT_WRITABLE, WL_ERROR);
|
||||
|
@ -542,8 +540,7 @@ void ClientNetworkContentSocketHandler::AfterDownload()
|
|||
{
|
||||
/* We read nothing; that's our marker for end-of-stream.
|
||||
* Now gunzip the tar and make it known. */
|
||||
fclose(this->curFile);
|
||||
this->curFile = nullptr;
|
||||
this->curFile.reset();
|
||||
|
||||
if (GunzipFile(this->curInfo)) {
|
||||
FioRemove(GetFullFilename(this->curInfo, true));
|
||||
|
@ -583,11 +580,10 @@ void ClientNetworkContentSocketHandler::OnFailure()
|
|||
this->http_response.shrink_to_fit();
|
||||
this->http_response_index = -2;
|
||||
|
||||
if (this->curFile != nullptr) {
|
||||
if (this->curFile.has_value()) {
|
||||
this->OnDownloadProgress(this->curInfo, -1);
|
||||
|
||||
fclose(this->curFile);
|
||||
this->curFile = nullptr;
|
||||
this->curFile.reset();
|
||||
}
|
||||
|
||||
/* If we fail, download the rest via the 'old' system. */
|
||||
|
@ -623,7 +619,7 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr<char[]> da
|
|||
|
||||
if (data != nullptr) {
|
||||
/* We have data, so write it to the file. */
|
||||
if (fwrite(data.get(), 1, length, this->curFile) != length) {
|
||||
if (fwrite(data.get(), 1, length, *this->curFile) != length) {
|
||||
/* Writing failed somehow, let try via the old method. */
|
||||
this->OnFailure();
|
||||
} else {
|
||||
|
@ -635,7 +631,7 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr<char[]> da
|
|||
return;
|
||||
}
|
||||
|
||||
if (this->curFile != nullptr) {
|
||||
if (this->curFile.has_value()) {
|
||||
/* We've finished downloading a file. */
|
||||
this->AfterDownload();
|
||||
}
|
||||
|
@ -732,7 +728,7 @@ void ClientNetworkContentSocketHandler::OnReceiveData(std::unique_ptr<char[]> da
|
|||
ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
|
||||
NetworkContentSocketHandler(),
|
||||
http_response_index(-2),
|
||||
curFile(nullptr),
|
||||
curFile(std::nullopt),
|
||||
curInfo(nullptr),
|
||||
isConnecting(false),
|
||||
isCancelled(false)
|
||||
|
@ -744,7 +740,6 @@ ClientNetworkContentSocketHandler::ClientNetworkContentSocketHandler() :
|
|||
ClientNetworkContentSocketHandler::~ClientNetworkContentSocketHandler()
|
||||
{
|
||||
delete this->curInfo;
|
||||
if (this->curFile != nullptr) fclose(this->curFile);
|
||||
|
||||
for (ContentInfo *ci : this->infos) delete ci;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ protected:
|
|||
std::vector<char> http_response; ///< The HTTP response to the requests we've been doing
|
||||
int http_response_index; ///< Where we are, in the response, with handling it
|
||||
|
||||
FILE *curFile; ///< Currently downloaded file
|
||||
std::optional<FileHandle> curFile; ///< Currently downloaded file
|
||||
ContentInfo *curInfo; ///< Information about the currently downloaded file
|
||||
bool isConnecting; ///< Whether we're connecting
|
||||
bool isCancelled; ///< Whether the download has been cancelled
|
||||
|
|
|
@ -252,7 +252,7 @@ void UpdateNewGRFConfigPalette(int32_t)
|
|||
* @param f GRF.
|
||||
* @return Size of the data section or SIZE_MAX if the file has no separate data section.
|
||||
*/
|
||||
size_t GRFGetSizeOfDataSection(FILE *f)
|
||||
size_t GRFGetSizeOfDataSection(FileHandle &f)
|
||||
{
|
||||
extern const uint8_t _grf_cont_v2_sig[];
|
||||
static const uint header_len = 14;
|
||||
|
@ -284,32 +284,28 @@ size_t GRFGetSizeOfDataSection(FILE *f)
|
|||
*/
|
||||
static bool CalcGRFMD5Sum(GRFConfig *config, Subdirectory subdir)
|
||||
{
|
||||
FILE *f;
|
||||
Md5 checksum;
|
||||
uint8_t buffer[1024];
|
||||
size_t len, size;
|
||||
|
||||
/* open the file */
|
||||
f = FioFOpenFile(config->filename, "rb", subdir, &size);
|
||||
if (f == nullptr) return false;
|
||||
auto f = FioFOpenFile(config->filename, "rb", subdir, &size);
|
||||
if (!f.has_value()) return false;
|
||||
|
||||
long start = ftell(f);
|
||||
size = std::min(size, GRFGetSizeOfDataSection(f));
|
||||
long start = ftell(*f);
|
||||
size = std::min(size, GRFGetSizeOfDataSection(*f));
|
||||
|
||||
if (start < 0 || fseek(f, start, SEEK_SET) < 0) {
|
||||
FioFCloseFile(f);
|
||||
if (start < 0 || fseek(*f, start, SEEK_SET) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* calculate md5sum */
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, *f)) != 0 && size != 0) {
|
||||
size -= len;
|
||||
checksum.Append(buffer, len);
|
||||
}
|
||||
checksum.Finish(config->ident.md5sum);
|
||||
|
||||
FioFCloseFile(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ struct NewGRFScanCallback {
|
|||
virtual void OnNewGRFsScanned() = 0;
|
||||
};
|
||||
|
||||
size_t GRFGetSizeOfDataSection(FILE *f);
|
||||
size_t GRFGetSizeOfDataSection(FileHandle &f);
|
||||
|
||||
void ScanNewGRFFiles(NewGRFScanCallback *callback);
|
||||
const GRFConfig *FindGRFConfig(uint32_t grfid, FindGRFConfigMode mode, const MD5Hash *md5sum = nullptr, uint32_t desired_version = 0);
|
||||
|
|
|
@ -104,15 +104,18 @@ uint32_t NewGRFProfiler::Finish()
|
|||
std::string filename = this->GetOutputFilename();
|
||||
IConsolePrint(CC_DEBUG, "Finished profile of NewGRF [{:08X}], writing {} events to '{}'.", BSWAP32(this->grffile->grfid), this->calls.size(), filename);
|
||||
|
||||
FILE *f = FioFOpenFile(filename, "wt", Subdirectory::NO_DIRECTORY);
|
||||
FileCloser fcloser(f);
|
||||
|
||||
uint32_t total_microseconds = 0;
|
||||
|
||||
fmt::print(f, "Tick,Sprite,Feature,Item,CallbackID,Microseconds,Depth,Result\n");
|
||||
for (const Call &c : this->calls) {
|
||||
fmt::print(f, "{},{},{:#X},{},{:#X},{},{},{}\n", c.tick, c.root_sprite, c.feat, c.item, (uint)c.cb, c.time, c.subs, c.result);
|
||||
total_microseconds += c.time;
|
||||
auto f = FioFOpenFile(filename, "wt", Subdirectory::NO_DIRECTORY);
|
||||
|
||||
if (!f.has_value()) {
|
||||
IConsolePrint(CC_ERROR, "Failed to open '{}' for writing.", filename);
|
||||
} else {
|
||||
fmt::print(*f, "Tick,Sprite,Feature,Item,CallbackID,Microseconds,Depth,Result\n");
|
||||
for (const Call &c : this->calls) {
|
||||
fmt::print(*f, "{},{},{:#X},{},{:#X},{},{},{}\n", c.tick, c.root_sprite, c.feat, c.item, (uint)c.cb, c.time, c.subs, c.result);
|
||||
total_microseconds += c.time;
|
||||
}
|
||||
}
|
||||
|
||||
this->Abort();
|
||||
|
|
|
@ -24,14 +24,12 @@ template <typename Tpf> void DumpState(Tpf &pf1, Tpf &pf2)
|
|||
DumpTarget dmp1, dmp2;
|
||||
pf1.DumpBase(dmp1);
|
||||
pf2.DumpBase(dmp2);
|
||||
FILE *f1 = fopen("yapf1.txt", "wt");
|
||||
FILE *f2 = fopen("yapf2.txt", "wt");
|
||||
assert(f1 != nullptr);
|
||||
assert(f2 != nullptr);
|
||||
fwrite(dmp1.m_out.c_str(), 1, dmp1.m_out.size(), f1);
|
||||
fwrite(dmp2.m_out.c_str(), 1, dmp2.m_out.size(), f2);
|
||||
fclose(f1);
|
||||
fclose(f2);
|
||||
auto f1 = FileHandle::Open("yapf1.txt", "wt");
|
||||
auto f2 = FileHandle::Open("yapf2.txt", "wt");
|
||||
assert(f1.has_value());
|
||||
assert(f2.has_value());
|
||||
fwrite(dmp1.m_out.c_str(), 1, dmp1.m_out.size(), *f1);
|
||||
fwrite(dmp2.m_out.c_str(), 1, dmp2.m_out.size(), *f2);
|
||||
}
|
||||
|
||||
template <class Types>
|
||||
|
|
|
@ -26,10 +26,10 @@ RandomAccessFile::RandomAccessFile(const std::string &filename, Subdirectory sub
|
|||
{
|
||||
size_t file_size;
|
||||
this->file_handle = FioFOpenFile(filename, "rb", subdir, &file_size);
|
||||
if (this->file_handle == nullptr) UserError("Cannot open file '{}'", filename);
|
||||
if (!this->file_handle.has_value()) UserError("Cannot open file '{}'", filename);
|
||||
|
||||
/* When files are in a tar-file, the begin of the file might not be at 0. */
|
||||
long pos = ftell(this->file_handle);
|
||||
long pos = ftell(*this->file_handle);
|
||||
if (pos < 0) UserError("Cannot read file '{}'", filename);
|
||||
|
||||
/* Make a note of start and end position for readers who check bounds. */
|
||||
|
@ -45,14 +45,6 @@ RandomAccessFile::RandomAccessFile(const std::string &filename, Subdirectory sub
|
|||
this->SeekTo(static_cast<size_t>(pos), SEEK_SET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the file's file handle.
|
||||
*/
|
||||
RandomAccessFile::~RandomAccessFile()
|
||||
{
|
||||
fclose(this->file_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filename of the opened file with the path from the SubDirectory and the extension.
|
||||
* @return Name of the file.
|
||||
|
@ -100,7 +92,7 @@ void RandomAccessFile::SeekTo(size_t pos, int mode)
|
|||
if (mode == SEEK_CUR) pos += this->GetPos();
|
||||
|
||||
this->pos = pos;
|
||||
if (fseek(this->file_handle, this->pos, SEEK_SET) < 0) {
|
||||
if (fseek(*this->file_handle, this->pos, SEEK_SET) < 0) {
|
||||
Debug(misc, 0, "Seeking in {} failed", this->filename);
|
||||
}
|
||||
|
||||
|
@ -116,7 +108,7 @@ uint8_t RandomAccessFile::ReadByte()
|
|||
{
|
||||
if (this->buffer == this->buffer_end) {
|
||||
this->buffer = this->buffer_start;
|
||||
size_t size = fread(this->buffer, 1, RandomAccessFile::BUFFER_SIZE, this->file_handle);
|
||||
size_t size = fread(this->buffer, 1, RandomAccessFile::BUFFER_SIZE, *this->file_handle);
|
||||
this->pos += size;
|
||||
this->buffer_end = this->buffer_start + size;
|
||||
|
||||
|
@ -153,7 +145,7 @@ uint32_t RandomAccessFile::ReadDword()
|
|||
void RandomAccessFile::ReadBlock(void *ptr, size_t size)
|
||||
{
|
||||
this->SeekTo(this->GetPos(), SEEK_SET);
|
||||
this->pos += fread(ptr, 1, size, this->file_handle);
|
||||
this->pos += fread(ptr, 1, size, *this->file_handle);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -26,7 +26,7 @@ class RandomAccessFile {
|
|||
std::string filename; ///< Full name of the file; relative path to subdir plus the extension of the file.
|
||||
std::string simplified_filename; ///< Simplified lowecase name of the file; only the name, no path or extension.
|
||||
|
||||
FILE *file_handle; ///< File handle of the open file.
|
||||
std::optional<FileHandle> file_handle; ///< File handle of the open file.
|
||||
size_t pos; ///< Position in the file of the end of the read buffer.
|
||||
size_t start_pos; ///< Start position of file. May be non-zero if file is within a tar file.
|
||||
size_t end_pos; ///< End position of file.
|
||||
|
@ -40,7 +40,7 @@ public:
|
|||
RandomAccessFile(const RandomAccessFile&) = delete;
|
||||
void operator=(const RandomAccessFile&) = delete;
|
||||
|
||||
virtual ~RandomAccessFile();
|
||||
virtual ~RandomAccessFile() {}
|
||||
|
||||
const std::string &GetFilename() const;
|
||||
const std::string &GetSimplifiedFilename() const;
|
||||
|
|
|
@ -65,7 +65,7 @@ static uint8_t ReadByteFromFile(LoadgameState *ls)
|
|||
if (ls->buffer_cur >= ls->buffer_count) {
|
||||
|
||||
/* Read some new bytes from the file */
|
||||
int count = (int)fread(ls->buffer, 1, BUFFER_SIZE, ls->file);
|
||||
int count = static_cast<int>(fread(ls->buffer, 1, BUFFER_SIZE, *ls->file));
|
||||
|
||||
/* We tried to read, but there is nothing in the file anymore.. */
|
||||
if (count == 0) {
|
||||
|
@ -235,7 +235,7 @@ static bool VerifyOldNameChecksum(char *title, uint len)
|
|||
return sum == sum2;
|
||||
}
|
||||
|
||||
static std::tuple<SavegameType, std::string> DetermineOldSavegameTypeAndName(FILE *f)
|
||||
static std::tuple<SavegameType, std::string> DetermineOldSavegameTypeAndName(FileHandle &f)
|
||||
{
|
||||
long pos = ftell(f);
|
||||
char buffer[std::max(TTO_HEADER_SIZE, TTD_HEADER_SIZE)];
|
||||
|
@ -267,13 +267,13 @@ bool LoadOldSaveGame(const std::string &file)
|
|||
/* Open file */
|
||||
ls.file = FioFOpenFile(file, "rb", NO_DIRECTORY);
|
||||
|
||||
if (ls.file == nullptr) {
|
||||
if (!ls.file.has_value()) {
|
||||
Debug(oldloader, 0, "Cannot open file '{}'", file);
|
||||
return false;
|
||||
}
|
||||
|
||||
SavegameType type;
|
||||
std::tie(type, std::ignore) = DetermineOldSavegameTypeAndName(ls.file);
|
||||
std::tie(type, std::ignore) = DetermineOldSavegameTypeAndName(*ls.file);
|
||||
|
||||
LoadOldMainProc *proc = nullptr;
|
||||
|
||||
|
@ -296,7 +296,7 @@ bool LoadOldSaveGame(const std::string &file)
|
|||
|
||||
if (!game_loaded) {
|
||||
SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED);
|
||||
fclose(ls.file);
|
||||
ls.file.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -307,11 +307,10 @@ bool LoadOldSaveGame(const std::string &file)
|
|||
|
||||
std::string GetOldSaveGameName(const std::string &file)
|
||||
{
|
||||
FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY);
|
||||
if (f == nullptr) return {};
|
||||
auto f = FioFOpenFile(file, "rb", NO_DIRECTORY);
|
||||
if (!f.has_value()) return {};
|
||||
|
||||
std::string name;
|
||||
std::tie(std::ignore, name) = DetermineOldSavegameTypeAndName(f);
|
||||
fclose(f);
|
||||
std::tie(std::ignore, name) = DetermineOldSavegameTypeAndName(*f);
|
||||
return name;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ static const uint BUFFER_SIZE = 4096;
|
|||
static const uint OLD_MAP_SIZE = 256;
|
||||
|
||||
struct LoadgameState {
|
||||
FILE *file;
|
||||
std::optional<FileHandle> file;
|
||||
|
||||
uint chunk_size;
|
||||
|
||||
|
|
|
@ -2204,39 +2204,37 @@ static void SlFixPointers()
|
|||
|
||||
/** Yes, simply reading from a file. */
|
||||
struct FileReader : LoadFilter {
|
||||
FILE *file; ///< The file to read from.
|
||||
std::optional<FileHandle> file; ///< The file to read from.
|
||||
long begin; ///< The begin of the file.
|
||||
|
||||
/**
|
||||
* Create the file reader, so it reads from a specific file.
|
||||
* @param file The file to read from.
|
||||
*/
|
||||
FileReader(FILE *file) : LoadFilter(nullptr), file(file), begin(ftell(file))
|
||||
FileReader(FileHandle &&file) : LoadFilter(nullptr), file(std::move(file)), begin(ftell(*this->file))
|
||||
{
|
||||
}
|
||||
|
||||
/** Make sure everything is cleaned up. */
|
||||
~FileReader()
|
||||
{
|
||||
if (this->file != nullptr) {
|
||||
_game_session_stats.savegame_size = ftell(this->file) - this->begin;
|
||||
fclose(this->file);
|
||||
if (this->file.has_value()) {
|
||||
_game_session_stats.savegame_size = ftell(*this->file) - this->begin;
|
||||
}
|
||||
this->file = nullptr;
|
||||
}
|
||||
|
||||
size_t Read(uint8_t *buf, size_t size) override
|
||||
{
|
||||
/* We're in the process of shutting down, i.e. in "failure" mode. */
|
||||
if (this->file == nullptr) return 0;
|
||||
if (!this->file.has_value()) return 0;
|
||||
|
||||
return fread(buf, 1, size, this->file);
|
||||
return fread(buf, 1, size, *this->file);
|
||||
}
|
||||
|
||||
void Reset() override
|
||||
{
|
||||
clearerr(this->file);
|
||||
if (fseek(this->file, this->begin, SEEK_SET)) {
|
||||
clearerr(*this->file);
|
||||
if (fseek(*this->file, this->begin, SEEK_SET)) {
|
||||
Debug(sl, 1, "Could not reset the file reading");
|
||||
}
|
||||
}
|
||||
|
@ -2244,13 +2242,13 @@ struct FileReader : LoadFilter {
|
|||
|
||||
/** Yes, simply writing to a file. */
|
||||
struct FileWriter : SaveFilter {
|
||||
FILE *file; ///< The file to write to.
|
||||
std::optional<FileHandle> file; ///< The file to write to.
|
||||
|
||||
/**
|
||||
* Create the file writer, so it writes to a specific file.
|
||||
* @param file The file to write to.
|
||||
*/
|
||||
FileWriter(FILE *file) : SaveFilter(nullptr), file(file)
|
||||
FileWriter(FileHandle &&file) : SaveFilter(nullptr), file(std::move(file))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -2263,18 +2261,17 @@ struct FileWriter : SaveFilter {
|
|||
void Write(uint8_t *buf, size_t size) override
|
||||
{
|
||||
/* We're in the process of shutting down, i.e. in "failure" mode. */
|
||||
if (this->file == nullptr) return;
|
||||
if (this->file.has_value()) return;
|
||||
|
||||
if (fwrite(buf, 1, size, this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
|
||||
if (fwrite(buf, 1, size, *this->file) != size) SlError(STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE);
|
||||
}
|
||||
|
||||
void Finish() override
|
||||
{
|
||||
if (this->file != nullptr) {
|
||||
_game_session_stats.savegame_size = ftell(this->file);
|
||||
fclose(this->file);
|
||||
if (this->file.has_value()) {
|
||||
_game_session_stats.savegame_size = ftell(*this->file);
|
||||
this->file.reset();
|
||||
}
|
||||
this->file = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3144,14 +3141,14 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop,
|
|||
default: NOT_REACHED();
|
||||
}
|
||||
|
||||
FILE *fh = (fop == SLO_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
|
||||
auto fh = (fop == SLO_SAVE) ? FioFOpenFile(filename, "wb", sb) : FioFOpenFile(filename, "rb", sb);
|
||||
|
||||
/* Make it a little easier to load savegames from the console */
|
||||
if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
|
||||
if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
|
||||
if (fh == nullptr && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
|
||||
if (!fh.has_value() && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SAVE_DIR);
|
||||
if (!fh.has_value() && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", BASE_DIR);
|
||||
if (!fh.has_value() && fop != SLO_SAVE) fh = FioFOpenFile(filename, "rb", SCENARIO_DIR);
|
||||
|
||||
if (fh == nullptr) {
|
||||
if (!fh.has_value()) {
|
||||
SlError(fop == SLO_SAVE ? STR_GAME_SAVELOAD_ERROR_FILE_NOT_WRITEABLE : STR_GAME_SAVELOAD_ERROR_FILE_NOT_READABLE);
|
||||
}
|
||||
|
||||
|
@ -3159,13 +3156,13 @@ SaveOrLoadResult SaveOrLoad(const std::string &filename, SaveLoadOperation fop,
|
|||
Debug(desync, 1, "save: {:08x}; {:02x}; {}", TimerGameEconomy::date, TimerGameEconomy::date_fract, filename);
|
||||
if (!_settings_client.gui.threaded_saves) threaded = false;
|
||||
|
||||
return DoSave(std::make_shared<FileWriter>(fh), threaded);
|
||||
return DoSave(std::make_shared<FileWriter>(std::move(*fh)), threaded);
|
||||
}
|
||||
|
||||
/* LOAD game */
|
||||
assert(fop == SLO_LOAD || fop == SLO_CHECK);
|
||||
Debug(desync, 1, "load: {}", filename);
|
||||
return DoLoad(std::make_shared<FileReader>(fh), fop == SLO_CHECK);
|
||||
return DoLoad(std::make_shared<FileReader>(std::move(*fh)), fop == SLO_CHECK);
|
||||
} catch (...) {
|
||||
/* This code may be executed both for old and new save games. */
|
||||
ClearSaveLoadState();
|
||||
|
|
|
@ -124,8 +124,9 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
default: return false;
|
||||
}
|
||||
|
||||
FILE *f = fopen(name, "wb");
|
||||
if (f == nullptr) return false;
|
||||
auto of = FileHandle::Open(name, "wb");
|
||||
if (!of.has_value()) return false;
|
||||
auto &f = *of;
|
||||
|
||||
/* Each scanline must be aligned on a 32bit boundary */
|
||||
uint bytewidth = Align(w * bpp, 4); // bytes per line in file
|
||||
|
@ -156,7 +157,6 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
|
||||
/* Write file header and info header */
|
||||
if (fwrite(&bfh, sizeof(bfh), 1, f) != 1 || fwrite(&bih, sizeof(bih), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -171,7 +171,6 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
}
|
||||
/* Write the palette */
|
||||
if (fwrite(rq, sizeof(rq), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -208,13 +207,11 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
}
|
||||
/* Write to file */
|
||||
if (fwrite(line.data(), bytewidth, 1, f) != 1) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while (h != 0);
|
||||
|
||||
fclose(f);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -259,7 +256,6 @@ static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
|
|||
static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
|
||||
{
|
||||
png_color rq[256];
|
||||
FILE *f;
|
||||
uint i, y, n;
|
||||
uint maxlines;
|
||||
uint bpp = pixelformat / 8;
|
||||
|
@ -269,26 +265,24 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
/* only implemented for 8bit and 32bit images so far. */
|
||||
if (pixelformat != 8 && pixelformat != 32) return false;
|
||||
|
||||
f = fopen(name, "wb");
|
||||
if (f == nullptr) return false;
|
||||
auto of = FileHandle::Open(name, "wb");
|
||||
if (!of.has_value()) return false;
|
||||
auto &f = *of;
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast<char *>(name), png_my_error, png_my_warning);
|
||||
|
||||
if (png_ptr == nullptr) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == nullptr) {
|
||||
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -388,7 +382,6 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
png_write_end(png_ptr, info_ptr);
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
#endif /* WITH_PNG */
|
||||
|
@ -432,7 +425,6 @@ static_assert(sizeof(PcxHeader) == 128);
|
|||
*/
|
||||
static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
|
||||
{
|
||||
FILE *f;
|
||||
uint maxlines;
|
||||
uint y;
|
||||
PcxHeader pcx;
|
||||
|
@ -444,8 +436,9 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
}
|
||||
if (pixelformat != 8 || w == 0) return false;
|
||||
|
||||
f = fopen(name, "wb");
|
||||
if (f == nullptr) return false;
|
||||
auto of = FileHandle::Open(name, "wb");
|
||||
if (!of.has_value()) return false;
|
||||
auto &f = *of;
|
||||
|
||||
memset(&pcx, 0, sizeof(pcx));
|
||||
|
||||
|
@ -466,7 +459,6 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
|
||||
/* write pcx header */
|
||||
if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -500,12 +492,10 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
if (ch != runchar || runcount >= 0x3f) {
|
||||
if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
|
||||
if (fputc(0xC0 | runcount, f) == EOF) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fputc(runchar, f) == EOF) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
runcount = 0;
|
||||
|
@ -517,12 +507,10 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
/* write remaining bytes.. */
|
||||
if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
|
||||
if (fputc(0xC0 | runcount, f) == EOF) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (fputc(runchar, f) == EOF) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -530,7 +518,6 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
|
||||
/* write 8-bit colour palette */
|
||||
if (fputc(12, f) == EOF) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -544,8 +531,6 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
|
|||
}
|
||||
success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
|
||||
|
||||
fclose(f);
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
|
@ -168,11 +168,11 @@ struct ScriptFileChecksumCreator : FileScanner {
|
|||
size_t len, size;
|
||||
|
||||
/* Open the file ... */
|
||||
FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
|
||||
if (f == nullptr) return false;
|
||||
auto f = FioFOpenFile(filename, "rb", this->dir, &size);
|
||||
if (!f.has_value()) return false;
|
||||
|
||||
/* ... calculate md5sum... */
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
|
||||
while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, *f)) != 0 && size != 0) {
|
||||
size -= len;
|
||||
checksum.Append(buffer, len);
|
||||
}
|
||||
|
@ -180,8 +180,6 @@ struct ScriptFileChecksumCreator : FileScanner {
|
|||
MD5Hash tmp_md5sum;
|
||||
checksum.Finish(tmp_md5sum);
|
||||
|
||||
FioFCloseFile(f);
|
||||
|
||||
/* ... and xor it to the overall md5sum. */
|
||||
this->md5sum ^= tmp_md5sum;
|
||||
|
||||
|
|
|
@ -548,12 +548,12 @@ void Squirrel::Initialize()
|
|||
|
||||
class SQFile {
|
||||
private:
|
||||
FILE *file;
|
||||
FileHandle file;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
|
||||
public:
|
||||
SQFile(FILE *file, size_t size) : file(file), size(size), pos(0) {}
|
||||
SQFile(FileHandle file, size_t size) : file(std::move(file)), size(size), pos(0) {}
|
||||
|
||||
size_t Read(void *buf, size_t elemsize, size_t count)
|
||||
{
|
||||
|
@ -622,40 +622,37 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool
|
|||
{
|
||||
ScriptAllocatorScope alloc_scope(this);
|
||||
|
||||
FILE *file;
|
||||
std::optional<FileHandle> file = std::nullopt;
|
||||
size_t size;
|
||||
if (strncmp(this->GetAPIName(), "AI", 2) == 0) {
|
||||
file = FioFOpenFile(filename, "rb", AI_DIR, &size);
|
||||
if (file == nullptr) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
|
||||
if (!file.has_value()) file = FioFOpenFile(filename, "rb", AI_LIBRARY_DIR, &size);
|
||||
} else if (strncmp(this->GetAPIName(), "GS", 2) == 0) {
|
||||
file = FioFOpenFile(filename, "rb", GAME_DIR, &size);
|
||||
if (file == nullptr) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size);
|
||||
if (!file.has_value()) file = FioFOpenFile(filename, "rb", GAME_LIBRARY_DIR, &size);
|
||||
} else {
|
||||
NOT_REACHED();
|
||||
}
|
||||
|
||||
if (file == nullptr) {
|
||||
if (!file.has_value()) {
|
||||
return sq_throwerror(vm, "cannot open the file");
|
||||
}
|
||||
unsigned short bom = 0;
|
||||
if (size >= 2) {
|
||||
[[maybe_unused]] size_t sr = fread(&bom, 1, sizeof(bom), file);
|
||||
if (fread(&bom, 1, sizeof(bom), *file) != sizeof(bom)) return sq_throwerror(vm, "cannot read the file");;
|
||||
}
|
||||
|
||||
SQLEXREADFUNC func;
|
||||
switch (bom) {
|
||||
case SQ_BYTECODE_STREAM_TAG: { // BYTECODE
|
||||
if (fseek(file, -2, SEEK_CUR) < 0) {
|
||||
FioFCloseFile(file);
|
||||
if (fseek(*file, -2, SEEK_CUR) < 0) {
|
||||
return sq_throwerror(vm, "cannot seek the file");
|
||||
}
|
||||
|
||||
SQFile f(file, size);
|
||||
SQFile f(std::move(*file), size);
|
||||
if (SQ_SUCCEEDED(sq_readclosure(vm, _io_file_read, &f))) {
|
||||
FioFCloseFile(file);
|
||||
return SQ_OK;
|
||||
}
|
||||
FioFCloseFile(file);
|
||||
return sq_throwerror(vm, "Couldn't read bytecode");
|
||||
}
|
||||
case 0xFFFE:
|
||||
|
@ -673,12 +670,10 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool
|
|||
case 0xEFBB: { // UTF-8 on big-endian machine
|
||||
/* Similarly, check the file is actually big enough to finish checking BOM */
|
||||
if (size < 3) {
|
||||
FioFCloseFile(file);
|
||||
return sq_throwerror(vm, "I/O error");
|
||||
}
|
||||
unsigned char uc;
|
||||
if (fread(&uc, 1, sizeof(uc), file) != sizeof(uc) || uc != 0xBF) {
|
||||
FioFCloseFile(file);
|
||||
if (fread(&uc, 1, sizeof(uc), *file) != sizeof(uc) || uc != 0xBF) {
|
||||
return sq_throwerror(vm, "Unrecognized encoding");
|
||||
}
|
||||
func = _io_file_lexfeed_UTF8;
|
||||
|
@ -688,19 +683,16 @@ SQRESULT Squirrel::LoadFile(HSQUIRRELVM vm, const std::string &filename, SQBool
|
|||
default: // ASCII
|
||||
func = _io_file_lexfeed_ASCII;
|
||||
/* Account for when we might not have fread'd earlier */
|
||||
if (size >= 2 && fseek(file, -2, SEEK_CUR) < 0) {
|
||||
FioFCloseFile(file);
|
||||
if (size >= 2 && fseek(*file, -2, SEEK_CUR) < 0) {
|
||||
return sq_throwerror(vm, "cannot seek the file");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
SQFile f(file, size);
|
||||
SQFile f(std::move(*file), size);
|
||||
if (SQ_SUCCEEDED(sq_compile(vm, func, &f, filename.c_str(), printerror))) {
|
||||
FioFCloseFile(file);
|
||||
return SQ_OK;
|
||||
}
|
||||
FioFCloseFile(file);
|
||||
return SQ_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -156,17 +156,17 @@ struct SettingsIniFile : IniLoadFile {
|
|||
{
|
||||
}
|
||||
|
||||
FILE *OpenFile(const std::string &filename, Subdirectory, size_t *size) override
|
||||
std::optional<FileHandle> OpenFile(const std::string &filename, Subdirectory, size_t *size) override
|
||||
{
|
||||
/* Open the text file in binary mode to prevent end-of-line translations
|
||||
* done by ftell() and friends, as defined by K&R. */
|
||||
FILE *in = fopen(filename.c_str(), "rb");
|
||||
if (in == nullptr) return nullptr;
|
||||
auto in = FileHandle::Open(filename, "rb");
|
||||
if (!in.has_value()) return in;
|
||||
|
||||
fseek(in, 0L, SEEK_END);
|
||||
*size = ftell(in);
|
||||
fseek(*in, 0L, SEEK_END);
|
||||
*size = ftell(*in);
|
||||
fseek(*in, 0L, SEEK_SET); // Seek back to the start of the file.
|
||||
|
||||
fseek(in, 0L, SEEK_SET); // Seek back to the start of the file.
|
||||
return in;
|
||||
}
|
||||
|
||||
|
@ -327,21 +327,19 @@ static void AppendFile(const char *fname, FILE *out_fp)
|
|||
{
|
||||
if (fname == nullptr) return;
|
||||
|
||||
FILE *in_fp = fopen(fname, "r");
|
||||
if (in_fp == nullptr) {
|
||||
auto in_fp = FileHandle::Open(fname, "r");
|
||||
if (!in_fp.has_value()) {
|
||||
FatalError("Cannot open file {} for copying", fname);
|
||||
}
|
||||
|
||||
char buffer[4096];
|
||||
size_t length;
|
||||
do {
|
||||
length = fread(buffer, 1, lengthof(buffer), in_fp);
|
||||
length = fread(buffer, 1, lengthof(buffer), *in_fp);
|
||||
if (fwrite(buffer, 1, length, out_fp) != length) {
|
||||
FatalError("Cannot copy file");
|
||||
}
|
||||
} while (length == lengthof(buffer));
|
||||
|
||||
fclose(in_fp);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -352,12 +350,11 @@ static void AppendFile(const char *fname, FILE *out_fp)
|
|||
*/
|
||||
static bool CompareFiles(const char *n1, const char *n2)
|
||||
{
|
||||
FILE *f2 = fopen(n2, "rb");
|
||||
if (f2 == nullptr) return false;
|
||||
auto f2 = FileHandle::Open(n2, "rb");
|
||||
if (!f2.has_value()) return false;
|
||||
|
||||
FILE *f1 = fopen(n1, "rb");
|
||||
if (f1 == nullptr) {
|
||||
fclose(f2);
|
||||
auto f1 = FileHandle::Open(n1, "rb");
|
||||
if (!f1.has_value()) {
|
||||
FatalError("can't open {}", n1);
|
||||
}
|
||||
|
||||
|
@ -365,18 +362,14 @@ static bool CompareFiles(const char *n1, const char *n2)
|
|||
do {
|
||||
char b1[4096];
|
||||
char b2[4096];
|
||||
l1 = fread(b1, 1, sizeof(b1), f1);
|
||||
l2 = fread(b2, 1, sizeof(b2), f2);
|
||||
l1 = fread(b1, 1, sizeof(b1), *f1);
|
||||
l2 = fread(b2, 1, sizeof(b2), *f2);
|
||||
|
||||
if (l1 != l2 || memcmp(b1, b2, l1) != 0) {
|
||||
fclose(f2);
|
||||
fclose(f1);
|
||||
return false;
|
||||
}
|
||||
} while (l1 != 0);
|
||||
|
||||
fclose(f2);
|
||||
fclose(f1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -480,15 +473,15 @@ int CDECL main(int argc, char *argv[])
|
|||
} else {
|
||||
static const char * const tmp_output = "tmp2.xxx";
|
||||
|
||||
FILE *fp = fopen(tmp_output, "w");
|
||||
if (fp == nullptr) {
|
||||
auto fp = FileHandle::Open(tmp_output, "w");
|
||||
if (!fp.has_value()) {
|
||||
FatalError("Cannot open file {}", tmp_output);
|
||||
}
|
||||
AppendFile(before_file, fp);
|
||||
_stored_output.Write(fp);
|
||||
_post_amble_output.Write(fp);
|
||||
AppendFile(after_file, fp);
|
||||
fclose(fp);
|
||||
AppendFile(before_file, *fp);
|
||||
_stored_output.Write(*fp);
|
||||
_post_amble_output.Write(*fp);
|
||||
AppendFile(after_file, *fp);
|
||||
fp.reset();
|
||||
|
||||
std::error_code error_code;
|
||||
if (CompareFiles(tmp_output, output_file)) {
|
||||
|
@ -502,3 +495,16 @@ int CDECL main(int argc, char *argv[])
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Simplified FileHandle::Open which ignores OTTD2FS. Required as settingsgen does not include all of the fileio system.
|
||||
* @param filename UTF-8 encoded filename to open.
|
||||
* @param mode Mode to open file.
|
||||
* @return FileHandle, or std::nullopt on failure.
|
||||
*/
|
||||
std::optional<FileHandle> FileHandle::Open(const std::string &filename, const std::string &mode)
|
||||
{
|
||||
auto f = fopen(filename.c_str(), mode.c_str());
|
||||
if (f == nullptr) return std::nullopt;
|
||||
return FileHandle(f);
|
||||
}
|
||||
|
|
|
@ -35,22 +35,19 @@ static const std::initializer_list<std::array<uint8_t, 32>> _public_keys_v1 = {
|
|||
*/
|
||||
static std::string CalculateHashV1(const std::string &filename)
|
||||
{
|
||||
FILE *f = FioFOpenFile(filename, "rb", NO_DIRECTORY);
|
||||
if (f == nullptr) {
|
||||
return "";
|
||||
}
|
||||
auto f = FioFOpenFile(filename, "rb", NO_DIRECTORY);
|
||||
if (!f.has_value()) return {};
|
||||
|
||||
std::array<uint8_t, 32> digest;
|
||||
crypto_blake2b_ctx ctx;
|
||||
crypto_blake2b_init(&ctx, digest.size());
|
||||
|
||||
while (!feof(f)) {
|
||||
while (!feof(*f)) {
|
||||
std::array<uint8_t, 1024> buf;
|
||||
size_t len = fread(buf.data(), 1, buf.size(), f);
|
||||
size_t len = fread(buf.data(), 1, buf.size(), *f);
|
||||
|
||||
crypto_blake2b_update(&ctx, buf.data(), len);
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
crypto_blake2b_final(&ctx, digest.data());
|
||||
return FormatArrayAsHex(digest);
|
||||
|
@ -197,15 +194,14 @@ static bool ValidateSchema(const nlohmann::json &signatures, const std::string &
|
|||
static bool _ValidateSignatureFile(const std::string &filename)
|
||||
{
|
||||
size_t filesize;
|
||||
FILE *f = FioFOpenFile(filename, "rb", NO_DIRECTORY, &filesize);
|
||||
if (f == nullptr) {
|
||||
auto f = FioFOpenFile(filename, "rb", NO_DIRECTORY, &filesize);
|
||||
if (!f.has_value()) {
|
||||
Debug(misc, 0, "Failed to validate signature: file not found: {}", filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string text(filesize, '\0');
|
||||
size_t len = fread(text.data(), filesize, 1, f);
|
||||
FioFCloseFile(f);
|
||||
size_t len = fread(text.data(), filesize, 1, *f);
|
||||
if (len != 1) {
|
||||
Debug(misc, 0, "Failed to validate signature: failed to read file: {}", filename);
|
||||
return false;
|
||||
|
|
|
@ -165,19 +165,13 @@
|
|||
#if !defined(STRGEN) && !defined(SETTINGSGEN)
|
||||
# if defined(_WIN32)
|
||||
char *getcwd(char *buf, size_t size);
|
||||
# include <io.h>
|
||||
# include <tchar.h>
|
||||
|
||||
# define fopen(file, mode) _wfopen(OTTD2FS(file).c_str(), _T(mode))
|
||||
|
||||
std::string FS2OTTD(const std::wstring &name);
|
||||
std::wstring OTTD2FS(const std::string &name);
|
||||
# elif defined(WITH_ICONV)
|
||||
# define fopen(file, mode) fopen(OTTD2FS(file).c_str(), mode)
|
||||
std::string FS2OTTD(const std::string &name);
|
||||
std::string OTTD2FS(const std::string &name);
|
||||
# else
|
||||
// no override of fopen() since no transformation is required of the filename
|
||||
template <typename T> std::string FS2OTTD(T name) { return name; }
|
||||
template <typename T> std::string OTTD2FS(T name) { return name; }
|
||||
# endif /* _WIN32 or WITH_ICONV */
|
||||
|
|
|
@ -2043,11 +2043,10 @@ const LanguageMetadata *GetLanguage(uint8_t newgrflangid)
|
|||
*/
|
||||
static bool GetLanguageFileHeader(const std::string &file, LanguagePackHeader *hdr)
|
||||
{
|
||||
FILE *f = fopen(file.c_str(), "rb");
|
||||
if (f == nullptr) return false;
|
||||
auto f = FileHandle::Open(file, "rb");
|
||||
if (!f.has_value()) return false;
|
||||
|
||||
size_t read = fread(hdr, sizeof(*hdr), 1, f);
|
||||
fclose(f);
|
||||
size_t read = fread(hdr, sizeof(*hdr), 1, *f);
|
||||
|
||||
bool ret = read == 1 && hdr->IsValid();
|
||||
|
||||
|
|
|
@ -742,15 +742,14 @@ static std::vector<char> Xunzip(std::span<char> input)
|
|||
|
||||
/* Get text from file */
|
||||
size_t filesize;
|
||||
FILE *handle = FioFOpenFile(textfile, "rb", dir, &filesize);
|
||||
if (handle == nullptr) return;
|
||||
auto handle = FioFOpenFile(textfile, "rb", dir, &filesize);
|
||||
if (!handle.has_value()) return;
|
||||
/* Early return on empty files. */
|
||||
if (filesize == 0) return;
|
||||
|
||||
std::vector<char> buf;
|
||||
buf.resize(filesize);
|
||||
size_t read = fread(buf.data(), 1, buf.size(), handle);
|
||||
fclose(handle);
|
||||
size_t read = fread(buf.data(), 1, buf.size(), *handle);
|
||||
|
||||
if (read != buf.size()) return;
|
||||
|
||||
|
|
Loading…
Reference in New Issue