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 <sys/stat.h>
00017
00018 #include "../script/squirrel.hpp"
00019 #include "script_scanner.hpp"
00020 #include "script_info.hpp"
00021
00022 bool ScriptScanner::AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
00023 {
00024 free(this->main_script);
00025 this->main_script = strdup(filename);
00026 if (this->main_script == NULL) return false;
00027
00028 free(this->tar_file);
00029 if (tar_filename != NULL) {
00030 this->tar_file = strdup(tar_filename);
00031 if (this->tar_file == NULL) return false;
00032 } else {
00033 this->tar_file = NULL;
00034 }
00035
00036 const char *end = this->main_script + strlen(this->main_script) + 1;
00037 char *p = strrchr(this->main_script, PATHSEPCHAR);
00038 if (p == NULL) {
00039 p = this->main_script;
00040 } else {
00041
00042 p++;
00043 }
00044
00045 strecpy(p, "main.nut", end);
00046
00047 if (!FioCheckFileExists(filename, this->subdir) || !FioCheckFileExists(this->main_script, this->subdir)) return false;
00048
00049
00050 this->engine->ResetCrashed();
00051 this->engine->LoadScript(filename);
00052 return true;
00053 }
00054
00055 ScriptScanner::ScriptScanner() :
00056 engine(NULL),
00057 main_script(NULL),
00058 tar_file(NULL)
00059 {
00060 }
00061
00062 void ScriptScanner::Initialize(const char *name)
00063 {
00064 this->engine = new Squirrel(name);
00065
00066
00067 this->engine->SetGlobalPointer(this);
00068
00069 this->RegisterAPI(this->engine);
00070 this->RescanDir();
00071
00072 this->engine->ResetCrashed();
00073 }
00074
00075 ScriptScanner::~ScriptScanner()
00076 {
00077 this->Reset();
00078
00079 free(this->main_script);
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
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 char *ScriptScanner::GetConsoleList(char *p, const char *last, bool newest_only) const
00157 {
00158 p += seprintf(p, last, "List of %s:\n", this->GetScannerName());
00159 const ScriptInfoList &list = newest_only ? this->info_single_list : this->info_list;
00160 ScriptInfoList::const_iterator it = list.begin();
00161 for (; it != list.end(); it++) {
00162 ScriptInfo *i = (*it).second;
00163 p += seprintf(p, last, "%10s (v%d): %s\n", i->GetName(), i->GetVersion(), i->GetDescription());
00164 }
00165 p += seprintf(p, last, "\n");
00166
00167 return p;
00168 }
00169
00170 #if defined(ENABLE_NETWORK)
00171 #include "../network/network_content.h"
00172 #include "../3rdparty/md5/md5.h"
00173 #include "../tar_type.h"
00174
00176 struct ScriptFileChecksumCreator : FileScanner {
00177 byte md5sum[16];
00178 Subdirectory dir;
00179
00184 ScriptFileChecksumCreator(Subdirectory dir)
00185 {
00186 this->dir = dir;
00187 memset(this->md5sum, 0, sizeof(this->md5sum));
00188 }
00189
00190
00191 virtual bool AddFile(const char *filename, size_t basepath_length, const char *tar_filename)
00192 {
00193 Md5 checksum;
00194 uint8 buffer[1024];
00195 size_t len, size;
00196 byte tmp_md5sum[16];
00197
00198
00199 FILE *f = FioFOpenFile(filename, "rb", this->dir, &size);
00200 if (f == NULL) return false;
00201
00202
00203 while ((len = fread(buffer, 1, (size > sizeof(buffer)) ? sizeof(buffer) : size, f)) != 0 && size != 0) {
00204 size -= len;
00205 checksum.Append(buffer, len);
00206 }
00207 checksum.Finish(tmp_md5sum);
00208
00209 FioFCloseFile(f);
00210
00211
00212 for (uint i = 0; i < sizeof(md5sum); i++) this->md5sum[i] ^= tmp_md5sum[i];
00213
00214 return true;
00215 }
00216 };
00217
00226 static bool IsSameScript(const ContentInfo *ci, bool md5sum, ScriptInfo *info, Subdirectory dir)
00227 {
00228 uint32 id = 0;
00229 const char *str = info->GetShortName();
00230 for (int j = 0; j < 4 && *str != '\0'; j++, str++) id |= *str << (8 * j);
00231
00232 if (id != ci->unique_id) return false;
00233 if (!md5sum) return true;
00234
00235 ScriptFileChecksumCreator checksum(dir);
00236 const char *tar_filename = info->GetTarFile();
00237 TarList::iterator iter;
00238 if (tar_filename != NULL && (iter = _tar_list[dir].find(tar_filename)) != _tar_list[dir].end()) {
00239
00240
00241 TarFileList::iterator tar;
00242 FOR_ALL_TARS(tar, dir) {
00243
00244 if (tar->second.tar_filename != iter->first) continue;
00245
00246
00247 const char *ext = strrchr(tar->first.c_str(), '.');
00248 if (ext == NULL || strcasecmp(ext, ".nut") != 0) continue;
00249
00250 checksum.AddFile(tar->first.c_str(), 0, tar_filename);
00251 }
00252 } else {
00253 char path[MAX_PATH];
00254 strecpy(path, info->GetMainScript(), lastof(path));
00255
00256
00257
00258 *strrchr(path, PATHSEPCHAR) = '\0';
00259 checksum.Scan(".nut", path);
00260 }
00261
00262 return memcmp(ci->md5sum, checksum.md5sum, sizeof(ci->md5sum)) == 0;
00263 }
00264
00265 bool ScriptScanner::HasScript(const ContentInfo *ci, bool md5sum)
00266 {
00267 for (ScriptInfoList::iterator it = this->info_list.begin(); it != this->info_list.end(); it++) {
00268 if (IsSameScript(ci, md5sum, (*it).second, this->GetDirectory())) return true;
00269 }
00270 return false;
00271 }
00272
00273 #endif