Changeset - r24529:3dec691db49a
[Not reviewed]
master
0 16 0
Michael Lutz - 3 years ago 2020-12-06 20:11:50
michi@icosahedron.de
Codechange: Use std::string in file scanners.
16 files changed with 91 insertions and 132 deletions:
0 comments (0 inline, 0 general)
src/ai/ai_scanner.cpp
Show inline comments
 
@@ -23,26 +23,25 @@ AIScannerInfo::AIScannerInfo() :
 
	ScriptScanner(),
 
	info_dummy(nullptr)
 
{
 
}
 

	
 
void AIScannerInfo::Initialize()
 
{
 
	ScriptScanner::Initialize("AIScanner");
 

	
 
	ScriptAllocatorScope alloc_scope(this->engine);
 

	
 
	/* Create the dummy AI */
 
	free(this->main_script);
 
	this->main_script = stredup("%_dummy");
 
	this->main_script = "%_dummy";
 
	extern void Script_CreateDummyInfo(HSQUIRRELVM vm, const char *type, const char *dir);
 
	Script_CreateDummyInfo(this->engine->GetVM(), "AI", "ai");
 
}
 

	
 
void AIScannerInfo::SetDummyAI(class AIInfo *info)
 
{
 
	this->info_dummy = info;
 
}
 

	
 
AIScannerInfo::~AIScannerInfo()
 
{
 
	delete this->info_dummy;
src/base_media_base.h
Show inline comments
 
@@ -158,25 +158,25 @@ struct BaseSet {
 

	
 
/**
 
 * Base for all base media (graphics, sounds)
 
 * @tparam Tbase_set the real set we're going to be
 
 */
 
template <class Tbase_set>
 
class BaseMedia : FileScanner {
 
protected:
 
	static Tbase_set *available_sets; ///< All available sets
 
	static Tbase_set *duplicate_sets; ///< All sets that aren't available, but needed for not downloading base sets when a newer version than the one on BaNaNaS is loaded.
 
	static const Tbase_set *used_set; ///< The currently used set
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override;
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
 

	
 
	/**
 
	 * Get the extension that is used to identify this set.
 
	 * @return the extension
 
	 */
 
	static const char *GetExtension();
 
public:
 
	/** The set as saved in the config file. */
 
	static std::string ini_set;
 

	
 
	/**
 
	 * Determine the graphics pack that has to be used.
src/base_media_func.h
Show inline comments
 
@@ -141,42 +141,42 @@ bool BaseSet<T, Tnum_files, Tsearch_in_t
 
				break;
 

	
 
			case MD5File::CR_NO_FILE:
 
				DEBUG(grf, 1, "The file %s specified in %s is missing", filename, full_filename);
 
				break;
 
		}
 
	}
 

	
 
	return true;
 
}
 

	
 
template <class Tbase_set>
 
bool BaseMedia<Tbase_set>::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
bool BaseMedia<Tbase_set>::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
{
 
	bool ret = false;
 
	DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename);
 
	DEBUG(grf, 1, "Checking %s for base " SET_TYPE " set", filename.c_str());
 

	
 
	Tbase_set *set = new Tbase_set();
 
	IniFile *ini = new IniFile();
 
	std::string path{ filename + basepath_length };
 
	std::string path{ filename, basepath_length };
 
	ini->LoadFromDisk(path, BASESET_DIR);
 

	
 
	auto psep = path.rfind(PATHSEPCHAR);
 
	if (psep != std::string::npos) {
 
		path.erase(psep + 1);
 
	} else {
 
		path.clear();
 
	}
 

	
 
	if (set->FillSetDetails(ini, path.c_str(), filename)) {
 
	if (set->FillSetDetails(ini, path.c_str(), filename.c_str())) {
 
		Tbase_set *duplicate = nullptr;
 
		for (Tbase_set *c = BaseMedia<Tbase_set>::available_sets; c != nullptr; c = c->next) {
 
			if (c->name == set->name || c->shortname == set->shortname) {
 
				duplicate = c;
 
				break;
 
			}
 
		}
 
		if (duplicate != nullptr) {
 
			/* The more complete set takes precedence over the version number. */
 
			if ((duplicate->valid_files == set->valid_files && duplicate->version >= set->version) ||
 
					duplicate->valid_files > set->valid_files) {
 
				DEBUG(grf, 1, "Not adding %s (%i) as base " SET_TYPE " set (duplicate, %s)", set->name.c_str(), set->version,
 
@@ -368,24 +368,24 @@ template <class Tbase_set>
 
{
 
	return BaseMedia<Tbase_set>::available_sets;
 
}
 

	
 
/**
 
 * Force instantiation of methods so we don't get linker errors.
 
 * @param repl_type the type of the BaseMedia to instantiate
 
 * @param set_type  the type of the BaseSet to instantiate
 
 */
 
#define INSTANTIATE_BASE_MEDIA_METHODS(repl_type, set_type) \
 
	template std::string repl_type::ini_set; \
 
	template const char *repl_type::GetExtension(); \
 
	template bool repl_type::AddFile(const char *filename, size_t pathlength, const char *tar_filename); \
 
	template bool repl_type::AddFile(const std::string &filename, size_t pathlength, const std::string &tar_filename); \
 
	template bool repl_type::HasSet(const struct ContentInfo *ci, bool md5sum); \
 
	template bool repl_type::SetSet(const std::string &name); \
 
	template char *repl_type::GetSetsList(char *p, const char *last); \
 
	template int repl_type::GetNumSets(); \
 
	template int repl_type::GetIndexOfUsedSet(); \
 
	template const set_type *repl_type::GetSet(int index); \
 
	template const set_type *repl_type::GetUsedSet(); \
 
	template bool repl_type::DetermineBestSet(); \
 
	template set_type *repl_type::GetAvailableSets(); \
 
	template const char *TryGetBaseSetFile(const ContentInfo *ci, bool md5sum, const set_type *s);
 

	
src/fileio.cpp
Show inline comments
 
@@ -237,25 +237,25 @@ static const char * const _subdirs[] = {
 
	"game" PATHSEP "library" PATHSEP,
 
	"screenshot" PATHSEP,
 
};
 
static_assert(lengthof(_subdirs) == NUM_SUBDIRS);
 

	
 
/**
 
 * The search paths OpenTTD could search through.
 
 * At least one of the slots has to be filled with a path.
 
 * An empty string tells that there is no such path for the
 
 * current operating system.
 
 */
 
std::array<std::string, NUM_SEARCHPATHS> _searchpaths;
 
TarList _tar_list[NUM_SUBDIRS];
 
std::array<TarList, NUM_SUBDIRS> _tar_list;
 
TarFileList _tar_filelist[NUM_SUBDIRS];
 

	
 
typedef std::map<std::string, std::string> TarLinkList;
 
static TarLinkList _tar_linklist[NUM_SUBDIRS]; ///< List of directory links
 

	
 
/**
 
 * Checks whether the given search path is a valid search path
 
 * @param sp the search path to check
 
 * @return true if the search path is valid
 
 */
 
bool IsValidSearchPath(Searchpath sp)
 
{
 
@@ -381,25 +381,25 @@ static FILE *FioFOpenFileSp(const std::s
 
	return f;
 
}
 

	
 
/**
 
 * Opens a file from inside a tar archive.
 
 * @param entry The entry to open.
 
 * @param[out] filesize If not \c nullptr, size of the opened file.
 
 * @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)
 
{
 
	FILE *f = fopen(entry.tar_filename, "rb");
 
	FILE *f = fopen(entry.tar_filename.c_str(), "rb");
 
	if (f == nullptr) return f;
 

	
 
	if (fseek(f, entry.position, SEEK_SET) < 0) {
 
		fclose(f);
 
		return nullptr;
 
	}
 

	
 
	if (filesize != nullptr) *filesize = entry.size;
 
	return f;
 
}
 

	
 
/**
 
@@ -604,34 +604,34 @@ uint TarScanner::DoScan(Subdirectory sd)
 
		num += fs.DoScan(HEIGHTMAP_DIR);
 
	}
 
	DEBUG(misc, 1, "Scan complete, found %d files", num);
 
	return num;
 
}
 

	
 
/**
 
 * Add a single file to the scanned files of a tar, circumventing the scanning code.
 
 * @param sd       The sub directory the file is in.
 
 * @param filename The name of the file to add.
 
 * @return True if the additions went correctly.
 
 */
 
bool TarScanner::AddFile(Subdirectory sd, const char *filename)
 
bool TarScanner::AddFile(Subdirectory sd, const std::string &filename)
 
{
 
	this->subdir = sd;
 
	return this->AddFile(filename, 0);
 
}
 

	
 
bool TarScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
bool TarScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
{
 
	/* No tar within tar. */
 
	assert(tar_filename == nullptr);
 
	assert(tar_filename.empty());
 

	
 
	/* The TAR-header, repeated for every file */
 
	struct TarHeader {
 
		char name[100];      ///< Name of the file
 
		char mode[8];
 
		char uid[8];
 
		char gid[8];
 
		char size[12];       ///< Size of the file, in ASCII
 
		char mtime[12];
 
		char chksum[8];
 
		char typeflag;
 
		char linkname[100];
 
@@ -641,59 +641,57 @@ bool TarScanner::AddFile(const char *fil
 
		char gname[32];
 
		char devmajor[8];
 
		char devminor[8];
 
		char prefix[155];    ///< Path of the file
 

	
 
		char unused[12];
 
	};
 

	
 
	/* Check if we already seen this file */
 
	TarList::iterator it = _tar_list[this->subdir].find(filename);
 
	if (it != _tar_list[this->subdir].end()) return false;
 

	
 
	FILE *f = fopen(filename, "rb");
 
	FILE *f = fopen(filename.c_str(), "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;
 

	
 
	const char *dupped_filename = stredup(filename);
 
	_tar_list[this->subdir][filename].filename = dupped_filename;
 
	_tar_list[this->subdir][filename].dirname = nullptr;
 
	_tar_list[this->subdir][filename] = std::string{};
 

	
 
	TarLinkList links; ///< Temporary list to collect links
 

	
 
	TarHeader th;
 
	char buf[sizeof(th.name) + 1], *end;
 
	char name[sizeof(th.prefix) + 1 + sizeof(th.name) + 1];
 
	char link[sizeof(th.linkname) + 1];
 
	char dest[sizeof(th.prefix) + 1 + sizeof(th.name) + 1 + 1 + sizeof(th.linkname) + 1];
 
	size_t num = 0, pos = 0;
 

	
 
	/* Make a char of 512 empty bytes */
 
	char empty[512];
 
	memset(&empty[0], 0, sizeof(empty));
 

	
 
	for (;;) { // Note: feof() always returns 'false' after 'fseek()'. Cool, isn't it?
 
		size_t num_bytes_read = fread(&th, 1, 512, f);
 
		if (num_bytes_read != 512) break;
 
		pos += num_bytes_read;
 

	
 
		/* Check if we have the new tar-format (ustar) or the old one (a lot of zeros after 'link' field) */
 
		if (strncmp(th.magic, "ustar", 5) != 0 && memcmp(&th.magic, &empty[0], 512 - offsetof(TarHeader, magic)) != 0) {
 
			/* 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);
 
			DEBUG(misc, 0, "The file '%s' isn't a valid tar-file", filename.c_str());
 
			fclose(f);
 
			return false;
 
		}
 

	
 
		name[0] = '\0';
 

	
 
		/* The prefix contains the directory-name */
 
		if (th.prefix[0] != '\0') {
 
			strecpy(name, th.prefix, lastof(name));
 
			strecat(name, PATHSEP, lastof(name));
 
		}
 

	
 
@@ -705,25 +703,25 @@ bool TarScanner::AddFile(const char *fil
 
		size_t skip = strtoul(buf, &end, 8);
 

	
 
		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 */
 
				TarFileListEntry entry;
 
				entry.tar_filename = dupped_filename;
 
				entry.tar_filename = filename;
 
				entry.size         = skip;
 
				entry.position     = pos;
 

	
 
				/* 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);
 
				if (_tar_filelist[this->subdir].insert(TarFileList::value_type(name, entry)).second) num++;
 

	
 
				break;
 
			}
 

	
 
@@ -773,64 +771,64 @@ bool TarScanner::AddFile(const char *fil
 
						/* Truncate 'dest' after last PATHSEPCHAR.
 
						 * This assumes that the truncated part is a real directory and not a link. */
 
						destpos = strrchr(dest, PATHSEPCHAR);
 
						if (destpos == nullptr) destpos = dest;
 
						*destpos = '\0';
 
					} else {
 
						/* Append at end of 'dest' */
 
						if (destpos != dest) destpos = strecpy(destpos, PATHSEP, lastof(dest));
 
						destpos = strecpy(destpos, pos, lastof(dest));
 
					}
 

	
 
					if (destpos >= lastof(dest)) {
 
						DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename);
 
						DEBUG(misc, 0, "The length of a link in tar-file '%s' is too large (malformed?)", filename.c_str());
 
						fclose(f);
 
						return false;
 
					}
 

	
 
					pos = next;
 
				}
 

	
 
				/* Store links in temporary list */
 
				DEBUG(misc, 6, "Found link in tar: %s -> %s", name, dest);
 
				links.insert(TarLinkList::value_type(name, dest));
 

	
 
				break;
 
			}
 

	
 
			case '5': // directory
 
				/* Convert to lowercase and our PATHSEPCHAR */
 
				SimplifyFileName(name);
 

	
 
				/* Store the first directory name we detect */
 
				DEBUG(misc, 6, "Found dir in tar: %s", name);
 
				if (_tar_list[this->subdir][filename].dirname == nullptr) _tar_list[this->subdir][filename].dirname = stredup(name);
 
				if (_tar_list[this->subdir][filename].empty()) _tar_list[this->subdir][filename] = name;
 
				break;
 

	
 
			default:
 
				/* Ignore other types */
 
				break;
 
		}
 

	
 
		/* 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);
 
			DEBUG(misc, 0, "The file '%s' can't be read as a valid tar-file", filename.c_str());
 
			fclose(f);
 
			return false;
 
		}
 
		pos += skip;
 
	}
 

	
 
	DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename, num);
 
	DEBUG(misc, 1, "Found tar '%s' with " PRINTF_SIZE " new files", filename.c_str(), num);
 
	fclose(f);
 

	
 
	/* Resolve file links and store directory links.
 
	 * We restrict usage of links to two cases:
 
	 *  1) Links to directories:
 
	 *      Both the source path and the destination path must NOT contain any further links.
 
	 *      When resolving files at most one directory link is resolved.
 
	 *  2) Links to files:
 
	 *      The destination path must NOT contain any links.
 
	 *      The source path may contain one directory link.
 
	 */
 
	for (TarLinkList::iterator link = links.begin(); link != links.end(); link++) {
 
@@ -846,28 +844,28 @@ bool TarScanner::AddFile(const char *fil
 
 * Extract the tar with the given filename in the directory
 
 * where the tar resides.
 
 * @param tar_filename the name of the tar to extract.
 
 * @param subdir The sub directory the tar is in.
 
 * @return false on failure.
 
 */
 
bool ExtractTar(const std::string &tar_filename, Subdirectory subdir)
 
{
 
	TarList::iterator it = _tar_list[subdir].find(tar_filename);
 
	/* We don't know the file. */
 
	if (it == _tar_list[subdir].end()) return false;
 

	
 
	const char *dirname = (*it).second.dirname;
 
	const auto &dirname = (*it).second;
 

	
 
	/* The file doesn't have a sub directory! */
 
	if (dirname == nullptr) {
 
	if (dirname.empty()) {
 
		DEBUG(misc, 1, "Extracting %s failed; archive rejected, the contents must be in a sub directory", tar_filename.c_str());
 
		return false;
 
	}
 

	
 
	std::string filename = tar_filename;
 
	auto p = filename.find_last_of(PATHSEPCHAR);
 
	/* The file's path does not have a separator? */
 
	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());
 
	FioCreateDirectory(filename);
 
@@ -1299,45 +1297,45 @@ static uint ScanPath(FileScanner *fs, co
 

	
 
		std::string filename(path);
 
		filename += d_name;
 

	
 
		if (S_ISDIR(sb.st_mode)) {
 
			/* Directory */
 
			if (!recursive) continue;
 
			if (strcmp(d_name, ".") == 0 || strcmp(d_name, "..") == 0) continue;
 
			AppendPathSeparator(filename);
 
			num += ScanPath(fs, extension, filename.c_str(), basepath_length, recursive);
 
		} else if (S_ISREG(sb.st_mode)) {
 
			/* File */
 
			if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename.c_str(), basepath_length, nullptr)) num++;
 
			if (MatchesExtension(extension, filename.c_str()) && fs->AddFile(filename, basepath_length, {})) num++;
 
		}
 
	}
 

	
 
	closedir(dir);
 

	
 
	return num;
 
}
 

	
 
/**
 
 * Scan the given tar and add graphics sets when it finds one.
 
 * @param fs        the file scanner to scan for
 
 * @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)
 
{
 
	uint num = 0;
 
	const char *filename = (*tar).first.c_str();
 
	const auto &filename = (*tar).first;
 

	
 
	if (MatchesExtension(extension, filename) && 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;
 
}
 

	
 
/**
 
 * Scan for files with the given extension in the given search path.
 
 * @param extension the extension of files to search for.
 
 * @param sd        the sub directory to search in.
 
 * @param tars      whether to search in the tars too.
 
 * @param recursive whether to search recursively
 
 * @return the number of found files, i.e. the number of times that
 
 *         AddFile returned true.
src/fileio_func.h
Show inline comments
 
@@ -65,45 +65,45 @@ public:
 

	
 
	uint Scan(const char *extension, Subdirectory sd, bool tars = true, bool recursive = true);
 
	uint Scan(const char *extension, const char *directory, bool recursive = true);
 

	
 
	/**
 
	 * Add a file with the given filename.
 
	 * @param filename        the full path to the file to read
 
	 * @param basepath_length amount of characters to chop of before to get a
 
	 *                        filename relative to the search path.
 
	 * @param tar_filename    the name of the tar file the file is read from.
 
	 * @return true if the file is added.
 
	 */
 
	virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) = 0;
 
	virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) = 0;
 
};
 

	
 
/** Helper for scanning for files with tar as extension */
 
class TarScanner : FileScanner {
 
	uint DoScan(Subdirectory sd);
 
public:
 
	/** The mode of tar scanning. */
 
	enum Mode {
 
		NONE     = 0,      ///< Scan nothing.
 
		BASESET  = 1 << 0, ///< Scan for base sets.
 
		NEWGRF   = 1 << 1, ///< Scan for non-base sets.
 
		AI       = 1 << 2, ///< Scan for AIs and its libraries.
 
		SCENARIO = 1 << 3, ///< Scan for scenarios and heightmaps.
 
		GAME     = 1 << 4, ///< Scan for game scripts.
 
		ALL      = BASESET | NEWGRF | AI | SCENARIO | GAME, ///< Scan for everything.
 
	};
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename = nullptr) override;
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename = nullptr) override;
 

	
 
	bool AddFile(Subdirectory sd, const char *filename);
 
	bool AddFile(Subdirectory sd, const std::string &filename);
 

	
 
	/** Do the scan for Tars. */
 
	static uint DoScan(TarScanner::Mode mode);
 
};
 

	
 
DECLARE_ENUM_AS_BIT_SET(TarScanner::Mode)
 

	
 
/* Implementation of opendir/readdir/closedir for Windows */
 
#if defined(_WIN32)
 
struct DIR;
 

	
 
struct dirent { // XXX - only d_name implemented
src/fios.cpp
Show inline comments
 
@@ -33,25 +33,25 @@
 
/* Variables to display file lists */
 
static std::string *_fios_path = nullptr;
 
SortingBits _savegame_sort_order = SORT_BY_DATE | SORT_DESCENDING;
 

	
 
/* OS-specific functions are taken from their respective files (win32/unix/os2 .c) */
 
extern bool FiosIsRoot(const char *path);
 
extern bool FiosIsValidFile(const char *path, const struct dirent *ent, struct stat *sb);
 
extern bool FiosIsHiddenFile(const struct dirent *ent);
 
extern void FiosGetDrives(FileList &file_list);
 
extern bool FiosGetDiskFreeSpace(const char *path, uint64 *tot);
 

	
 
/* get the name of an oldstyle savegame */
 
extern void GetOldSaveGameName(const char *file, char *title, const char *last);
 
extern void GetOldSaveGameName(const std::string &file, char *title, const char *last);
 

	
 
/**
 
 * Compare two FiosItem's. Used with sort when sorting the file list.
 
 * @param other The FiosItem to compare to.
 
 * @return for ascending order: returns true if da < db. Vice versa for descending order.
 
 */
 
bool FiosItem::operator< (const FiosItem &other) const
 
{
 
	int r = false;
 

	
 
	if ((_savegame_sort_order & SORT_BY_NAME) == 0 && (*this).mtime != other.mtime) {
 
		r = (*this).mtime - other.mtime;
 
@@ -251,105 +251,106 @@ std::string FiosMakeHeightmapName(const 
 

	
 
/**
 
 * Delete a file.
 
 * @param name Filename to delete.
 
 * @return Whether the file deletion was successful.
 
 */
 
bool FiosDelete(const char *name)
 
{
 
	std::string filename = FiosMakeSavegameName(name);
 
	return unlink(filename.c_str()) == 0;
 
}
 

	
 
typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const char *filename, const char *ext, char *title, const char *last);
 
typedef FiosType fios_getlist_callback_proc(SaveLoadOperation fop, const std::string &filename, const char *ext, char *title, const char *last);
 

	
 
/**
 
 * Scanner to scan for a particular type of FIOS file.
 
 */
 
class FiosFileScanner : public FileScanner {
 
	SaveLoadOperation fop;   ///< The kind of file we are looking for.
 
	fios_getlist_callback_proc *callback_proc; ///< Callback to check whether the file may be added
 
	FileList &file_list;     ///< Destination of the found files.
 
public:
 
	/**
 
	 * Create the scanner
 
	 * @param fop Purpose of collecting the list.
 
	 * @param callback_proc The function that is called where you need to do the filtering.
 
	 * @param file_list Destination of the found files.
 
	 */
 
	FiosFileScanner(SaveLoadOperation fop, fios_getlist_callback_proc *callback_proc, FileList &file_list) :
 
			fop(fop), callback_proc(callback_proc), file_list(file_list)
 
	{}
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override;
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
 
};
 

	
 
/**
 
 * Try to add a fios item set with the given filename.
 
 * @param filename        the full path to the file to read
 
 * @param basepath_length amount of characters to chop of before to get a relative filename
 
 * @return true if the file is added.
 
 */
 
bool FiosFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
bool FiosFileScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
{
 
	const char *ext = strrchr(filename, '.');
 
	if (ext == nullptr) return false;
 
	auto sep = filename.rfind('.');
 
	if (sep == std::string::npos) return false;
 
	std::string ext = filename.substr(sep);
 

	
 
	char fios_title[64];
 
	fios_title[0] = '\0'; // reset the title;
 

	
 
	FiosType type = this->callback_proc(this->fop, filename, ext, fios_title, lastof(fios_title));
 
	FiosType type = this->callback_proc(this->fop, filename, ext.c_str(), fios_title, lastof(fios_title));
 
	if (type == FIOS_TYPE_INVALID) return false;
 

	
 
	for (const FiosItem *fios = file_list.Begin(); fios != file_list.End(); fios++) {
 
		if (strcmp(fios->name, filename) == 0) return false;
 
		if (filename == fios->name) return false;
 
	}
 

	
 
	FiosItem *fios = file_list.Append();
 
#ifdef _WIN32
 
	// Retrieve the file modified date using GetFileTime rather than stat to work around an obscure MSVC bug that affects Windows XP
 
	HANDLE fh = CreateFile(OTTD2FS(filename), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
 
	HANDLE fh = CreateFile(OTTD2FS(filename.c_str()), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
 

	
 
	if (fh != INVALID_HANDLE_VALUE) {
 
		FILETIME ft;
 
		ULARGE_INTEGER ft_int64;
 

	
 
		if (GetFileTime(fh, nullptr, nullptr, &ft) != 0) {
 
			ft_int64.HighPart = ft.dwHighDateTime;
 
			ft_int64.LowPart = ft.dwLowDateTime;
 

	
 
			// Convert from hectonanoseconds since 01/01/1601 to seconds since 01/01/1970
 
			fios->mtime = ft_int64.QuadPart / 10000000ULL - 11644473600ULL;
 
		} else {
 
			fios->mtime = 0;
 
		}
 

	
 
		CloseHandle(fh);
 
#else
 
	struct stat sb;
 
	if (stat(filename, &sb) == 0) {
 
	if (stat(filename.c_str(), &sb) == 0) {
 
		fios->mtime = sb.st_mtime;
 
#endif
 
	} else {
 
		fios->mtime = 0;
 
	}
 

	
 
	fios->type = type;
 
	strecpy(fios->name, filename, lastof(fios->name));
 
	strecpy(fios->name, filename.c_str(), lastof(fios->name));
 

	
 
	/* If the file doesn't have a title, use its filename */
 
	const char *t = fios_title;
 
	if (StrEmpty(fios_title)) {
 
		t = strrchr(filename, PATHSEPCHAR);
 
		t = (t == nullptr) ? filename : (t + 1);
 
		auto ps = filename.rfind(PATHSEPCHAR);
 
		t = filename.c_str() + (ps == std::string::npos ? 0 : ps + 1);
 
	}
 
	strecpy(fios->title, t, lastof(fios->title));
 
	str_validate(fios->title, lastof(fios->title));
 

	
 
	return true;
 
}
 

	
 

	
 
/**
 
 * Fill the list of the files in a directory, according to some arbitrary rule.
 
 * @param fop Purpose of collecting the list.
 
 * @param callback_proc The function that is called where you need to do the filtering.
 
@@ -424,52 +425,51 @@ static void FiosGetFileList(SaveLoadOper
 

	
 
	file_list.Compact();
 
}
 

	
 
/**
 
 * Get the title of a file, which (if exists) is stored in a file named
 
 * the same as the data file but with '.title' added to it.
 
 * @param file filename to get the title for
 
 * @param title the title buffer to fill
 
 * @param last the last element in the title buffer
 
 * @param subdir the sub directory to search in
 
 */
 
static void GetFileTitle(const char *file, char *title, const char *last, Subdirectory subdir)
 
static void GetFileTitle(const std::string &file, char *title, const char *last, Subdirectory subdir)
 
{
 
	char buf[MAX_PATH];
 
	strecpy(buf, file, lastof(buf));
 
	strecat(buf, ".title", lastof(buf));
 
	std::string buf = file;
 
	buf += ".title";
 

	
 
	FILE *f = FioFOpenFile(buf, "r", subdir);
 
	if (f == nullptr) return;
 

	
 
	size_t read = fread(title, 1, last - title, f);
 
	assert(title + read <= last);
 
	title[read] = '\0';
 
	str_validate(title, last);
 
	FioFCloseFile(f);
 
}
 

	
 
/**
 
 * Callback for FiosGetFileList. It tells if a file is a savegame or not.
 
 * @param fop Purpose of collecting the list.
 
 * @param file Name of the file to check.
 
 * @param ext A pointer to the extension identifier inside file
 
 * @param title Buffer if a callback wants to lookup the title of the file; nullptr to skip the lookup
 
 * @param last Last available byte in buffer (to prevent buffer overflows); not used when title == nullptr
 
 * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a savegame
 
 * @see FiosGetFileList
 
 * @see FiosGetSavegameList
 
 */
 
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
 
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last)
 
{
 
	/* Show savegame files
 
	 * .SAV OpenTTD saved game
 
	 * .SS1 Transport Tycoon Deluxe preset game
 
	 * .SV1 Transport Tycoon Deluxe (Patch) saved game
 
	 * .SV2 Transport Tycoon Deluxe (Patch) saved 2-player game */
 

	
 
	/* Don't crash if we supply no extension */
 
	if (ext == nullptr) return FIOS_TYPE_INVALID;
 

	
 
	if (strcasecmp(ext, ".sav") == 0) {
 
		GetFileTitle(file, title, last, SAVE_DIR);
 
@@ -506,25 +506,25 @@ void FiosGetSavegameList(SaveLoadOperati
 

	
 
/**
 
 * Callback for FiosGetFileList. It tells if a file is a scenario or not.
 
 * @param fop Purpose of collecting the list.
 
 * @param file Name of the file to check.
 
 * @param ext A pointer to the extension identifier inside file
 
 * @param title Buffer if a callback wants to lookup the title of the file
 
 * @param last Last available byte in buffer (to prevent buffer overflows)
 
 * @return a FIOS_TYPE_* type of the found file, FIOS_TYPE_INVALID if not a scenario
 
 * @see FiosGetFileList
 
 * @see FiosGetScenarioList
 
 */
 
static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
 
static FiosType FiosGetScenarioListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last)
 
{
 
	/* Show scenario files
 
	 * .SCN OpenTTD style scenario file
 
	 * .SV0 Transport Tycoon Deluxe (Patch) scenario
 
	 * .SS0 Transport Tycoon Deluxe preset scenario */
 
	if (strcasecmp(ext, ".scn") == 0) {
 
		GetFileTitle(file, title, last, SCENARIO_DIR);
 
		return FIOS_TYPE_SCENARIO;
 
	}
 

	
 
	if (fop == SLO_LOAD) {
 
		if (strcasecmp(ext, ".sv0") == 0 || strcasecmp(ext, ".ss0") == 0 ) {
 
@@ -547,25 +547,25 @@ void FiosGetScenarioList(SaveLoadOperati
 
	static std::optional<std::string> fios_scn_path;
 

	
 
	/* Copy the default path on first run or on 'New Game' */
 
	if (!fios_scn_path) fios_scn_path = FioFindDirectory(SCENARIO_DIR);
 

	
 
	_fios_path = &(*fios_scn_path);
 

	
 
	std::string base_path = FioFindDirectory(SCENARIO_DIR);
 
	Subdirectory subdir = (fop == SLO_LOAD && base_path == *_fios_path) ? SCENARIO_DIR : NO_DIRECTORY;
 
	FiosGetFileList(fop, &FiosGetScenarioListCallback, subdir, file_list);
 
}
 

	
 
static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last)
 
static FiosType FiosGetHeightmapListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last)
 
{
 
	/* Show heightmap files
 
	 * .PNG PNG Based heightmap files
 
	 * .BMP BMP Based heightmap files
 
	 */
 

	
 
	FiosType type = FIOS_TYPE_INVALID;
 

	
 
#ifdef WITH_PNG
 
	if (strcasecmp(ext, ".png") == 0) type = FIOS_TYPE_PNG;
 
#endif /* WITH_PNG */
 

	
 
@@ -660,46 +660,43 @@ public:
 
	/**
 
	 * Scan, but only if it's needed.
 
	 * @param rescan whether to force scanning even when it's not necessary
 
	 */
 
	void Scan(bool rescan)
 
	{
 
		if (this->scanned && !rescan) return;
 

	
 
		this->FileScanner::Scan(".id", SCENARIO_DIR, true, true);
 
		this->scanned = true;
 
	}
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override
 
	{
 
		FILE *f = FioFOpenFile(filename, "r", SCENARIO_DIR);
 
		if (f == nullptr) return false;
 

	
 
		ScenarioIdentifier id;
 
		int fret = fscanf(f, "%u", &id.scenid);
 
		FioFCloseFile(f);
 
		if (fret != 1) return false;
 
		strecpy(id.filename, filename, lastof(id.filename));
 
		strecpy(id.filename, filename.c_str(), lastof(id.filename));
 

	
 
		Md5 checksum;
 
		uint8 buffer[1024];
 
		char basename[MAX_PATH]; ///< \a filename without the extension.
 
		size_t len, size;
 

	
 
		/* open the scenario file, but first get the name.
 
		 * This is safe as we check on extension which
 
		 * must always exist. */
 
		strecpy(basename, filename, lastof(basename));
 
		*strrchr(basename, '.') = '\0';
 
		f = FioFOpenFile(basename, "rb", SCENARIO_DIR, &size);
 
		f = FioFOpenFile(filename.substr(0, filename.rfind('.')), "rb", SCENARIO_DIR, &size);
 
		if (f == nullptr) return false;
 

	
 
		/* calculate md5sum */
 
		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);
src/fios.h
Show inline comments
 
@@ -214,15 +214,15 @@ void ShowSaveLoadDialog(AbstractFileType
 

	
 
void FiosGetSavegameList(SaveLoadOperation fop, FileList &file_list);
 
void FiosGetScenarioList(SaveLoadOperation fop, FileList &file_list);
 
void FiosGetHeightmapList(SaveLoadOperation fop, FileList &file_list);
 

	
 
const char *FiosBrowseTo(const FiosItem *item);
 

	
 
StringID FiosGetDescText(const char **path, uint64 *total_free);
 
bool FiosDelete(const char *name);
 
std::string FiosMakeHeightmapName(const char *name);
 
std::string FiosMakeSavegameName(const char *name);
 

	
 
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const char *file, const char *ext, char *title, const char *last);
 
FiosType FiosGetSavegameListCallback(SaveLoadOperation fop, const std::string &file, const char *ext, char *title, const char *last);
 

	
 
#endif /* FIOS_H */
src/game/game_text.cpp
Show inline comments
 
@@ -197,25 +197,25 @@ private:
 
public:
 
	/** Initialise */
 
	LanguageScanner(GameStrings *gs, const std::string &exclude) : gs(gs), exclude(exclude) {}
 

	
 
	/**
 
	 * Scan.
 
	 */
 
	void Scan(const char *directory)
 
	{
 
		this->FileScanner::Scan(".txt", directory, false);
 
	}
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override
 
	{
 
		if (exclude == filename) return true;
 

	
 
		auto ls = ReadRawLanguageStrings(filename);
 
		if (!ls.IsValid()) return false;
 

	
 
		gs->raw_strings.push_back(std::move(ls));
 
		return true;
 
	}
 
};
 

	
 
/**
 
@@ -235,39 +235,39 @@ GameStrings *LoadTranslations()
 

	
 
	auto ls = ReadRawLanguageStrings(filename);
 
	if (!ls.IsValid()) return nullptr;
 

	
 
	GameStrings *gs = new GameStrings();
 
	try {
 
		gs->raw_strings.push_back(std::move(ls));
 

	
 
		/* Scan for other language files */
 
		LanguageScanner scanner(gs, filename);
 
		std::string ldir = basename + "lang" PATHSEP;
 

	
 
		const char *tar_filename = info->GetTarFile();
 
		const std::string tar_filename = info->GetTarFile();
 
		TarList::iterator iter;
 
		if (tar_filename != nullptr && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) {
 
		if (!tar_filename.empty() && (iter = _tar_list[GAME_DIR].find(tar_filename)) != _tar_list[GAME_DIR].end()) {
 
			/* The main script is in a tar file, so find all files that
 
			 * are in the same tar and add them to the langfile scanner. */
 
			TarFileList::iterator tar;
 
			FOR_ALL_TARS(tar, GAME_DIR) {
 
				/* Not in the same tar. */
 
				if (tar->second.tar_filename != iter->first) continue;
 

	
 
				/* Check the path and extension. */
 
				if (tar->first.size() <= ldir.size() || tar->first.compare(0, ldir.size(), ldir) != 0) continue;
 
				if (tar->first.compare(tar->first.size() - 4, 4, ".txt") != 0) continue;
 

	
 
				scanner.AddFile(tar->first.c_str(), 0, tar_filename);
 
				scanner.AddFile(tar->first, 0, tar_filename);
 
			}
 
		} else {
 
			/* Scan filesystem */
 
			scanner.Scan(ldir.c_str());
 
		}
 

	
 
		gs->Compile();
 
		return gs;
 
	} catch (...) {
 
		delete gs;
 
		return nullptr;
 
	}
src/newgrf_config.cpp
Show inline comments
 
@@ -577,41 +577,41 @@ compatible_grf:
 
}
 

	
 
/** Helper for scanning for files with GRF as extension */
 
class GRFFileScanner : FileScanner {
 
	uint next_update; ///< The next (realtime tick) we do update the screen.
 
	uint num_scanned; ///< The number of GRFs we have scanned.
 

	
 
public:
 
	GRFFileScanner() : next_update(_realtime_tick), num_scanned(0)
 
	{
 
	}
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override;
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
 

	
 
	/** Do the scan for GRFs. */
 
	static uint DoScan()
 
	{
 
		GRFFileScanner fs;
 
		int ret = fs.Scan(".grf", NEWGRF_DIR);
 
		/* The number scanned and the number returned may not be the same;
 
		 * duplicate NewGRFs and base sets are ignored in the return value. */
 
		_settings_client.gui.last_newgrf_count = fs.num_scanned;
 
		return ret;
 
	}
 
};
 

	
 
bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
bool GRFFileScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
{
 
	GRFConfig *c = new GRFConfig(filename + basepath_length);
 
	GRFConfig *c = new GRFConfig(filename.c_str() + basepath_length);
 

	
 
	bool added = true;
 
	if (FillGRFDetails(c, false)) {
 
		if (_all_grfs == nullptr) {
 
			_all_grfs = c;
 
		} else {
 
			/* Insert file into list at a position determined by its
 
			 * name, so the list is sorted as we go along */
 
			GRFConfig **pd, *d;
 
			bool stop = false;
 
			for (pd = &_all_grfs; (d = *pd) != nullptr; pd = &d->next) {
 
				if (c->ident.grfid == d->ident.grfid && memcmp(c->ident.md5sum, d->ident.md5sum, sizeof(c->ident.md5sum)) == 0) added = false;
src/openttd.cpp
Show inline comments
 
@@ -619,25 +619,25 @@ int openttd_main(int argc, char *argv[])
 
			}
 
		case 'e': _switch_mode = (_switch_mode == SM_LOAD_GAME || _switch_mode == SM_LOAD_SCENARIO ? SM_LOAD_SCENARIO : SM_EDITOR); break;
 
		case 'g':
 
			if (mgo.opt != nullptr) {
 
				_file_to_saveload.SetName(mgo.opt);
 
				bool is_scenario = _switch_mode == SM_EDITOR || _switch_mode == SM_LOAD_SCENARIO;
 
				_switch_mode = is_scenario ? SM_LOAD_SCENARIO : SM_LOAD_GAME;
 
				_file_to_saveload.SetMode(SLO_LOAD, is_scenario ? FT_SCENARIO : FT_SAVEGAME, DFT_GAME_FILE);
 

	
 
				/* if the file doesn't exist or it is not a valid savegame, let the saveload code show an error */
 
				auto t = _file_to_saveload.name.find_last_of('.');
 
				if (t != std::string::npos) {
 
					FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name.c_str(), _file_to_saveload.name.substr(t).c_str(), nullptr, nullptr);
 
					FiosType ft = FiosGetSavegameListCallback(SLO_LOAD, _file_to_saveload.name, _file_to_saveload.name.substr(t).c_str(), nullptr, nullptr);
 
					if (ft != FIOS_TYPE_INVALID) _file_to_saveload.SetMode(ft);
 
				}
 

	
 
				break;
 
			}
 

	
 
			_switch_mode = SM_NEWGAME;
 
			/* Give a random map if no seed has been given */
 
			if (scanner->generation_seed == GENERATE_NEW_SEED) {
 
				scanner->generation_seed = InteractiveRandom();
 
			}
 
			break;
src/saveload/oldloader.cpp
Show inline comments
 
@@ -308,25 +308,25 @@ bool LoadOldSaveGame(const std::string &
 

	
 
	if (!game_loaded) {
 
		SetSaveLoadError(STR_GAME_SAVELOAD_ERROR_DATA_INTEGRITY_CHECK_FAILED);
 
		fclose(ls.file);
 
		return false;
 
	}
 

	
 
	_pause_mode = PM_PAUSED_SAVELOAD;
 

	
 
	return true;
 
}
 

	
 
void GetOldSaveGameName(const char *file, char *title, const char *last)
 
void GetOldSaveGameName(const std::string &file, char *title, const char *last)
 
{
 
	FILE *f = FioFOpenFile(file, "rb", NO_DIRECTORY);
 

	
 
	if (f == nullptr) {
 
		*title = '\0';
 
		return;
 
	}
 

	
 
	DetermineOldSavegameType(f, title, last);
 

	
 
	fclose(f);
 
}
src/script/script_info.cpp
Show inline comments
 
@@ -30,26 +30,24 @@ ScriptInfo::~ScriptInfo()
 
			delete item.labels;
 
		}
 
	}
 
	this->config_list.clear();
 

	
 
	free(this->author);
 
	free(this->name);
 
	free(this->short_name);
 
	free(this->description);
 
	free(this->date);
 
	free(this->instance_name);
 
	free(this->url);
 
	free(this->main_script);
 
	free(this->tar_file);
 
	free(this->SQ_instance);
 
}
 

	
 
bool ScriptInfo::CheckMethod(const char *name) const
 
{
 
	if (!this->engine->MethodExists(*this->SQ_instance, name)) {
 
		char error[1024];
 
		seprintf(error, lastof(error), "your info.nut/library.nut doesn't have the method '%s'", name);
 
		this->engine->ThrowError(error);
 
		return false;
 
	}
 
	return true;
 
@@ -72,27 +70,26 @@ bool ScriptInfo::CheckMethod(const char 
 
		"GetName",
 
		"GetShortName",
 
		"GetDescription",
 
		"GetVersion",
 
		"GetDate",
 
		"CreateInstance",
 
	};
 
	for (size_t i = 0; i < lengthof(required_functions); i++) {
 
		if (!info->CheckMethod(required_functions[i])) return SQ_ERROR;
 
	}
 

	
 
	/* Get location information of the scanner */
 
	info->main_script = stredup(info->scanner->GetMainScript());
 
	const char *tar_name = info->scanner->GetTarFile();
 
	if (tar_name != nullptr) info->tar_file = stredup(tar_name);
 
	info->main_script = info->scanner->GetMainScript();
 
	info->tar_file = info->scanner->GetTarFile();
 

	
 
	/* Cache the data the info file gives us. */
 
	if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetAuthor", &info->author, MAX_GET_OPS)) return SQ_ERROR;
 
	if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetName", &info->name, MAX_GET_OPS)) return SQ_ERROR;
 
	if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetShortName", &info->short_name, MAX_GET_OPS)) return SQ_ERROR;
 
	if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDescription", &info->description, MAX_GET_OPS)) return SQ_ERROR;
 
	if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "GetDate", &info->date, MAX_GET_OPS)) return SQ_ERROR;
 
	if (!info->engine->CallIntegerMethod(*info->SQ_instance, "GetVersion", &info->version, MAX_GET_OPS)) return SQ_ERROR;
 
	if (!info->engine->CallStringMethodStrdup(*info->SQ_instance, "CreateInstance", &info->instance_name, MAX_CREATEINSTANCE_OPS)) return SQ_ERROR;
 

	
 
	/* The GetURL function is optional. */
 
	if (info->engine->MethodExists(*info->SQ_instance, "GetURL")) {
src/script/script_info.hpp
Show inline comments
 
@@ -23,26 +23,24 @@ static const int MAX_CONSTRUCTOR_OPS    
 
static const int MAX_CREATEINSTANCE_OPS = 100000;
 
/** Number of operations to get the author and similar information. */
 
static const int MAX_GET_OPS            =   1000;
 
/** Maximum number of operations allowed for getting a particular setting. */
 
static const int MAX_GET_SETTING_OPS    = 100000;
 

	
 
/** All static information from an Script like name, version, etc. */
 
class ScriptInfo : public SimpleCountedObject {
 
public:
 
	ScriptInfo() :
 
		engine(nullptr),
 
		SQ_instance(nullptr),
 
		main_script(nullptr),
 
		tar_file(nullptr),
 
		author(nullptr),
 
		name(nullptr),
 
		short_name(nullptr),
 
		description(nullptr),
 
		date(nullptr),
 
		instance_name(nullptr),
 
		version(0),
 
		url(nullptr),
 
		scanner(nullptr)
 
	{}
 
	~ScriptInfo();
 

	
 
@@ -80,30 +78,30 @@ public:
 
	 * Get the name of the instance of the script to create.
 
	 */
 
	const char *GetInstanceName() const { return this->instance_name; }
 

	
 
	/**
 
	 * Get the website for this script.
 
	 */
 
	const char *GetURL() const { return this->url; }
 

	
 
	/**
 
	 * Get the filename of the main.nut script.
 
	 */
 
	const char *GetMainScript() const { return this->main_script; }
 
	const char *GetMainScript() const { return this->main_script.c_str(); }
 

	
 
	/**
 
	 * Get the filename of the tar the script is in.
 
	 */
 
	const char *GetTarFile() const { return this->tar_file; }
 
	std::string GetTarFile() const { return this->tar_file; }
 

	
 
	/**
 
	 * Check if a given method exists.
 
	 */
 
	bool CheckMethod(const char *name) const;
 

	
 
	/**
 
	 * Process the creation of a FileInfo object.
 
	 */
 
	static SQInteger Constructor(HSQUIRRELVM vm, ScriptInfo *info);
 

	
 
	/**
 
@@ -143,26 +141,26 @@ public:
 

	
 
	/**
 
	 * Can this script be selected by developers only?
 
	 */
 
	virtual bool IsDeveloperOnly() const { return false; }
 

	
 
protected:
 
	class Squirrel *engine;           ///< Engine used to register for Squirrel.
 
	HSQOBJECT *SQ_instance;           ///< The Squirrel instance created for this info.
 
	ScriptConfigItemList config_list; ///< List of settings from this Script.
 

	
 
private:
 
	char *main_script;            ///< The full path of the script.
 
	char *tar_file;               ///< If, which tar file the script was in.
 
	std::string main_script;      ///< The full path of the script.
 
	std::string tar_file;         ///< If, which tar file the script was in.
 
	const char *author;           ///< Author of the script.
 
	const char *name;             ///< Full name of the script.
 
	const char *short_name;       ///< Short name (4 chars) which uniquely identifies the script.
 
	const char *description;      ///< Small description of the script.
 
	const char *date;             ///< The date the script was written at.
 
	const char *instance_name;    ///< Name of the main class in the script.
 
	int version;                  ///< Version of the script.
 
	const char *url;              ///< URL of the script.
 

	
 
	class ScriptScanner *scanner; ///< ScriptScanner object that was used to scan this script info.
 
};
 

	
src/script/script_scanner.cpp
Show inline comments
 
@@ -14,90 +14,70 @@
 

	
 
#include "../script/squirrel.hpp"
 
#include "script_scanner.hpp"
 
#include "script_info.hpp"
 
#include "script_fatalerror.hpp"
 

	
 
#include "../network/network_content.h"
 
#include "../3rdparty/md5/md5.h"
 
#include "../tar_type.h"
 

	
 
#include "../safeguards.h"
 

	
 
bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
bool ScriptScanner::AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
{
 
	free(this->main_script);
 
	this->main_script = stredup(filename);
 
	if (this->main_script == nullptr) return false;
 
	this->main_script = filename;
 
	this->tar_file = tar_filename;
 

	
 
	free(this->tar_file);
 
	if (tar_filename != nullptr) {
 
		this->tar_file = stredup(tar_filename);
 
		if (this->tar_file == nullptr) return false;
 
	} else {
 
		this->tar_file = nullptr;
 
	}
 

	
 
	const char *end = this->main_script + strlen(this->main_script) + 1;
 
	char *p = strrchr(this->main_script, PATHSEPCHAR);
 
	if (p == nullptr) {
 
		p = this->main_script;
 
	} else {
 
		/* Skip over the path separator character. We don't need that. */
 
		p++;
 
	}
 

	
 
	strecpy(p, "main.nut", end);
 
	auto p = this->main_script.rfind(PATHSEPCHAR);
 
	this->main_script.erase(p != std::string::npos ? p + 1 : 0);
 
	this->main_script += "main.nut";
 

	
 
	if (!FioCheckFileExists(filename, this->subdir) || !FioCheckFileExists(this->main_script, this->subdir)) return false;
 

	
 
	this->ResetEngine();
 
	try {
 
		this->engine->LoadScript(filename);
 
		this->engine->LoadScript(filename.c_str());
 
	} catch (Script_FatalError &e) {
 
		DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage(), filename);
 
		DEBUG(script, 0, "Fatal error '%s' when trying to load the script '%s'.", e.GetErrorMessage(), filename.c_str());
 
		return false;
 
	}
 
	return true;
 
}
 

	
 
ScriptScanner::ScriptScanner() :
 
	engine(nullptr),
 
	main_script(nullptr),
 
	tar_file(nullptr)
 
	engine(nullptr)
 
{
 
}
 

	
 
void ScriptScanner::ResetEngine()
 
{
 
	this->engine->Reset();
 
	this->engine->SetGlobalPointer(this);
 
	this->RegisterAPI(this->engine);
 
}
 

	
 
void ScriptScanner::Initialize(const char *name)
 
{
 
	this->engine = new Squirrel(name);
 

	
 
	this->RescanDir();
 

	
 
	this->ResetEngine();
 
}
 

	
 
ScriptScanner::~ScriptScanner()
 
{
 
	this->Reset();
 

	
 
	free(this->main_script);
 
	free(this->tar_file);
 
	delete this->engine;
 
}
 

	
 
void ScriptScanner::RescanDir()
 
{
 
	/* Forget about older scans */
 
	this->Reset();
 

	
 
	/* Scan for scripts */
 
	this->Scan(this->GetFileName(), this->GetDirectory());
 
}
 

	
 
@@ -185,33 +165,33 @@ struct ScriptFileChecksumCreator : FileS
 

	
 
	/**
 
	 * Initialise the md5sum to be all zeroes,
 
	 * so we can easily xor the data.
 
	 */
 
	ScriptFileChecksumCreator(Subdirectory dir)
 
	{
 
		this->dir = dir;
 
		memset(this->md5sum, 0, sizeof(this->md5sum));
 
	}
 

	
 
	/* Add the file and calculate the md5 sum. */
 
	virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
 
	virtual bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename)
 
	{
 
		Md5 checksum;
 
		uint8 buffer[1024];
 
		size_t len, size;
 
		byte tmp_md5sum[16];
 

	
 
		/* Open the file ... */
 
		FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
 
		FILE *f = FioFOpenFile(filename.c_str(), "rb", this->dir, &size);
 
		if (f == nullptr) return false;
 

	
 
		/* ... calculate md5sum... */
 
		while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
 
			size -= len;
 
			checksum.Append(buffer, len);
 
		}
 
		checksum.Finish(tmp_md5sum);
 

	
 
		FioFCloseFile(f);
 

	
 
		/* ... and xor it to the overall md5sum. */
 
@@ -230,39 +210,39 @@ struct ScriptFileChecksumCreator : FileS
 
 * @return True iff they're the same.
 
 */
 
static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir)
 
{
 
	uint32 id = 0;
 
	const char *str = info->GetShortName();
 
	for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j);
 

	
 
	if (id != ci->unique_id) return false;
 
	if (!md5sum) return true;
 

	
 
	ScriptFileChecksumCreator checksum(dir);
 
	const char *tar_filename = info->GetTarFile();
 
	auto tar_filename = info->GetTarFile();
 
	TarList::iterator iter;
 
	if (tar_filename != nullptr && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) {
 
	if (!tar_filename.empty() && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) {
 
		/* The main script is in a tar file, so find all files that
 
		 * are in the same tar and add them to the MD5 checksumming. */
 
		TarFileList::iterator tar;
 
		FOR_ALL_TARS(tar, dir) {
 
			/* Not in the same tar. */
 
			if (tar->second.tar_filename != iter->first) continue;
 

	
 
			/* Check the extension. */
 
			const char *ext = strrchr(tar->first.c_str(), '.');
 
			if (ext == nullptr || strcasecmp(ext, ".nut") != 0) continue;
 

	
 
			checksum.AddFile(tar->first.c_str(), 0, tar_filename);
 
			checksum.AddFile(tar->first, 0, tar_filename);
 
		}
 
	} else {
 
		char path[MAX_PATH];
 
		strecpy(path, info->GetMainScript(), lastof(path));
 
		/* There'll always be at least 1 path separator character in a script
 
		 * main script name as the search algorithm requires the main script to
 
		 * be in a subdirectory of the script directory; so <dir>/<path>/main.nut. */
 
		*strrchr(path, PATHSEPCHAR) = '\0';
 
		checksum.Scan(".nut", path);
 
	}
 

	
 
	return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0;
src/script/script_scanner.hpp
Show inline comments
 
@@ -23,30 +23,30 @@ public:
 
	virtual ~ScriptScanner();
 

	
 
	virtual void Initialize() = 0;
 

	
 
	/**
 
	 * Get the engine of the main squirrel handler (it indexes all available scripts).
 
	 */
 
	class Squirrel *GetEngine() { return this->engine; }
 

	
 
	/**
 
	 * Get the current main script the ScanDir is currently tracking.
 
	 */
 
	const char *GetMainScript() { return this->main_script; }
 
	std::string GetMainScript() { return this->main_script; }
 

	
 
	/**
 
	 * Get the current tar file the ScanDir is currently tracking.
 
	 */
 
	const char *GetTarFile() { return this->tar_file; }
 
	std::string GetTarFile() { return this->tar_file; }
 

	
 
	/**
 
	 * Get the list of all registered scripts.
 
	 */
 
	const ScriptInfoList *GetInfoList() { return &this->info_list; }
 

	
 
	/**
 
	 * Get the list of the latest version of all registered scripts.
 
	 */
 
	const ScriptInfoList *GetUniqueInfoList() { return &this->info_single_list; }
 

	
 
	/**
 
@@ -66,35 +66,35 @@ public:
 
	 * @return True iff we have a script matching.
 
	 */
 
	bool HasScript(const struct ContentInfo *ci, bool md5sum);
 

	
 
	/**
 
	 * Find a script of a #ContentInfo
 
	 * @param ci The information to compare to.
 
	 * @param md5sum Whether to check the MD5 checksum.
 
	 * @return A filename of a file of the content, else \c nullptr.
 
	 */
 
	const char *FindMainScript(const ContentInfo *ci, bool md5sum);
 

	
 
	bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename) override;
 
	bool AddFile(const std::string &filename, size_t basepath_length, const std::string &tar_filename) override;
 

	
 
	/**
 
	 * Rescan the script dir.
 
	 */
 
	void RescanDir();
 

	
 
protected:
 
	class Squirrel *engine; ///< The engine we're scanning with.
 
	char *main_script;      ///< The full path of the script.
 
	char *tar_file;         ///< If, which tar file the script was in.
 
	class Squirrel *engine;  ///< The engine we're scanning with.
 
	std::string main_script; ///< The full path of the script.
 
	std::string tar_file;    ///< If, which tar file the script was in.
 

	
 
	ScriptInfoList info_list;        ///< The list of all script.
 
	ScriptInfoList info_single_list; ///< The list of all unique script. The best script (highest version) is shown.
 

	
 
	/**
 
	 * Initialize the scanner.
 
	 * @param name The name of the scanner ("AIScanner", "GSScanner", ..).
 
	 */
 
	void Initialize(const char *name);
 

	
 
	/**
 
	 * Get the script name how to store the script in memory.
src/tar_type.h
Show inline comments
 
@@ -3,41 +3,31 @@
 
 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
 
 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <http://www.gnu.org/licenses/>.
 
 */
 

	
 
/** @file tar_type.h Structs, typedefs and macros used for TAR file handling. */
 

	
 
#ifndef TAR_TYPE_H
 
#define TAR_TYPE_H
 

	
 
#include <map>
 
#include <string>
 
#include <array>
 

	
 
#include "fileio_type.h"
 

	
 
/** The define of a TarList. */
 
struct TarListEntry {
 
	const char *filename;
 
	const char *dirname;
 

	
 
	/* MSVC goes copying around this struct after initialisation, so it tries
 
	 * to free filename, which isn't set at that moment... but because it
 
	 * initializes the variable with garbage, it's going to segfault. */
 
	TarListEntry() : filename(nullptr), dirname(nullptr) {}
 
	~TarListEntry() { free(this->filename); free(this->dirname); }
 
};
 

	
 
struct TarFileListEntry {
 
	const char *tar_filename;
 
	std::string tar_filename;
 
	size_t size;
 
	size_t position;
 
};
 

	
 
typedef std::map<std::string, TarListEntry> TarList;
 
typedef std::map<std::string, std::string> TarList; ///< Map of tar file to tar directory.
 
typedef std::map<std::string, TarFileListEntry> TarFileList;
 
extern TarList _tar_list[NUM_SUBDIRS];
 
extern std::array<TarList, NUM_SUBDIRS> _tar_list;
 
extern TarFileList _tar_filelist[NUM_SUBDIRS];
 

	
 
#define FOR_ALL_TARS(tar, sd) for (tar = _tar_filelist[sd].begin(); tar != _tar_filelist[sd].end(); tar++)
 

	
 
#endif /* TAR_TYPE_H */
0 comments (0 inline, 0 general)