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 delete this->engine;
00080 }
00081
00082 void ScriptScanner::RescanDir()
00083 {
00084
00085 this->Reset();
00086
00087
00088 this->Scan(this->GetFileName(), this->GetDirectory());
00089 }
00090
00091 void ScriptScanner::Reset()
00092 {
00093 ScriptInfoList::iterator it = this->info_list.begin();
00094 for (; it != this->info_list.end(); it++) {
00095 free((*it).first);
00096 delete (*it).second;
00097 }
00098 it = this->info_single_list.begin();
00099 for (; it != this->info_single_list.end(); it++) {
00100 free((*it).first);
00101 }
00102
00103 this->info_list.clear();
00104 this->info_single_list.clear();
00105 }
00106
00107 void ScriptScanner::RegisterScript(ScriptInfo *info)
00108 {
00109 char script_original_name[1024];
00110 this->GetScriptName(info, script_original_name, sizeof(script_original_name));
00111 strtolower(script_original_name);
00112
00113 char script_name[1024];
00114 snprintf(script_name, sizeof(script_name), "%s.%d", script_original_name, info->GetVersion());
00115
00116
00117 if (strlen(info->GetShortName()) != 4) {
00118 DEBUG(script, 0, "The script '%s' returned a string from GetShortName() which is not four characaters. Unable to load the script.", info->GetName());
00119 delete info;
00120 return;
00121 }
00122
00123 if (this->info_list.find(script_name) != this->info_list.end()) {
00124
00125 #ifdef WIN32
00126
00127 if (strcasecmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
00128 #else
00129 if (strcmp(this->info_list[script_name]->GetMainScript(), info->GetMainScript()) == 0) {
00130 #endif
00131 delete info;
00132 return;
00133 }
00134
00135 DEBUG(script, 1, "Registering two scripts with the same name and version");
00136 DEBUG(script, 1, " 1: %s", this->info_list[script_name]->GetMainScript());
00137 DEBUG(script, 1, " 2: %s", info->GetMainScript());
00138 DEBUG(script, 1, "The first is taking precedence.");
00139
00140 delete info;
00141 return;
00142 }
00143
00144 this->info_list[strdup(script_name)] = info;
00145
00146 if (!info->IsDeveloperOnly() || _settings_client.gui.ai_developer_tools) {
00147
00148
00149 if (this->info_single_list.find(script_original_name) == this->info_single_list.end()) {
00150 this->info_single_list[strdup(script_original_name)] = info;
00151 } else if (this->info_single_list[script_original_name]->GetVersion() < info->GetVersion()) {
00152 this->info_single_list[script_original_name] = info;
00153 }
00154 }
00155 }
00156
00157 char *ScriptScanner::GetConsoleList(char *p, const char *last, bool newest_only) const
00158 {
00159 p += seprintf(p, last, "List of %s:\n", this->GetScannerName());
00160 const ScriptInfoList &list = newest_only ? this->info_single_list : this->info_list;
00161 ScriptInfoList::const_iterator it = list.begin();
00162 for (; it != list.end(); it++) {
00163 ScriptInfo *i = (*it).second;
00164 p += seprintf(p, last, "%10s (v%d): %s\n", i->GetName(), i->GetVersion(), i->GetDescription());
00165 }
00166 p += seprintf(p, last, "\n");
00167
00168 return p;
00169 }
00170
00171 #if defined(ENABLE_NETWORK)
00172 #include "../network/network_content.h"
00173 #include "../3rdparty/md5/md5.h"
00174 #include "../tar_type.h"
00175
00177 struct ScriptFileChecksumCreator : FileScanner {
00178 byte md5sum[16];
00179 Subdirectory dir;
00180
00185 ScriptFileChecksumCreator(Subdirectory dir)
00186 {
00187 this->dir = dir;
00188 memset(this->md5sum, 0, sizeof(this->md5sum));
00189 }
00190
00191
00192 virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
00193 {
00194 Md5 checksum;
00195 uint8 buffer[1024];
00196 size_t len, size;
00197 byte tmp_md5sum[16];
00198
00199
00200 FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
00201 if (f == NULL) return false;
00202
00203
00204 while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
00205 size -= len;
00206 checksum.Append(buffer, len);
00207 }
00208 checksum.Finish(tmp_md5sum);
00209
00210 FioFCloseFile(f);
00211
00212
00213 for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i];
00214
00215 return true;
00216 }
00217 };
00218
00227 static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir)
00228 {
00229 uint32 id = 0;
00230 const char *str = info->GetShortName();
00231 for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j);
00232
00233 if (id != ci->unique_id) return false;
00234 if (!md5sum) return true;
00235
00236 ScriptFileChecksumCreator checksum(dir);
00237 const char *tar_filename = info->GetTarFile();
00238 TarList::iterator iter;
00239 if (tar_filename != NULL && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) {
00240
00241
00242 TarFileList::iterator tar;
00243 FOR_ALL_TARS(tar, dir) {
00244
00245 if (tar->second.tar_filename != iter->first) continue;
00246
00247
00248 const char *ext = strrchr(tar->first.c_str(), '.');
00249 if (ext == NULL || strcasecmp(ext, ".nut") != 0) continue;
00250
00251 checksum.AddFile(tar->first.c_str(), 0, tar_filename);
00252 }
00253 } else {
00254 char path[MAX_PATH];
00255 strecpy(path, info->GetMainScript(), lastof(path));
00256
00257
00258
00259 *strrchr(path, PATHSEPCHAR) = '\0';
00260 checksum.Scan(".nut", path);
00261 }
00262
00263 return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0;
00264 }
00265
00266 bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum)
00267 {
00268 for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) {
00269 if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return true;
00270 }
00271 return false;
00272 }
00273
00274 const char *ScriptScanner::FindMainScript(const ContentInfo *ci, bool md5sum)
00275 {
00276 for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) {
00277 if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return (*it).second->GetMainScript();
00278 }
00279 return NULL;
00280 }
00281
00282 #endif