00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "global.hpp"
00016
00017 #include "config.hpp"
00018 #include "filesystem.hpp"
00019 #include "publish_campaign.hpp"
00020 #include "serialization/parser.hpp"
00021
00022 #include <algorithm>
00023 #include <cstring>
00024
00025 static const std::string& campaign_dir()
00026 {
00027 static const std::string res = get_user_data_dir() + "/data/campaigns";
00028 return res;
00029 }
00030
00031 static void setup_dirs()
00032 {
00033 make_directory(get_user_data_dir() + "/data");
00034 make_directory(campaign_dir());
00035 }
00036
00037 void get_campaign_info(const std::string& campaign_name, config& cfg)
00038 {
00039
00040 std::string exterior = campaign_dir() + "/" + campaign_name + ".pbl";
00041 std::string interior = campaign_dir() + "/" + campaign_name + "/_server.pbl";
00042 std::string pbl_file;
00043
00044 if (file_exists(exterior))
00045 pbl_file = exterior;
00046 else
00047 pbl_file = interior;
00048
00049 scoped_istream stream = istream_file(pbl_file);
00050 read(cfg, *stream);
00051 }
00052
00053 void set_campaign_info(const std::string& campaign_name, const config& cfg)
00054 {
00055 scoped_ostream stream = ostream_file(campaign_dir() + "/" + campaign_name + ".pbl");
00056 write(*stream, cfg);
00057 }
00058
00059 std::vector<std::string> available_campaigns()
00060 {
00061 std::vector<std::string> res;
00062
00063 std::vector<std::string> files, dirs;
00064 get_files_in_dir(campaign_dir(),&files,&dirs);
00065
00066 for(std::vector<std::string>::const_iterator i = dirs.begin(); i != dirs.end(); ++i) {
00067 const std::string external_cfg_file = *i + ".cfg";
00068 const std::string internal_cfg_file = *i + "/_main.cfg";
00069 const std::string external_pbl_file = *i + ".pbl";
00070 const std::string internal_pbl_file = *i + "/_server.pbl";
00071 if((std::find(files.begin(),files.end(),external_cfg_file) != files.end() || file_exists(campaign_dir() + "/" + internal_cfg_file)) &&
00072 (std::find(files.begin(),files.end(),external_pbl_file) != files.end() || (file_exists(campaign_dir() + "/" + internal_pbl_file)))) {
00073 res.push_back(*i);
00074 }
00075 }
00076
00077 return res;
00078 }
00079
00080
00081 std::vector<std::string> installed_campaigns()
00082 {
00083 std::vector<std::string> res;
00084
00085 std::vector<std::string> files, dirs;
00086 get_files_in_dir(campaign_dir(),&files,&dirs);
00087
00088 for(std::vector<std::string>::const_iterator i = dirs.begin(); i != dirs.end(); ++i) {
00089 const std::string external_cfg_file = *i + ".cfg";
00090 const std::string internal_cfg_file = *i + "/_main.cfg";
00091 if(std::find(files.begin(),files.end(),external_cfg_file) != files.end() || file_exists(campaign_dir() + "/" + internal_cfg_file)) {
00092 res.push_back(*i);
00093 }
00094 }
00095
00096 return res;
00097 }
00098
00099
00100 std::vector<config *> find_scripts(const config &cfg, std::string extension)
00101 {
00102 std::vector<config *> python_scripts;
00103 const config::child_list& dirs = cfg.get_children("dir");
00104 config::child_list::const_iterator i;
00105 for(i = dirs.begin(); i != dirs.end(); ++i) {
00106 const config::child_list& files = (**i).get_children("file");
00107 config::child_list::const_iterator j;
00108 for(j = files.begin(); j != files.end(); ++j) {
00109 std::string filename = (**j)["name"].str();
00110 if (filename.length() > extension.length()) {
00111 if (filename.substr(filename.length() - extension.length()) ==
00112 extension) {
00113 python_scripts.push_back(*j);
00114 }
00115 }
00116 }
00117
00118 std::vector<config *> childs = find_scripts(**i, extension);
00119 python_scripts.insert(python_scripts.end(),
00120 childs.begin(), childs.end());
00121 }
00122 return python_scripts;
00123 }
00124
00125 namespace {
00126
00127 const char escape_char = 1;
00128
00129 }
00130
00131 static bool needs_escaping(char c) { return c == 0 || c == escape_char; }
00132
00133 static std::string encode_binary(const std::string& str)
00134 {
00135 std::string res;
00136 res.resize(str.size());
00137 size_t n = 0;
00138 for(std::string::const_iterator j = str.begin(); j != str.end(); ++j) {
00139 if(needs_escaping(*j)) {
00140 res.resize(res.size()+1);
00141 res[n++] = escape_char;
00142 res[n++] = *j + 1;
00143 } else {
00144 res[n++] = *j;
00145 }
00146 }
00147
00148 return res;
00149 }
00150
00151 static std::string unencode_binary(const std::string& str)
00152 {
00153 std::string res;
00154 res.resize(str.size());
00155
00156 size_t n = 0;
00157 for(std::string::const_iterator j = str.begin(); j != str.end(); ++j) {
00158 if(*j == escape_char && j+1 != str.end()) {
00159 ++j;
00160 res[n++] = *j - 1;
00161 res.resize(res.size()-1);
00162 } else {
00163 res[n++] = *j;
00164 }
00165 }
00166
00167 return res;
00168 }
00169
00170 static std::pair<std::vector<std::string>, std::vector<std::string> > read_ignore_patterns(const std::string& campaign_name) {
00171 std::pair<std::vector<std::string>, std::vector<std::string> > patterns;
00172 std::string exterior = campaign_dir() + "/" + campaign_name + ".ign";
00173 std::string interior = campaign_dir() + "/" + campaign_name + "/_server.ign";
00174 std::string ign_file;
00175 if (file_exists(interior)) {
00176 ign_file = interior;
00177 } else if (file_exists(exterior)) {
00178 ign_file = exterior;
00179 } else {
00180 patterns.first.push_back("*~");
00181 patterns.first.push_back("*-bak");
00182 patterns.first.push_back("*.pbl");
00183 patterns.first.push_back("*.ign");
00184
00185
00186
00187
00188
00189
00190 patterns.first.push_back("*.exe");
00191 patterns.first.push_back("*.bat");
00192 patterns.first.push_back("*.com");
00193 patterns.first.push_back("*.scr");
00194 patterns.first.push_back("*.sh");
00195 return patterns;
00196 }
00197 std::istream *stream = istream_file(ign_file);
00198 std::string line;
00199 while (std::getline(*stream, line)) {
00200 size_t l = line.size();
00201 if (line[l - 1] == '/') {
00202 patterns.second.push_back(line.substr(0, l - 1));
00203 } else {
00204 patterns.first.push_back(line);
00205 }
00206 }
00207 return patterns;
00208 }
00209
00210 static void archive_file(const std::string& path, const std::string& fname, config& cfg)
00211 {
00212 cfg["name"] = fname;
00213 cfg["contents"] = encode_binary(read_file(path + '/' + fname));
00214 }
00215
00216 static void archive_dir(const std::string& path, const std::string& dirname, config& cfg, std::pair<std::vector<std::string>, std::vector<std::string> >& ignore_patterns)
00217 {
00218 cfg["name"] = dirname;
00219 const std::string dir = path + '/' + dirname;
00220
00221 std::vector<std::string> files, dirs;
00222 get_files_in_dir(dir,&files,&dirs);
00223 for(std::vector<std::string>::const_iterator i = files.begin(); i != files.end(); ++i) {
00224 bool valid = true;
00225 for(std::vector<std::string>::const_iterator p = ignore_patterns.first.begin(); p != ignore_patterns.first.end(); ++p) {
00226 if (utils::wildcard_string_match(*i, *p)) {
00227 valid = false;
00228 break;
00229 }
00230 }
00231 if (valid) {
00232 archive_file(dir,*i,cfg.add_child("file"));
00233 }
00234 }
00235
00236 for(std::vector<std::string>::const_iterator j = dirs.begin(); j != dirs.end(); ++j) {
00237 bool valid = true;
00238 for(std::vector<std::string>::const_iterator p = ignore_patterns.second.begin(); p != ignore_patterns.second.end(); ++p) {
00239 if (utils::wildcard_string_match(*j, *p)) {
00240 valid = false;
00241 break;
00242 }
00243 }
00244 if (valid) {
00245 archive_dir(dir,*j,cfg.add_child("dir"),ignore_patterns);
00246 }
00247 }
00248 }
00249
00250 void archive_campaign(const std::string& campaign_name, config& cfg)
00251 {
00252 std::pair<std::vector<std::string>, std::vector<std::string> > ignore_patterns;
00253
00254 std::string external_cfg = campaign_name + ".cfg";
00255 if (file_exists(campaign_dir() + "/" + external_cfg))
00256 archive_file(campaign_dir(), external_cfg,cfg.add_child("file"));
00257 ignore_patterns = read_ignore_patterns(campaign_name);
00258 archive_dir(campaign_dir(),campaign_name,cfg.add_child("dir"),ignore_patterns);
00259 }
00260
00261 static void unarchive_file(const std::string& path, const config& cfg)
00262 {
00263 write_file(path + '/' + cfg["name"].str(), unencode_binary(cfg["contents"]));
00264 }
00265
00266 static void unarchive_dir(const std::string& path, const config& cfg)
00267 {
00268 std::string dir;
00269 if (cfg["name"].empty())
00270 dir = path;
00271 else
00272 dir = path + '/' + cfg["name"].str();
00273
00274 make_directory(dir);
00275
00276 const config::child_list& dirs = cfg.get_children("dir");
00277 for(config::child_list::const_iterator i = dirs.begin(); i != dirs.end(); ++i) {
00278 unarchive_dir(dir,**i);
00279 }
00280
00281 const config::child_list& files = cfg.get_children("file");
00282 for(config::child_list::const_iterator j = files.begin(); j != files.end(); ++j) {
00283 unarchive_file(dir,**j);
00284 }
00285 }
00286
00287 void unarchive_campaign(const config& cfg)
00288 {
00289 setup_dirs();
00290 unarchive_dir(campaign_dir(),cfg);
00291 }
00292
00293 static bool two_dots(char a, char b) { return a == '.' && b == '.'; }
00294
00295 bool campaign_name_legal(const std::string& name)
00296 {
00297 if(name == "" || strlen(name.c_str()) == 0 || name == "." ||
00298 std::find(name.begin(),name.end(),'/') != name.end() ||
00299 std::find(name.begin(),name.end(),'\\') != name.end() ||
00300 std::find(name.begin(),name.end(),':') != name.end() ||
00301 std::adjacent_find(name.begin(),name.end(),two_dots) != name.end()) {
00302 return false;
00303 } else {
00304 return true;
00305 }
00306 }
00307
00308 bool check_names_legal(const config& dir)
00309 {
00310 const config::child_list& files = dir.get_children("file");
00311 for(config::child_list::const_iterator i = files.begin(); i != files.end(); ++i) {
00312 if (!campaign_name_legal((**i)["name"])) return false;
00313 }
00314 const config::child_list& dirs = dir.get_children("dir");
00315 {
00316 for(config::child_list::const_iterator i = dirs.begin(); i != dirs.end(); ++i) {
00317 if (!campaign_name_legal((**i)["name"])) return false;
00318 if (!check_names_legal(**i)) return false;
00319 }
00320 }
00321 return true;
00322 }