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