diff options
author | truebrain <truebrain@openttd.org> | 2011-11-29 23:21:52 +0000 |
---|---|---|
committer | truebrain <truebrain@openttd.org> | 2011-11-29 23:21:52 +0000 |
commit | e37149a1def6a0e63dda8e0964abf1b82316761a (patch) | |
tree | d8f80cee8a3b1eb60feb883796e43300fb50cfb1 /src/script/script_scanner.cpp | |
parent | ae8540f5e080adebca3e54c69aa7cd85a87e550b (diff) | |
download | openttd-e37149a1def6a0e63dda8e0964abf1b82316761a.tar.xz |
(svn r23362) -Codechange: refactor AIScanner, splitting it in AIScannerInfo and AIScannerLibrary
Diffstat (limited to 'src/script/script_scanner.cpp')
-rw-r--r-- | src/script/script_scanner.cpp | 214 |
1 files changed, 210 insertions, 4 deletions
diff --git a/src/script/script_scanner.cpp b/src/script/script_scanner.cpp index 049790196..57e412150 100644 --- a/src/script/script_scanner.cpp +++ b/src/script/script_scanner.cpp @@ -10,12 +10,14 @@ /** @file script_scanner.cpp Allows scanning for scripts. */ #include "../stdafx.h" +#include "../debug.h" #include "../string_func.h" #include "../fileio_func.h" #include <sys/stat.h> #include "../script/squirrel.hpp" #include "script_scanner.hpp" +#include "script_info.hpp" bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename) { @@ -50,18 +52,222 @@ bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const return true; } -ScriptScanner::ScriptScanner() +ScriptScanner::ScriptScanner() : + engine(NULL), + main_script(NULL), + tar_file(NULL) { - this->engine = new Squirrel("Scanner"); +} + +void ScriptScanner::Initialize(const char *name) +{ + this->engine = new Squirrel(name); /* Mark this class as global pointer */ this->engine->SetGlobalPointer(this); - this->main_script = NULL; - this->tar_file = NULL; + + this->RegisterAPI(this->engine); + this->RescanDir(); + + this->engine->ResetCrashed(); } ScriptScanner::~ScriptScanner() { + this->Reset(); + free(this->main_script); delete this->engine; } + +void ScriptScanner::RescanDir() +{ + /* Forget about older scans */ + this->Reset(); + + /* Scan for scripts */ + this->Scan(this->GetFileName(), this->GetDirectory()); +} + +void ScriptScanner::Reset() +{ + ScriptInfoList::iterator it = this->info_list.begin(); + for (; it != this->info_list.end(); it++) { + free((*it).first); + delete (*it).second; + } + it = this->info_single_list.begin(); + for (; it != this->info_single_list.end(); it++) { + free((*it).first); + } + + this->info_list.clear(); + this->info_single_list.clear(); +} + +void ScriptScanner::RegisterScript(ScriptInfo *info) +{ + char script_original_name[1024]; + this->GetScriptName(info, script_original_name, sizeof(script_original_name)); + strtolower(script_original_name); + + char script_name[1024]; + snprintf(script_name, sizeof(script_name), "%s.%d", script_original_name, info->GetVersion()); + + /* Check if GetShortName follows the rules */ + if (strlen(info->GetShortName()) != 4) { + DEBUG(ai, 0, "The script '%s' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName()); + delete info; + return; + } + + if (this->info_list.find(script_name) != this->info_list.end()) { + /* This script was already registered */ +#ifdef WIN32 + /* Windows doesn't care about the case */ + if (strcasecmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) { +#else + if (strcmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) { +#endif + delete info; + return; + } + + DEBUG(ai, 1, "Registering two scripts with the same name and version"); + DEBUG(ai, 1, " 1: %s", this->info_list[script_name]->GetMainScript()); + DEBUG(ai, 1, " 2: %s", info->GetMainScript()); + DEBUG(ai, 1, "The first is taking precedence."); + + delete info; + return; + } + + this->info_list[strdup(script_name)] = info; + + /* Add the script to the 'unique' script list, where only the highest version + * of the script is registered. */ + if (this->info_single_list.find(script_original_name) == this->info_single_list.end()) { + this->info_single_list[strdup(script_original_name)] = info; + } else if (this->info_single_list[script_original_name]->GetVersion() < info->GetVersion()) { + this->info_single_list[script_original_name] = info; + } +} + +char *ScriptScanner::GetConsoleList(char *p, const char *last, bool newest_only) const +{ + p += seprintf(p, last, "List of %s:\n", this->GetScannerName()); + const ScriptInfoList &list = newest_only ? this->info_single_list : this->info_list; + ScriptInfoList::const_iterator it = list.begin(); + for (; it != list.end(); it++) { + ScriptInfo *i = (*it).second; + p += seprintf(p, last, "%10s (v%d): %s\n", i->GetName(), i->GetVersion(), i->GetDescription()); + } + p += seprintf(p, last, "\n"); + + return p; +} + +#if defined(ENABLE_NETWORK) +#include "../network/network_content.h" +#include "../3rdparty/md5/md5.h" +#include "../tar_type.h" + +/** Helper for creating a MD5sum of all files within of a script. */ +struct ScriptFileChecksumCreator : FileScanner { + byte md5sum[16]; ///< The final md5sum. + Subdirectory dir; ///< The directory to look in. + + /** + * 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) + { + Md5 checksum; + uint8 buffer[1024]; + size_t len, size; + byte tmp_md5sum[16]; + + /* Open the file ... */ + FILE *f = FioFOpenFile(filename, "rb", this->dir, &size); + if (f == NULL) 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. */ + for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i]; + + return true; + } +}; + +/** + * Check whether the script given in info is the same as in ci based + * on the shortname and md5 sum. + * @param ci The information to compare to. + * @param md5sum Whether to check the MD5 checksum. + * @param info The script to get the shortname and md5 sum from. + * @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(); + TarList::iterator iter; + if (tar_filename != NULL && (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 == NULL || strcasecmp(ext, ".nut") != 0) continue; + + checksum.AddFile(tar->first.c_str(), 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; +} + +bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum) +{ + for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) { + if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return true; + } + return false; +} + +#endif /* ENABLE_NETWORK */ |