00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "../stdafx.h"
00013 #include "../debug.h"
00014 #include "../string_func.h"
00015 #include "../settings_type.h"
00016
00017 #include "../script/squirrel.hpp"
00018 #include "script_scanner.hpp"
00019 #include "script_info.hpp"
00020
00021 bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
00022 {
00023 free(this->main_script);
00024 this->main_script = strdup(filename);
00025 if (this->main_script == NULL) return false;
00026
00027 free(this->tar_file);
00028 if (tar_filename != NULL) {
00029 this->tar_file = strdup(tar_filename);
00030 if (this->tar_file == NULL) return false;
00031 } else {
00032 this->tar_file = NULL;
00033 }
00034
00035 const char *end = this->main_script + strlen(this->main_script) + 1;
00036 char *p = strrchr(this->main_script, PATHSEPCHAR);
00037 if (p == NULL) {
00038 p = this->main_script;
00039 } else {
00040
00041 p++;
00042 }
00043
00044 strecpy(p, "main.nut", end);
00045
00046 if (!FioCheckFileExists(filename, this->subdir) || !FioCheckFileExists(this->main_script, this->subdir)) return false;
00047
00048
00049 this->engine->ResetCrashed();
00050 this->engine->LoadScript(filename);
00051 return true;
00052 }
00053
00054 ScriptScanner::ScriptScanner() :
00055 engine(NULL),
00056 main_script(NULL),
00057 tar_file(NULL)
00058 {
00059 }
00060
00061 void ScriptScanner::Initialize(const char *name)
00062 {
00063 this->engine = new Squirrel(name);
00064
00065
00066 this->engine->SetGlobalPointer(this);
00067
00068 this->RegisterAPI(this->engine);
00069 this->RescanDir();
00070
00071 this->engine->ResetCrashed();
00072 }
00073
00074 ScriptScanner::~ScriptScanner()
00075 {
00076 this->Reset();
00077
00078 free(this->main_script);
00079 free(this->tar_file);
00080 delete this->engine;
00081 }
00082
00083 void ScriptScanner::RescanDir()
00084 {
00085
00086 this->Reset();
00087
00088
00089 this->Scan(this->GetFileName(), this->GetDirectory());
00090 }
00091
00092 void ScriptScanner::Reset()
00093 {
00094 ScriptInfoList::iterator it = this->info_list.begin();
00095 for (; it != this->info_list.end(); it++) {
00096 free((*it).first);
00097 delete (*it).second;
00098 }
00099 it = this->info_single_list.begin();
00100 for (; it != this->info_single_list.end(); it++) {
00101 free((*it).first);
00102 }
00103
00104 this->info_list.clear();
00105 this->info_single_list.clear();
00106 }
00107
00108 void ScriptScanner::RegisterScript(ScriptInfo *info)
00109 {
00110 char script_original_name[1024];
00111 this->GetScriptName(info, script_original_name, sizeof(script_original_name));
00112 strtolower(script_original_name);
00113
00114 char script_name[1024];
00115 snprintf(script_name, sizeof(script_name), "%s.%d", script_original_name, info->GetVersion());
00116
00117
00118 if (strlen(info->GetShortName()) != 4) {
00119 DEBUG(script, 0, "The script '%s' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName());
00120 delete info;
00121 return;
00122 }
00123
00124 if (this->info_list.find(script_name) != this->info_list.end()) {
00125
00126 #ifdef WIN32
00127
00128 if (strcasecmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
00129 #else
00130 if (strcmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
00131 #endif
00132 delete info;
00133 return;
00134 }
00135
00136 DEBUG(script, 1, "Registering two scripts with the same name and version");
00137 DEBUG(script, 1, " 1: %s", this->info_list[script_name]->GetMainScript());
00138 DEBUG(script, 1, " 2: %s", info->GetMainScript());
00139 DEBUG(script, 1, "The first is taking precedence.");
00140
00141 delete info;
00142 return;
00143 }
00144
00145 this->info_list[strdup(script_name)] = info;
00146
00147 if (!info->IsDeveloperOnly() || _settings_client.gui.ai_developer_tools) {
00148
00149
00150 if (this->info_single_list.find(script_original_name) == this->info_single_list.end()) {
00151 this->info_single_list[strdup(script_original_name)] = info;
00152 } else if (this->info_single_list[script_original_name]->GetVersion() < info->GetVersion()) {
00153 this->info_single_list[script_original_name] = info;
00154 }
00155 }
00156 }
00157
00158 char *ScriptScanner::GetConsoleList(char *p, const char *last, bool newest_only) const
00159 {
00160 p += seprintf(p, last, "List of %s:\n", this->GetScannerName());
00161 const ScriptInfoList &list = newest_only ? this->info_single_list : this->info_list;
00162 ScriptInfoList::const_iterator it = list.begin();
00163 for (; it != list.end(); it++) {
00164 ScriptInfo *i = (*it).second;
00165 p += seprintf(p, last, "%10s (v%d): %s\n", i->GetName(), i->GetVersion(), i->GetDescription());
00166 }
00167 p += seprintf(p, last, "\n");
00168
00169 return p;
00170 }
00171
00172 #if defined(ENABLE_NETWORK)
00173 #include "../network/network_content.h"
00174 #include "../3rdparty/md5/md5.h"
00175 #include "../tar_type.h"
00176
00178 struct ScriptFileChecksumCreator : FileScanner {
00179 byte md5sum[16];
00180 Subdirectory dir;
00181
00186 ScriptFileChecksumCreator(Subdirectory dir)
00187 {
00188 this->dir = dir;
00189 memset(this->md5sum, 0, sizeof(this->md5sum));
00190 }
00191
00192
00193 virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
00194 {
00195 Md5 checksum;
00196 uint8 buffer[1024];
00197 size_t len, size;
00198 byte tmp_md5sum[16];
00199
00200
00201 FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
00202 if (f == NULL) return false;
00203
00204
00205 while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
00206 size -= len;
00207 checksum.Append(buffer, len);
00208 }
00209 checksum.Finish(tmp_md5sum);
00210
00211 FioFCloseFile(f);
00212
00213
00214 for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i];
00215
00216 return true;
00217 }
00218 };
00219
00228 static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir)
00229 {
00230 uint32 id = 0;
00231 const char *str = info->GetShortName();
00232 for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j);
00233
00234 if (id != ci->unique_id) return false;
00235 if (!md5sum) return true;
00236
00237 ScriptFileChecksumCreator checksum(dir);
00238 const char *tar_filename = info->GetTarFile();
00239 TarList::iterator iter;
00240 if (tar_filename != NULL && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) {
00241
00242
00243 TarFileList::iterator tar;
00244 FOR_ALL_TARS(tar, dir) {
00245
00246 if (tar->second.tar_filename != iter->first) continue;
00247
00248
00249 const char *ext = strrchr(tar->first.c_str(), '.');
00250 if (ext == NULL || strcasecmp(ext, ".nut") != 0) continue;
00251
00252 checksum.AddFile(tar->first.c_str(), 0, tar_filename);
00253 }
00254 } else {
00255 char path[MAX_PATH];
00256 strecpy(path, info->GetMainScript(), lastof(path));
00257
00258
00259
00260 *strrchr(path, PATHSEPCHAR) = '\0';
00261 checksum.Scan(".nut", path);
00262 }
00263
00264 return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0;
00265 }
00266
00267 bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum)
00268 {
00269 for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) {
00270 if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return true;
00271 }
00272 return false;
00273 }
00274
00275 const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum)
00276 {
00277 for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) {
00278 if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return (*it).second->GetMainScript();
00279 }
00280 return NULL;
00281 }
00282
00283 #endif