source: AE/Installer/trunk/source/installer.cpp@ 558

Last change on this file since 558 was 558, checked in by gumby, 15 years ago

fix for addon files not replacing bsl files if they exist

File size: 66.7 KB
Line 
1/***************************************************************************\
2| Project: AE Installer |
3| By: Gumby & Iritscen |
4| File: Installer.cpp |
5| Function: Contains the real meat of the installation process. Mm, beefy. |
6| Created: 24/05/2009 19:39:00 |
7\***************************************************************************/
8
9// TODO: Load credits from text resource file
10// TODO: Clear mod info fields when mod is de-selected
11
12//#define DEBUG
13#ifdef WIN32
14//#include <windows.h>
15#define popen _popen
16#endif
17#include "boost/date_time/gregorian/gregorian.hpp"
18#include "boost/date_time/date_parsing.hpp"
19#include "boost/date_time/posix_time/posix_time.hpp"
20#include <boost/algorithm/string.hpp>
21#include "installer.h"
22#include "aeinstallerapp.h"
23
24using namespace boost::gregorian;
25using namespace boost::posix_time;
26
27// externs declared in installer.h
28string strInstallCfg = "../GameDataFolder/Add.cfg";
29string strEUFN = "Edition"; // GetUpdateStatus() may set this to "Edition-patch" later, but this is the assumed name of the new Edition folder in Updates/
30extern MainWindow* TheWindow;
31
32int globalizeData(void)
33{
34 busy = 1;
35 using boost::lexical_cast;
36 using boost::bad_lexical_cast;
37 using namespace boost::gregorian;
38 using namespace boost::posix_time;
39 ptime start_time(second_clock::local_time());
40
41 setStatusArea("Globalizing!");
42 int err = 0;
43 int parts_done = 0;
44 remove("Globalize.log");
45 ofstream logfile("Globalize.log");
46 logfile << "Globalization started " << to_simple_string(start_time) << endl;
47
48 try { // the levels Oni has...probably should have made a string array. Oops.
49 char levels_cstr[15][3] = {"0", "1", "2", "3", "4", "6", "8", "9", "10", "11", "12", "13", "14", "18", "19"};
50 vector<string> levels;
51 for (int f = 0; f < 15; f++) {
52 levels.push_back(levels_cstr[f]);
53 }
54
55 path Characters = "../GameDataFolder/level0_Characters";
56 path Particles = "../GameDataFolder/level0_Particles";
57 path Archive = "../GameDataFolder/Archive";
58 path Textures = "../GameDataFolder/level0_Textures";
59 path Sounds = "../GameDataFolder/level0_Sounds";
60 path Animations = "../GameDataFolder/level0_Animations";
61 path TRAC = Animations / "level0_TRAC";
62 path TRAM = Animations / "level0_TRAM";
63
64 vector<path> GDFPaths;
65 GDFPaths.push_back(Particles);
66 GDFPaths.push_back(Textures);
67 GDFPaths.push_back(Sounds);
68 GDFPaths.push_back(TRAC);
69 GDFPaths.push_back(TRAM);
70
71 path VanillaCharacters = "VanillaDats/level0_Final/level0_Characters/level0_Characters.oni";
72 path VanillaParticles = "VanillaDats/level0_Final/level0_Particles/level0_Particles.oni";
73 path VanillaTextures = "VanillaDats/level0_Final/level0_Textures/level0_Textures.oni";
74 path VanillaSounds = "VanillaDats/level0_Final/level0_Sounds/level0_Sounds.oni";
75 path VanillaAnimations = "VanillaDats/level0_Final/level0_Animations/level0_Animations.oni";
76 path VanillaTRAC = "VanillaDats/level0_Final/level0_Animations/level0_TRAC.oni";
77 path VanillaTRAM = "VanillaDats/level0_Final/level0_Animations/level0_TRAM.oni";
78
79 vector<path> VanillaPaths;
80
81 VanillaPaths.push_back(VanillaParticles);
82 VanillaPaths.push_back(VanillaTextures);
83 VanillaPaths.push_back(VanillaSounds);
84 VanillaPaths.push_back(VanillaTRAC);
85 VanillaPaths.push_back(VanillaTRAM);
86
87 setStatusArea("Removing old GameDataFolder...\n");
88 logfile << "Removing old GameDataFolder...\n";
89 remove_all( "../GameDataFolder/" );
90 setStatusArea("Creating needed directories...");
91 logfile << "Creating needed directories...\n";
92 create_directory( "../GameDataFolder/" );
93
94 create_directory( "packages" );
95
96 if (exists("VanillaDats")) remove_all("VanillaDats");
97 create_directory( "VanillaDats" );
98 create_directory( "VanillaDats/level0_Final/" );
99 create_directory( Characters );
100 create_directory( Particles );
101 create_directory( Archive );
102 create_directory( Textures );
103 create_directory( Sounds );
104 create_directory( Animations );
105 create_directory( TRAC );
106 create_directory( TRAM );
107 int num_levels = 0;
108 for(int i = 1; i < 15; i++)
109 {
110 if (exists("../../GameDataFolder/level" + levels[i] + "_Final.dat")) {
111 num_levels++;
112
113 }
114 }
115 logfile << "Exporting and moving...\n\n";
116 int total_steps = 8 + 2 * num_levels;
117
118 for(int i = 0; i < 15; i++)
119 {
120 if (exists("../../GameDataFolder/level" + levels[i] + "_Final.dat")) {
121 logfile << "level" << levels[i] << "_Final\n";
122 logfile << "\tExporting level" << levels[i] << "_Final.dat\n";
123 setStatusArea("Step " + lexical_cast<std::string>(parts_done + 1) + "/" + lexical_cast<std::string>(total_steps) + " exporting level" + levels[i]+"_Final.dat");
124 create_directory( "../GameDataFolder/level" + levels[i] + "_Final" );
125 system((strOniSplit + " -export ../GameDataFolder/level" + levels[i] + "_Final ../../GameDataFolder/level" + levels[i] + "_Final.dat").c_str());
126 create_directory( "VanillaDats/level" + levels[i] + "_Final" );
127 create_directory( "VanillaDats/level" + levels[i] + "_Final/level" + levels[i] + "_Final" );
128
129 //Moves the AKEV and other files into a safe directory so that level specific textures are not globalized...
130 if ( strcmp(levels[i].c_str(), "0") ){
131 create_directory( "../GameDataFolder/level" + levels[i] + "_Final/AKEV" );
132 system((strOniSplit + " -move:overwrite ../GameDataFolder/level" + levels[i] + "_Final/AKEV ../GameDataFolder/level" + levels[i] + "_Final/AKEV*.oni").c_str());
133
134 }
135
136 directory_iterator end_iter;
137 for ( directory_iterator dir_itr( "../GameDataFolder/level" + levels[i] + "_Final" ); dir_itr != end_iter; ++dir_itr )
138 {
139 if ( is_regular_file( dir_itr->status() ) )
140 {
141 if ( dir_itr->path().filename().substr(0,8) == "TXMPfail" ||
142 dir_itr->path().filename().substr(0,9) == "TXMPlevel" ||
143 ( dir_itr->path().filename().substr(0,4) == "TXMP" && dir_itr->path().filename().find("intro")!=string::npos) ||
144 dir_itr->path().filename().substr(0,4) == "TXMB" ||
145 dir_itr->path().filename() == "M3GMpowerup_lsi.oni" ||
146 dir_itr->path().filename() == "TXMPlsi_icon.oni" ||
147 ( dir_itr->path().filename().substr(0,4) == "TXMB" && dir_itr->path().filename().find("splash_screen.oni")!=string::npos) )
148 {
149 cout <<dir_itr->path().filename() << "\n";
150 create_directory( dir_itr->path().parent_path() / "NoGlobal");
151 if(!exists( dir_itr->path().parent_path() / "NoGlobal" / dir_itr->filename())) rename(dir_itr->path(), dir_itr->path().parent_path() / "NoGlobal" /
152 dir_itr->filename());
153 else remove(dir_itr->path());
154 }
155 else if (dir_itr->path().filename().substr(0,4) == "TRAC"
156 ) {
157 cout <<dir_itr->path().filename() << "\n";
158 if(!exists( TRAC / dir_itr->filename())) rename(dir_itr->path(), TRAC / dir_itr->filename());
159 else remove(dir_itr->path());
160 }
161 else if (dir_itr->path().filename().substr(0,4) == "TRAM") {
162 cout <<dir_itr->path().filename() << "\n";
163 if(!exists( TRAM / dir_itr->filename())) rename(dir_itr->path(), TRAM / dir_itr->filename());
164 else remove(dir_itr->path());
165 }
166 else if (dir_itr->path().filename().substr(0,4) == "ONSK" ||
167 dir_itr->path().filename().substr(0,4) == "TXMP") {
168 cout <<dir_itr->path().filename() << "\n";\
169 create_directory( dir_itr->path().parent_path() / "TexFix");
170 if(!exists( Textures / dir_itr->filename())) rename(dir_itr->path(), Textures / dir_itr->filename());
171 }
172 else if (dir_itr->path().filename().substr(0,4) == "ONCC"
173 || dir_itr->path().filename().substr(0,4) == "TRBS"
174 || dir_itr->path().filename().substr(0,4) == "ONCV"
175 || dir_itr->path().filename().substr(0,4) == "ONVL"
176 || dir_itr->path().filename().substr(0,4) == "TRMA"
177 || dir_itr->path().filename().substr(0,4) == "TRSC"
178 || dir_itr->path().filename().substr(0,4) == "TRAS") {
179 cout <<dir_itr->path().filename() << "\n";
180 if(!exists( Characters / dir_itr->filename())) rename(dir_itr->path(), Characters / dir_itr->filename());
181 else remove(dir_itr->path());
182 }
183 else if (dir_itr->path().filename().substr(0,4) == "OSBD"
184 || dir_itr->path().filename().substr(0,4) == "SNDD") {
185 cout << dir_itr->path().filename() << "\n";
186 if(!exists( Sounds / dir_itr->filename())) rename(dir_itr->path(), Sounds / dir_itr->filename());
187 else remove(dir_itr->path());
188 }
189 else if (dir_itr->path().filename().substr(0,5) == "BINA3"
190 || dir_itr->path().filename().substr(0,10) == "M3GMdebris"
191 || dir_itr->path().filename() == "M3GMtoxic_bubble.oni"
192 || dir_itr->path().filename().substr(0,8) == "M3GMelec"
193 || dir_itr->path().filename().substr(0,7) == "M3GMrat"
194 || dir_itr->path().filename().substr(0,7) == "M3GMjet"
195 || dir_itr->path().filename().substr(0,9) == "M3GMbomb_"
196 || dir_itr->path().filename() == "M3GMbarab_swave.oni"
197 || dir_itr->path().filename() == "M3GMbloodyfoot.oni"
198 ){
199 cout <<dir_itr->path().filename() << "\n";
200 if(!exists( Particles / dir_itr->filename())) rename(dir_itr->path(), Particles / dir_itr->filename());
201 else remove(dir_itr->path());
202 }
203 else if (dir_itr->path().filename().substr(0,4) == "AGDB"
204 || dir_itr->path().filename().substr(0,4) == "TRCM") {
205 cout <<dir_itr->path().filename() << "\n";
206
207 if(!exists( Archive / dir_itr->filename())) rename(dir_itr->path(), Archive / dir_itr->filename());
208 else remove(dir_itr->path());
209 }
210 else if (dir_itr->path().filename().substr(0,4) == "ONWC") { //fix for buggy ONWC overriding
211 cout <<dir_itr->path().filename() << "\n";
212
213 if(!exists( "VanillaDats/level0_Final/level0_Final/" + dir_itr->filename()))
214 rename(dir_itr->path(), "VanillaDats/level0_Final/level0_Final/" + dir_itr->filename());
215 else remove(dir_itr->path());
216 }
217
218 if (exists(dir_itr->path())) {
219
220 }
221 else {
222 //logfile << "\tMoved file: " << dir_itr->path().filename() << "\n";
223 }
224 }
225
226
227
228 }
229
230 logfile << "\tCleaning up TXMPs...\n";
231 system( (strOniSplit + " -move:delete " + Textures.string() + " ../GameDataFolder/level" + levels[i] + "_Final/TXMP*.oni").c_str());
232
233
234 if ( strcmp(levels[i].c_str(), "0") ){
235 system((strOniSplit + " -move:overwrite ../GameDataFolder/level" + levels[i] + "_Final ../GameDataFolder/level" + levels[i] +
236 "_Final/AKEV/AKEV*.oni").c_str());
237 remove( "../GameDataFolder/level" + levels[i] + "_Final/AKEV" );
238 }
239
240 parts_done++;
241
242 setProgressBar( (int)(1000 * (float)(parts_done) / (float)(total_steps) ));
243
244 }
245 }
246 logfile << "Reimporting levels\n";
247 for (int i = 0; i < 15; i++)
248 {
249 logfile << "\tReimporting level" << levels[i] << "_Final.oni\n";
250 setStatusArea("Step " + lexical_cast<std::string>(parts_done + 1) + "/" + lexical_cast<std::string>(total_steps) + " reimporting level" +
251 levels[i] + "_Final.oni");
252 logfile << (strOniSplit + " " + strImportOption + " ../GameDataFolder/level" + levels[i] + "_Final VanillaDats/level" + levels[i] + "_Final/level"
253 + levels[i] + "_Final/level" + levels[i] + "_Final.oni >> Globalize.log").c_str() << '\n';
254 string sys_str = (strOniSplit + " " + strImportOption + " ../GameDataFolder/level" + levels[i] + "_Final VanillaDats/level" + levels[i] + "_Final/level"
255 + levels[i] + "_Final/level" + levels[i] + "_Final.oni");
256 system(sys_str.c_str() );
257 setProgressBar( (int)(1000 * (float)(parts_done) / (float)(total_steps) ));
258 parts_done++;
259 }
260 create_directory( VanillaParticles.parent_path() );
261 create_directory( VanillaTextures.parent_path() );
262 create_directory( VanillaSounds.parent_path() );
263 create_directory( VanillaAnimations.remove_filename() );
264
265 for(unsigned int j = 0; j < GDFPaths.size(); j++) {
266 logfile << "\tReimporting " << GDFPaths[j].filename() << ".oni\n";
267 setStatusArea("Step " + lexical_cast<std::string>(parts_done + 1) + "/" + lexical_cast<std::string>(total_steps) + ": reimporting " + GDFPaths[j].filename() );
268 system((strOniSplit + " " + strImportOption + " " + GDFPaths[j].string() + " " + VanillaPaths[j].string()).c_str());
269 parts_done++;
270 setProgressBar( (int)(1000 * (float)(parts_done) / (float)(total_steps) ));
271 }
272 logfile << "\nMoving level0_Characters\n";
273 setStatusArea("Step " + lexical_cast<std::string>(parts_done + 1) + "/" + lexical_cast<std::string>(total_steps) + ": moving level0_Characters" );
274 copy((path)"../GameDataFolder/level0_Characters", (path)("VanillaDats/level0_Final"));
275 GDFPaths.push_back( Characters );
276 //concactates level0....
277 for(int i = 0; i < GDFPaths.size(); i++)
278 {
279 directory_iterator end_iter;
280 for ( directory_iterator dir_itr( GDFPaths[i] ); dir_itr != end_iter; ++dir_itr )
281 {
282 try
283 {
284 rename(dir_itr->path(), "../GameDataFolder/level0_Final/" + dir_itr->path().filename() );
285 }
286 catch(exception &ex) {
287
288 }
289 }
290 }
291 //?: syntax is fun.
292 //condition ? value_if_true : value_if_false
293 (is_empty(Characters) ? remove( Characters ) : 1);
294 (is_empty(Particles) ? remove( Particles ) : 1);
295 (is_empty(Textures) ? remove( Textures ) : 1);
296 (is_empty(Sounds) ? remove( Sounds ) : 1);
297 (is_empty(TRAC) ? remove( TRAC ) : 1);
298 (is_empty(TRAM) ? remove( TRAM ) : 1);
299 (is_empty(Animations) ? remove( Animations ) : 1);
300
301 create_directory((path)"../GameDataFolder/IGMD");
302 copy((path)"packages/VanillaBSL/IGMD", (path)"../GameDataFolder");
303 setProgressBar( 1000 );
304
305 if(exists("../../persist.dat") && !exists("../persist.dat")) copy("../../persist.dat","..");
306 if(exists("../../key_config.txt")&& !exists("../key_config.txt")) copy("../../key_config.txt","..");
307
308#ifndef WIN32
309 /* On Mac only, set the current GDF to the AE GDF by writing to Oni's global preferences file (thankfully a standard OS X ".plist" XML file).
310 Tests for presence of prefs with [ -f ] before doing anything so it doesn't create a partial prefs file -- just in case user has never
311 run Oni before :-p */
312 string fullAEpath = escapePath(system_complete(".").parent_path().parent_path().string()); // get full path for Edition/ (Oni wants folder that *contains* the GDF)
313 string prefsCommand = "[ -f ~/Library/Preferences/com.godgames.oni.plist ] && defaults write com.godgames.oni RetailInstallationPath -string '"
314 + fullAEpath + "'";
315 system(prefsCommand.c_str());
316
317#endif
318
319 setStatusArea((string)"Done! Now select your mod packages and click install.");
320 }
321 catch (exception & ex) {
322 setStatusArea("Warning, handled exception: " + (string)ex.what());
323 }
324
325 ptime end_time(second_clock::local_time());
326 time_period total_time (start_time, end_time);
327 logfile << "\n\nGlobalization ended " << to_simple_string(end_time) << "\nThe process took " << total_time.length();
328 logfile.close();
329 busy = 0;
330 return err;
331}
332
333vector<ModPackage> getPackages(string packageDir)
334{
335 vector<ModPackage> packages;
336 ModPackage package;
337 packages.reserve(256);
338 fstream file;
339 string filename = "\0";
340 string MODINFO_CFG = "Mod_Info.cfg";
341
342 try
343 {
344 for (directory_iterator dir_itr(packageDir), end_itr; dir_itr != end_itr; ++dir_itr)
345 {
346 file.open((dir_itr->path().string() + "/" + MODINFO_CFG).c_str());
347
348 if (!file.fail())
349 {
350 package = fileToModPackage(file, dir_itr->path().filename());
351 if (package.installerVersion.compare(INSTALLER_VERSION) < 1) // if mod requires newer version of the Installer, we won't add it to the list
352 {
353#ifdef WIN32
354 if (!package.platform.compare("Windows") || !package.platform.compare("Both")) // don't show package if it's not for the right OS
355#else
356 if (!package.platform.compare("Macintosh") || !package.platform.compare("Both"))
357#endif
358 packages.push_back(package);
359 }
360 }
361 file.close();
362 file.clear();
363 }
364 sort(packages.begin(), packages.end());
365 }
366 catch (const std::exception & ex)
367 {
368 cout << "Warning, something odd happened!\n";
369 }
370
371 return packages;
372}
373
374ModPackage fileToModPackage(fstream &file, string modName)
375{
376 ModPackage package;
377 string line;
378 const string AEInstallVersion = "AEInstallVersion"; // used for comparing to the current token...
379 const string NameOfMod = "NameOfMod";
380 const string ARROW = "->";
381 const string ModString = "ModString";
382 const string ModVersion = "ModVersion";
383 const string Platform = "Platform";
384 const string HasOnis = "HasOnis";
385 const string HasDeltas = "HasDeltas";
386 const string HasBSL = "HasBSL";
387 const string HasDats = "HasDats";
388 const string IsEngine = "IsEngine";
389 const string Readme = "Readme";
390 const string GlobalNeeded = "GlobalNeeded";
391 const string Category = "Category";
392 const string Creator = "Creator";
393 package.modStringName = modName;
394 while (!file.eof())
395 {
396 getline(file,line);
397 vector<string> tokens;
398 vector<string>::iterator iter;
399 tokenize(line, tokens);
400 if (tokens.capacity() >= 3)
401 {
402 iter = tokens.begin();
403
404 if (!AEInstallVersion.compare(*iter))
405 {
406 iter++; iter++;
407 package.installerVersion = *iter;
408 }
409 else if (!NameOfMod.compare(*iter))
410 {
411 for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++) // iterates through the words, ends if it reaches the end of the line or a "//" comment
412 {
413 if (ARROW.compare(*iter) && NameOfMod.compare(*iter)) // ignores "->" and "NameOfMod"
414 package.name += *iter + " ";
415 }
416 }
417 else if (!ModString.compare(*iter))
418 {
419 iter++; iter++;
420 //package.modStringName = *iter;
421 iter++;
422 package.modStringVersion = atof((*iter).c_str());
423 }
424 else if (!ModVersion.compare(*iter))
425 {
426 iter++; iter++;
427 package.modStringVersion = atof((*iter).c_str());
428 }
429 else if (!Platform.compare(*iter))
430 {
431 iter++; iter++;
432 package.platform = *iter;
433 }
434 else if (!HasOnis.compare(*iter))
435 {
436 iter++; iter++;
437 if (boost::iequals(*iter, "Yes")) package.hasOnis = 1;
438 }
439 else if (!HasBSL.compare(*iter))
440 {
441 iter++; iter++;
442 if (boost::iequals(*iter, "Yes")) package.hasBSL = true;
443 else if (boost::iequals(*iter, "Addon")) package.hasAddon = true;
444 }
445 else if (!HasDeltas.compare(*iter))
446 {
447 iter++; iter++;
448 if (toupper((*iter)[0]) == 'Y' && toupper((*iter)[1]) == 'E' && toupper((*iter)[2]) == 'S') package.hasDeltas = 1;
449 }
450 else if (!HasDats.compare(*iter))
451 {
452 iter++; iter++;
453 if (toupper((*iter)[0]) == 'Y' && toupper((*iter)[1]) == 'E' && toupper((*iter)[2]) == 'S') package.hasDats = 1;
454 }
455 else if (!IsEngine.compare(*iter))
456 {
457 iter++; iter++;
458 if (toupper((*iter)[0]) == 'Y' && toupper((*iter)[1]) == 'E' && toupper((*iter)[2]) == 'S') package.isEngine = 1;
459 }
460 else if (!GlobalNeeded.compare(*iter))
461 {
462 iter++; iter++;
463 if (toupper((*iter)[0]) == 'Y' && toupper((*iter)[1]) == 'E' && toupper((*iter)[2]) == 'S') package.globalNeeded = 1;
464 else if (toupper((*iter)[0]) == 'N' && toupper((*iter)[1]) == 'O') package.globalNeeded = 1; // only place where checking for "No" is important atm
465 }
466 else if (!Category.compare(*iter))
467 {
468 for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++)
469 {
470 if (ARROW.compare(*iter) && Category.compare(*iter)) // ignores "->" and "Category"
471 package.category += *iter + " ";
472 }
473 }
474 else if (!Creator.compare(*iter))
475 {
476 for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++)
477 {
478 if (ARROW.compare(*iter) && Creator.compare(*iter)) // ignores "->" and "Creator"
479 package.creator += *iter + " ";
480 }
481 }
482 else if (!Readme.compare(*iter))
483 {
484 for ( ; iter !=tokens.end() && SLASHSLASH.compare(*iter); iter++)
485 {
486 if (ARROW.compare(*iter) && Readme.compare(*iter)) // ignores "->" and "Readme"
487 {
488 if (!(*iter).compare("\\n")) package.readme += '\n';
489 else package.readme += *iter + " ";
490 }
491 }
492 }
493 }
494 }
495
496 return package;
497}
498
499void recompileAll(vector<string> installedMods)
500{try {
501 busy = 1;
502 using namespace boost::gregorian;
503 using namespace boost::posix_time;
504 using boost::lexical_cast;
505 using boost::bad_lexical_cast;
506 path vanilla_dir = "./VanillaDats/";
507 string importCommand = "";
508 int numberOfDats = 0;
509 int j = 1;
510 string datString;
511
512 setStatusArea("Importing levels...");
513
514 std::stringstream out;
515
516 ptime start_time(second_clock::local_time());
517 clearOldDats();
518
519 if(exists("Install.log")) remove("Install.log");
520 ofstream logfile("Install.log");
521 logfile << "Mod Installation started " << to_simple_string(start_time) << endl;
522 logfile.close();
523
524 if(splitInstances == true)
525 {
526 recursive_directory_iterator end_iter;
527
528 for ( recursive_directory_iterator dir_itr( vanilla_dir );
529 dir_itr != end_iter;
530 ++dir_itr )
531 {
532 try{
533 if ( is_directory( dir_itr->status() ) && dir_itr.level() == 1)
534 {
535 numberOfDats++;
536 }
537 }
538 catch(exception & ex) {
539 remove("Install.log");
540 ofstream logfile("Install.log");
541
542 logfile << "Warning, exception " << ex.what() << "!";
543 setStatusArea("Warning, exception " + (string)ex.what() + "!");
544 logfile.close();
545 }
546 }
547 try {
548 out << numberOfDats;
549 datString = out.str();
550 for ( recursive_directory_iterator dir_itr( vanilla_dir );
551 dir_itr != end_iter;
552 ++dir_itr )
553 {
554 try
555 {
556 if ( is_directory( dir_itr->status() ) && dir_itr.level() == 1)
557 {
558 importCommand = strOniSplit + " " + strImportOption + " " + dir_itr->path().parent_path().string() + '/' + dir_itr->path().filename();
559 for (unsigned int i = 0; i < installedMods.size(); ++i) {
560 if (exists("packages/" + installedMods[i] + "/oni/" + dir_itr->path().parent_path().filename() + '/' + dir_itr->path().filename() ))
561 importCommand += " packages/" + installedMods[i] + "/oni/" + dir_itr->path().parent_path().filename() + '/' + dir_itr->path().filename();
562 }
563 importCommand += " ../GameDataFolder/" + dir_itr->path().filename() + ".dat >> Install.log";
564
565
566 setProgressBar( (int)(1000 * (float)(j-1) / (float)numberOfDats) ); //100% * dat we're on / total dats
567 setStatusArea("Step " + lexical_cast<std::string>(j) + '/' + lexical_cast<std::string>(numberOfDats)+ ": Importing " +
568 dir_itr->path().filename() + " ");
569
570 system(importCommand.c_str());
571 j++;
572 }
573 }
574 catch ( const std::exception & ex )
575 {
576 remove("Install.log");
577 ofstream logfile("Install.log");
578 logfile << "Warning, exception " << ex.what() << "!";
579 setStatusArea("Warning, exception " + (string)ex.what() + "!");
580 logfile.close();
581 }
582 }
583 }
584 catch( const std::exception & ex ) {
585 remove("Install.log");
586 ofstream logfile("Install.log");
587 logfile << "Warning, exception " << ex.what() << "!";
588 setStatusArea("Warning, exception " + (string)ex.what() + "!");
589 logfile.close();
590 }
591 }
592 else if(splitInstances == false){
593 directory_iterator end_iter;
594
595
596 char levelnums[256] = {0};
597
598
599
600 for(int k = 0; k < 256; k++) {
601 if( exists( (path)("./VanillaDats/level" + lexical_cast<std::string>(k) + "_final/") ) ) {
602 levelnums[k] = 1;
603
604 }
605 }
606
607 for (int i = installedMods.size() - 1; i >= 0; i--) { //Iterates through the installed mods (backwards :P)
608 for (unsigned int j = 0; j < globalPackages.size(); ++j) { //looking in the global packages
609 if (globalPackages[j].modStringName == installedMods[i]) { //for a mod that has BSL in it
610 for(int k = 0; k < 256; k++) {
611 if( globalPackages[j].hasOnis &&
612 exists( (path)("packages/" + globalPackages[j].modStringName + "/oni/level" + lexical_cast<std::string>(k) + "_final/") ) ) {
613 levelnums[k] = 1;
614
615 }
616 }
617 }
618 }
619 }
620 for (int levelnum = 0; levelnum < 256; levelnum++)
621 if (levelnums[levelnum])
622 numberOfDats++;
623
624 out << numberOfDats;
625 datString = out.str();
626
627 for(int levelnum = 0; levelnum < 256; levelnum++) {
628 try
629 {
630 if ( levelnums[levelnum] )
631 {
632 importCommand = strOniSplit + " " + strImportOption + " " + vanilla_dir.string() + "level" + lexical_cast<std::string>(levelnum) + "_Final ";
633 for (unsigned int i = 0; i < installedMods.size(); ++i) {
634 if (exists((path)("packages/" + installedMods[i] + "/oni/level" + lexical_cast<std::string>(levelnum) + "_final") ))
635 importCommand += " packages/" + installedMods[i] + "/oni/level" + lexical_cast<std::string>(levelnum) + "_Final";
636 }
637 importCommand += " ../GameDataFolder/level" + lexical_cast<std::string>(levelnum) + "_Final.dat >> Install.log";
638
639 setProgressBar( (int)(1000 * (float)(j-1) / (float)numberOfDats) ); //100% * dat we're on / total dats
640 setStatusArea("Step " + lexical_cast<std::string>(j) + '/' + lexical_cast<std::string>(numberOfDats)+ ": Importing " +
641 "level" + lexical_cast<std::string>(levelnum) + "_Final"+ " ");
642 system(importCommand.c_str());
643 j++;
644 }
645 }
646 catch ( const std::exception & ex )
647 {
648 remove("Install.log");
649 ofstream logfile("Install.log");
650 logfile << "Warning, exception " << ex.what() << "!";
651 setStatusArea("Warning, exception " + (string)ex.what() + "!");
652 logfile.close();
653 }
654 }
655 }
656
657 vector<string> BSLfolders;
658 vector<string> skippedfolders;
659
660 ofstream BSLlog("BSL.log");
661 if(exists("../GameDataFolder/BSLBackup/")) {
662 remove_all("../GameDataFolder/BSLBackup/");
663 }
664 else {
665 create_directory("../GameDataFolder/BSLBackup/");
666 }
667 copy("../GameDataFolder/IGMD/", "../GameDataFolder/BSLBackup/");
668 for ( directory_iterator dir_itr( "../GameDataFolder/IGMD/" ), end_itr;
669 dir_itr != end_itr;
670 ++dir_itr ) {
671 if( exists(dir_itr->path().string() + "/ignore.txt") ){
672 BSLfolders.push_back(dir_itr->path().filename());
673 skippedfolders.push_back(dir_itr->path().filename());
674 }
675 }
676
677 for (int i = installedMods.size() - 1; i >= 0; i--) { //Iterates through the installed mods (backwards :P)
678 for (unsigned int j = 0; j < globalPackages.size(); ++j) { //looking in the global packages
679 if (globalPackages[j].modStringName == installedMods[i]) { //for a mod that has BSL in it
680 if(globalPackages[j].hasBSL) break; //skip non-BSL
681 if( exists( "packages/" + globalPackages[j].modStringName + "/BSL/" ) ) {
682 copyBSL("packages/" + globalPackages[j].modStringName + "/BSL", BSLfolders, globalPackages[j] );
683 BSLlog << "Copied " << globalPackages[j].modStringName << "!\n";
684 }
685 }
686 }
687 }
688
689
690
691 ModPackage emptyPackage;
692 emptyPackage.modStringName = "VanillaBSL";
693 emptyPackage.hasBSL = 1;
694 copyBSL("packages/VanillaBSL/IGMD", BSLfolders, emptyPackage);
695 BSLlog.close();
696
697 for (int i = installedMods.size() - 1; i >= 0; i--) { //Iterates through the installed mods (backwards :P)
698 for (unsigned int j = 0; j < globalPackages.size(); ++j) { //looking in the global packages
699 if (globalPackages[j].modStringName == installedMods[i]) { //for a mod that has BSL in it
700 if(!globalPackages[j].hasAddon) break; //skip non-BSL
701 if( exists( "packages/" + globalPackages[j].modStringName + "/BSL/" ) ) {
702 copyBSL("packages/" + globalPackages[j].modStringName + "/BSL", BSLfolders, globalPackages[j] );
703 BSLlog << "Copied " << globalPackages[j].modStringName << "!\n";
704 }
705 }
706 }
707 }
708
709 logfile << "Writing config file";
710 writeInstalledMods(installedMods);
711 setProgressBar(1000);
712
713 string finallyDone = "Done! You can now play Oni.";
714 setStatusArea(finallyDone);
715
716 ptime end_time(second_clock::local_time());
717 time_period total_time (start_time, end_time);
718 ofstream logfile2("Install.log", ios::app | ios::ate);
719 string outstring = (string)"\n\nGlobalization ended " + to_simple_string(end_time) + "\nThe process took ";// + (string)total_time.length();
720
721 logfile2 << "\nInstallation ended " << to_simple_string(end_time) << "\nThe process took " << total_time.length();
722 logfile2.close();
723
724 Sleep(1000);
725 setProgressBar(0);
726}
727 catch(exception & ex) {
728 remove("Install.log"); //why did we do this? :|
729 ofstream logfile("Install.log");
730 logfile << "Warning, exception " << ex.what() << "!";
731 setStatusArea("Warning, exception " + (string)ex.what() + "!");
732 logfile.close();
733 }
734 busy = 0;
735}
736
737void copyBSL(string copypath, vector<string>& BSLfolders, ModPackage pkg)
738{
739 ofstream BSLlog("BSL.log", ios::app );
740
741 try {
742 for ( directory_iterator dir_itr( copypath ), end_itr;
743 dir_itr != end_itr;
744 ++dir_itr ) {
745
746 if ( is_directory( dir_itr->path() ) && dir_itr->path().string() != ".svn" ) {
747 BSLlog << "Testing " << dir_itr->path().string() << " HasBSL: " << pkg.hasBSL << " HasAddon: " << pkg.hasAddon << "\n";
748 int skip_folder = 0;
749 if(!pkg.hasAddon) {
750 for(unsigned int k = 0; k < BSLfolders.size(); k++) {//iterate through already found BSL folders
751 BSLlog << "testing " << dir_itr->path().filename() << " vs " << BSLfolders[k] << "\n";
752 if(dir_itr->path().filename() == BSLfolders[k]) {
753 skip_folder = 1;
754 BSLlog << "skipping " << BSLfolders[k] << " in " << pkg.modStringName << "\n";
755 break;
756 }
757 }
758 }
759 if (!skip_folder && !exists("../GameDataFolder/IGMD/" + dir_itr->path().filename() + "/ignore.txt")) {
760 if(!pkg.hasAddon) remove_all( "../GameDataFolder/IGMD/" + dir_itr->path().filename() );
761 Sleep(100);
762 create_directory( "../GameDataFolder/IGMD/" + dir_itr->path().filename());
763 BSLlog << "Copied " << dir_itr->path().string() << " in " << pkg.modStringName << "!\n";
764 for ( directory_iterator bsl_itr( dir_itr->path() );
765 bsl_itr != end_itr;
766 bsl_itr++ ) {
767 if ( bsl_itr->path().extension() == ".bsl" ) {
768 if(exists("../GameDataFolder/IGMD/" + dir_itr->path().filename() + "/" + bsl_itr->path().filename()))
769 remove("../GameDataFolder/IGMD/" + dir_itr->path().filename() + "/" + bsl_itr->path().filename());
770 copy_file(bsl_itr->path(), "../GameDataFolder/IGMD/" + dir_itr->path().filename() + "/" + bsl_itr->path().filename());
771 }
772 }
773 if( !pkg.hasAddon ) {
774 BSLfolders.push_back( dir_itr->path().filename() ); //add back check for addon
775 BSLlog << "Pushing " << dir_itr->path().filename() << "\n" ;
776 }
777 }
778 }
779 }
780 }
781 catch ( const std::exception & ex )
782 {
783 setStatusArea("Warning, exception " + (string)ex.what() + "!");
784 while(1) Sleep(1000);
785 }
786 BSLlog.close();
787
788}
789
790
791void writeInstalledMods(vector<string> installedMods)
792{
793 if ( exists( strInstallCfg ) )
794 {
795 remove( strInstallCfg );
796 }
797
798 ofstream file(strInstallCfg.c_str());
799
800 vector<string>list = installedMods;
801 vector<string>::iterator begin_iter = list.begin();
802 vector<string>::iterator end_iter = list.end();
803
804 sort( list.begin(), list.end() );
805
806 for( ; begin_iter != end_iter; ++begin_iter) {
807 file << *begin_iter << " ";
808 }
809
810 file.close();
811 file.clear();
812}
813
814vector<string> getInstallString(string Cfg)
815{
816 vector<string> returnval;
817 string line;
818 fstream file;
819
820 if (exists( Cfg ))
821 {
822 file.open(Cfg.c_str());
823 getline(file, line);
824 tokenize(line, returnval);
825 file.close();
826 file.clear();
827 sort(returnval.begin(), returnval.end());
828 }
829 else cout << "fail";
830
831 return returnval;
832}
833
834/* GetUpdateStatus determines whether there is an update available. It is called once, *\
835| on launch, by AEInstallerApp::OnInit(), and not only passes back a #defined result |
836| code, but also oversees the setting of data in the global structures currentAE and |
837| updateAE, which tell the Installer all the version information it needs to know. |
838| ---Return Values--- |
839| UPDATE_LOG_READ_ERR -- A log file could not be opened |
840| UPDATE_INST_REPL_ERR -- The Installer self-updating process failed |
841| UPDATE_MNTH_REQD_ERR -- The update is a patch, and the monthly release it |
842| patches is not installed |
843| UPDATE_NO_UPD_AVAIL -- Either there isn't an update in place, or it's not |
844| newer than what's installed |
845| UPDATE_SIMP_AVAIL -- An update is available |
846| UPDATE_GLOB_AVAIL -- An update is available that requires re-globalization |
847| afterwards (because of some notable change in the AE) |
848| UPDATE_INST_AVAIL -- An update is available that first requires the |
849| Installer to be replaced (when the new Installer |
850| launches, this function will be called again but will |
851| return UPDATE_SIMP_AVAIL or UPDATE_GLOB_AVAIL) |
852| UPDATE_PKG_AVAIL -- A newer version of individual package(s) is available |
853\* UPDATE_CONT_UPD -- Currently unused */
854int GetUpdateStatus(Install_info_cfg *currentAE, Install_info_cfg *updateAE, bool *installerJustUpdated)
855{
856 fstream currentAECfg, updateAECfg, updateLog;
857 string strInstaller = "Installer";
858 string strBeing = "being";
859 string strWas = "was"; // lol
860#ifdef WIN32
861 string strInstallerName = "AEInstaller.exe";
862#else
863 string strInstallerName = "Installer.app";
864#endif
865
866 // Try to get current AE's version info; if it doesn't exist, then the default version data for 2009-07 remains in place
867 if (exists("packages/Globalize/Install_Info.cfg"))
868 {
869 currentAECfg.open("packages/Globalize/Install_Info.cfg");
870 if (!currentAECfg.fail())
871 {
872 if (!ReadInstallInfoCfg(&currentAECfg, currentAE))
873 return UPDATE_LOG_READ_ERR;
874
875 currentAECfg.close();
876 currentAECfg.clear();
877 }
878 else
879 return UPDATE_LOG_READ_ERR;
880 }
881
882 // Is there an update in the updates/ folder, and is it a monthly release or a patch?
883 bool firstParty = 0;
884 // First create the folder if it's missing, so users are never left wondering where updates are supposed to be put
885 if (!exists("../updates"))
886 create_directory("../updates");
887 if (exists("../updates/Edition"))
888 {
889 firstParty = 1;
890 }
891 else {
892 strEUFN = "Edition-patch";
893 if (exists("../updates/Edition-patch")) {
894 firstParty = 1;
895 }
896
897 }
898
899 if(firstParty) {
900 // Unlike the current AE's version info, we *need* to find the update's version info or we won't continue
901 string updateCfgPath = ("../updates/" + strEUFN + "/install/packages/Globalize/Install_Info.cfg");
902 updateAECfg.open(updateCfgPath.c_str());
903 if (!updateAECfg.fail())
904 {
905 if (!ReadInstallInfoCfg(&updateAECfg, updateAE))
906 return UPDATE_LOG_READ_ERR;
907
908 updateAECfg.close();
909 updateAECfg.clear();
910 }
911 else
912 return UPDATE_LOG_READ_ERR;
913
914 // Now we check for an Installer update in progress
915 if (exists("Update.log"))
916 {
917 updateLog.open("Update.log");
918 if (!updateLog.fail())
919 {
920 vector<string> lines;
921 string line;
922 int num_lines = 0;
923 bool readingInstallerVersion = false, doneReadingFile = false;
924
925 while (!updateLog.eof() && !doneReadingFile)
926 {
927 getline(updateLog, line);
928 lines.push_back(line);
929 num_lines++;
930 vector<string> tokens;
931 vector<string>::iterator iter;
932 tokenize(line, tokens);
933 iter = tokens.begin();
934 if (!readingInstallerVersion && tokens.capacity() >= 4)
935 {
936 if (!strInstaller.compare(*iter))
937 {
938 if (!strBeing.compare(*++iter))
939 readingInstallerVersion = true;
940 else if (!strWas.compare(*iter))
941 *installerJustUpdated = true; // our third indirect return value after currentAE and updateAE
942 }
943 }
944 else if (readingInstallerVersion && tokens.capacity() >= 3)
945 {
946 readingInstallerVersion = false;
947 string installerVersion = INSTALLER_VERSION;
948 if (installerVersion.compare(*iter)) // then the shell script-powered replacement failed
949 return UPDATE_INST_REPL_ERR;
950 else
951 {
952 updateLog.close();
953 updateLog.clear();
954 Sleep(1000);
955 remove("Update.log");
956 ofstream newUpdateLog("Update.log");
957 if (!newUpdateLog.fail())
958 {
959 // Write over old log with updated information
960 ptime startTime(second_clock::local_time());
961 string strStartTime = to_simple_string(startTime);
962 string newUpdateLine = installerVersion + " on " + strStartTime;
963 for (int a = 0; a < lines.capacity() - 2; a++) // if there were even lines in the log before this at all
964 {
965 newUpdateLog << lines[a].c_str();
966 newUpdateLog << "\n";
967 }
968 newUpdateLog << "Installer was updated to:\n";
969 newUpdateLog << newUpdateLine.c_str();
970 *installerJustUpdated = true; // this value is indirectly returned to AEInstallerApp::OnInit()
971 doneReadingFile = true;
972 newUpdateLog.close();
973 newUpdateLog.clear();
974 //return UPDATE_CONT_UPD; // as noted above, we are not using this return value; in fact, we want...
975 // ...the code to continue running down through the Edition version check
976 }
977 else
978 return UPDATE_LOG_READ_ERR;
979 }
980 }
981 }
982 updateLog.close();
983 updateLog.clear();
984 }
985 else
986 return UPDATE_LOG_READ_ERR;
987 }
988
989 if (updateAE->AEVersion.compare(currentAE->AEVersion) > 0) // is the release update newer than what's installed?
990 {
991 string strNewInstallerPath = "../updates/" + strEUFN + "/install/" + strInstallerName;
992 string installerVersion = INSTALLER_VERSION;
993 if (updateAE->InstallerVersion.compare(installerVersion) >= 1)
994 {
995 if (exists(strNewInstallerPath))
996 return UPDATE_INST_AVAIL;
997 }
998 else if (updateAE->globalizationRequired)
999 return UPDATE_GLOB_AVAIL;
1000 else
1001 return UPDATE_SIMP_AVAIL;
1002 }
1003 else
1004 return UPDATE_MNTH_REQD_ERR;
1005 }
1006 try
1007 {
1008 directory_iterator end;
1009 if (exists("../updates"))
1010 {
1011 for (directory_iterator install_iter("../updates"); install_iter != end; ++install_iter)
1012 {
1013 ModPackage installedPackage, updatePackage;
1014 if (is_directory(install_iter->path()) && exists(install_iter->path().string() + "/Mod_Info.cfg"))
1015 {
1016 fstream file;
1017 file.open((install_iter->path().string() + "/Mod_Info.cfg").c_str());
1018 if (!file.fail())
1019 updatePackage = fileToModPackage(file, install_iter->path().filename());
1020 else
1021 {
1022 file.close();
1023 continue;
1024 }
1025 if (exists("packages/" + install_iter->path().filename() + "/Mod_Info.cfg"))
1026 {
1027 file.close();
1028 file.clear();
1029 file.open(("packages/" + install_iter->path().filename() + "/Mod_Info.cfg").c_str());
1030 if (!file.fail())
1031 installedPackage = fileToModPackage(file, install_iter->path().filename());
1032 file.close();
1033 if (updatePackage.modStringVersion > installedPackage.modStringVersion)
1034 {
1035 if (updatePackage.installerVersion <= INSTALLER_VERSION)
1036 return UPDATE_PKG_AVAIL;
1037 }
1038 }
1039 else
1040 {
1041 file.close();
1042 return UPDATE_PKG_AVAIL;
1043 }
1044 }
1045 }
1046 }
1047 }
1048 catch (exception & ex) {
1049 // setStatusArea("Warning, handled exception: " + (string)ex.what());
1050 }
1051
1052 return UPDATE_NO_UPD_AVAIL;
1053}
1054
1055bool ReadInstallInfoCfg(fstream *fileHandler, Install_info_cfg *info_cfg)
1056{
1057 vector<string> tokens;
1058 vector<string>::iterator iter;
1059 string line;
1060 string strAEVersion = "AE_Version";
1061 string strInstallerVersion = "Installer_Version";
1062 string strDaodanVersion = "Daodan_Version";
1063 string strOniSplitVersion = "OniSplit_Version";
1064 string strGUIWinVersion = "GUI_Win_Version";
1065 string strGUIMacVersion = "GUI_Mac_Version";
1066 string strReglobalize = "Reglobalize";
1067 string strDeleteList = "Delete_List";
1068 string strArrow = "->";
1069 string strDoubleSlash = "//";
1070 string strYes = "Yes"; // this is getting silly
1071
1072 while (getline(*fileHandler, line))
1073 {
1074 StripNewlines(&line);
1075 tokenize(line, tokens);
1076 iter = tokens.begin();
1077
1078 if (tokens.size() >= 3)
1079 {
1080 if (!strAEVersion.compare(*iter))
1081 {
1082 if (!strArrow.compare(*++iter))
1083 info_cfg->AEVersion = *++iter;
1084 else
1085 return false;
1086 }
1087 else if (!strInstallerVersion.compare(*iter))
1088 {
1089 if (!strArrow.compare(*++iter))
1090 info_cfg->InstallerVersion = *++iter;
1091 else
1092 return false;
1093 }
1094 else if (!strDaodanVersion.compare(*iter))
1095 {
1096 if (!strArrow.compare(*++iter))
1097 info_cfg->DaodanVersion = *++iter;
1098 else
1099 return false;
1100 }
1101 else if (!strOniSplitVersion.compare(*iter))
1102 {
1103 if (!strArrow.compare(*++iter))
1104 info_cfg->OniSplitVersion = *++iter;
1105 else
1106 return false;
1107 }
1108 else if (!strGUIWinVersion.compare(*iter))
1109 {
1110 if (!strArrow.compare(*++iter))
1111 info_cfg->WinGUIVersion = *++iter;
1112 else
1113 return false;
1114 }
1115 else if (!strGUIMacVersion.compare(*iter))
1116 {
1117 if (!strArrow.compare(*++iter))
1118 info_cfg->MacGUIVersion = *++iter;
1119 else
1120 return false;
1121 }
1122 else if (!strReglobalize.compare(*iter))
1123 {
1124 if (!strArrow.compare(*++iter))
1125 {
1126 if (!strYes.compare(*++iter))
1127 info_cfg->globalizationRequired = true;
1128 }
1129 else
1130 return false;
1131 }
1132 else if (!strDeleteList.compare(*iter))
1133 {
1134 // We need to perform a totally customized parsing process on this data
1135 if (!strArrow.compare(*++iter))
1136 {
1137 vector<string> tokens2;
1138 tokenize(line, tokens2, ","); // the paths on this line are comma-delimited, so we parse it again
1139 vector<string>::iterator iter2 = tokens2.begin();
1140 string finalPath = "";
1141 for (; iter2 != tokens2.end(); iter2++)
1142 {
1143 finalPath = finalPath + *iter2;
1144
1145 string::size_type loc = finalPath.find("->", 0); // the first word will have "Delete_List ->" at the front, so let's cut that off
1146 if (loc != string::npos)
1147 finalPath = finalPath.substr(loc + 3, finalPath.size());
1148
1149 // If a path has '//' in it, it must contain some optional comments that were at the end of the Delete_List line
1150 loc = finalPath.find("//", 0);
1151 if (loc != string::npos)
1152 finalPath = finalPath.substr(0, loc);
1153
1154 // Trim a single space if it exists at the start or finish; putting more than one space after a comma will break this
1155 if (finalPath.at(0) == ' ')
1156 finalPath = finalPath.substr(1, finalPath.size());
1157 if (finalPath.at(finalPath.size() - 1) == ' ')
1158 finalPath = finalPath.substr(0, finalPath.size() - 1);
1159
1160 // If the tokenized path ends with a '\', then we assume it was followed by a comma
1161 if (finalPath.at(finalPath.size() - 1) == '\\')
1162 {
1163 finalPath = finalPath.substr(0, finalPath.size() - 1); // clip the '\' off the end of the string now that it served its purpose...
1164 finalPath = finalPath + ","; // ...and add the actual comma back at the end
1165 }
1166 else // we can add the path to deleteList, and clear the path; otherwise it will be added to on the next iteration
1167 {
1168 if (StringIsLegalPathForDeletion(finalPath)) // ...and it's not violating any of our security rules as to what can be deleted...
1169 info_cfg->deleteList.push_back(finalPath); // ...then add it to our deleteList in memory
1170 finalPath.clear(); // clear the token we were building up before the next pass
1171 }
1172 }
1173 }
1174 else
1175 return false;
1176 }
1177 }
1178 tokens.clear();
1179 }
1180
1181 return true;
1182}
1183
1184// TODO: Fix security holes here
1185/* There is currently a security hole in this function; the first occurrence of a '.' not followed by a second '.' will prevent the function from
1186 noticing an actual occurrence of '..' later in the string; iow, it only looks after the first period it finds for a second period.
1187 A second hole is that the last slash will be trimmed from the path, but one could still use ".//" and it would get past this function, and
1188 possibly be interpreted by the Boost file functions as "the current directory". Iow, both of these checks need to be iterative, not one-time.
1189 Not too concerned about this at the moment, as only we of the AE Team are supplying the install_info file that this function is connected to. -I */
1190
1191/* This function serves as a barrier against the Installer deleting files it shouldn't. *\
1192| It tests for each of the following conditions in the path it is passed: |
1193| A. '..' as the whole path or '/..', '\..' anywhere in the path |
1194| Reason: Moving up from the parent directory, the Edition folder, would allow one |
1195| to delete anything on the hard drive, so all "parent path" references are illegal. |
1196| B. '/' at the beginning of the path |
1197| Reason: In Unix, this means the path starts from root level, as opposed to the |
1198| directory we will evaluate these paths as being relative to, which is Edition/. |
1199| C. '.' as the whole path |
1200| Reason: This would mean "the Edition folder", which is not allowed to be deleted. |
1201| D. 'GameDataFolder' at the end of the path |
1202| Reason: We don't allow the entire GDF to be deleted, only specific files in it. |
1203| E. '*' anywhere in the path |
1204| Reason: We don't want this interpreted as a wildcard; it's best to only delete |
1205*\ files by name. */
1206bool StringIsLegalPathForDeletion(string word)
1207{
1208 string::size_type loc1, loc2;
1209
1210 // Trim ending slashes in order to simplify the test
1211 // Note that we're only altering the local copy of the string here
1212 loc1 = word.find_last_of("\\", word.size());
1213 if (loc1 == word.size() - 1)
1214 word.resize(word.size() - 1);
1215 loc1 = word.find_last_of("/", word.size());
1216 if (loc1 == word.size() - 1)
1217 word.resize(word.size() - 1);
1218
1219 // Test B
1220 loc1 = word.find_first_of("\\", 0);
1221 if (loc1 == 0)
1222 return false; // path begins with a slash, meaning root level of HD in Unix, an illegal path
1223 loc1 = word.find_first_of("/", 0);
1224 if (loc1 == 0)
1225 return false; // path begins with a slash, meaning root level of HD in Unix, an illegal path
1226
1227 // Test E
1228 loc1 = word.find("*", 0);
1229 if (loc1 != string::npos) // if we found our character before reaching the end of the string
1230 return false; // path cannot contain the '*' character
1231
1232 // Tests A (part 1) and C
1233 loc1 = word.find(".", 0);
1234 if (loc1 != string::npos)
1235 {
1236 if (word.size() == 1)
1237 return false; // path cannot be simply '.', referring to Edition folder itself
1238 loc2 = word.find(".", loc1 + 1);
1239 if (loc2 == loc1 + 1) // make sure this second period comes after the first one
1240 if (word.size() == 2)
1241 return false; // not allowed to reference a parent directory
1242 }
1243
1244 // Test A (part 2)
1245 loc1 = word.find("/..", 0);
1246 if (loc1 != string::npos)
1247 return false; // not allowed to reference a parent directory
1248 loc1 = word.find("\\..", 0);
1249 if (loc1 != string::npos)
1250 return false; // not allowed to reference a parent directory
1251
1252 // Test D
1253 loc1 = word.find("GameDataFolder", 0);
1254 if (loc1 == word.size() - 14) // if "GameDataFolder" is the last 14 characters of the string...
1255 return false; // not allowed to delete the GDF
1256
1257 return true;
1258}
1259
1260bool ProcessInstallerUpdate(Install_info_cfg *currentAE, Install_info_cfg *updateAE)
1261{
1262 ofstream file;
1263 string shellScript;
1264
1265 ptime startTime(second_clock::local_time());
1266 string strStartTime = to_simple_string(startTime);
1267 string progressMsg = "Installer being updated to:\n" +
1268 updateAE->InstallerVersion + " on " + strStartTime;
1269 file.open("Update.log");
1270 if (!file.fail())
1271 file << progressMsg.c_str();
1272 file.close();
1273 file.clear();
1274
1275 string popenCommand = "../updates/" + strEUFN + "/install/";
1276#ifdef WIN32
1277 popenCommand = "replace_installer.bat";
1278#else
1279 // We can't just use '~' to mean "the home directory" because we need to check the path in C...
1280 // ...so we actually get the current user's shortname and manually construct the path to home
1281 FILE *fUserName = NULL;
1282 char chrUserName[32];
1283 fUserName = popen("whoami", "r");
1284 fgets(chrUserName, sizeof(chrUserName), fUserName);
1285 pclose(fUserName);
1286 string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1287 int endOfName = strUserName.find("\n", 0);
1288 string pathToTrash = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1289 tm tmStartTime = to_tm(startTime);
1290 pathToTrash = pathToTrash + "Old_Edition_files_" + currentAE->AEVersion + "_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1291 boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec); // lol
1292 create_directory(pathToTrash);
1293 // The script takes as a parameter the path the old Installer should go to, in quotes
1294 popenCommand = "bash " + popenCommand + "replace_installer.sh " + pathToTrash + "/Installer.app";
1295
1296#endif
1297 file.close();
1298 file.clear();
1299#ifdef WIN32
1300 system(popenCommand.c_str());
1301#else
1302 popen(popenCommand.c_str(), "r");
1303#endif
1304 return true; // returning 'true' tells the Installer to quit itself ASAP so it can be replaced by the process that is now running
1305}
1306
1307bool ProcessAEUpdate(Install_info_cfg *currentAE, Install_info_cfg *updateAE, bool *installerJustUpdated)
1308{
1309 try {
1310 fstream file;
1311 string line;
1312 vector<string> tokens, updateStarted;
1313 string strInstaller = "Installer";
1314 string strWas = "was";
1315 string strPathToEUFN = ("../updates/" + strEUFN + "/"); // strEUFN is set by GetUpdateStatus()
1316 string strPathToEUFNInstall = ("../updates/" + strEUFN + "/install/");
1317 string strPathToEUFNPackages = ("../updates/" + strEUFN + "/install/packages/");
1318 string strPathToPackages = "packages/";
1319 string strGlobalize = "Globalize/";
1320 string strOniSplit = "OniSplit.exe";
1321 string strDaodan = "binkw32.dll";
1322 string strWinGUI = "onisplit_gui.exe";
1323 string strWinGUILang = "ospgui_lang.ini";
1324 string strMacGUI = "AETools.app";
1325#ifdef WIN32
1326 string strOniApp = "Oni.exe";
1327#else
1328 string strOniApp = "Oni.app";
1329 bool needNewTrashDir = false;
1330#endif
1331
1332 bool readingVerAndDate = false;
1333
1334#ifdef WIN32
1335 //remove readonly attrib from files.
1336 setStatusArea("Removing readonly attribute...");
1337 system("attrib -r ./* /s");
1338 system("attrib -r ../Oni.exe /s");
1339 system("attrib -r ../binkw32.dll /s");
1340
1341#else
1342 FILE *fUserName = NULL;
1343 char chrUserName[32];
1344 fUserName = popen("whoami", "r");
1345 fgets(chrUserName, sizeof(chrUserName), fUserName);
1346 pclose(fUserName);
1347 string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1348 int endOfName = strUserName.find("\n", 0);
1349 string strTrashDir = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1350#endif
1351
1352 // Write to log that we are beginning the update process
1353 ptime startTime(second_clock::local_time());
1354 string strStartTime = to_simple_string(startTime);
1355 string progressMsg = "\nEdition being updated to:\n" +
1356 updateAE->AEVersion + " on " + strStartTime;
1357 file.open("Update.log");
1358 if (!file.fail())
1359 file << progressMsg.c_str();
1360
1361 if (*installerJustUpdated) // then we want to know what folder in the Trash the Installer was placed in...
1362 {
1363 while (!file.eof()) // ...so we read the log to get the timestamp so we know the name of the folder that should be in the Trash
1364 {
1365 getline(file, line);
1366 tokenize(line, tokens);
1367
1368 if (tokens.capacity() >= 4)
1369 if (!strInstaller.compare(tokens[0]))
1370 if (!strWas.compare(tokens[1]))
1371 readingVerAndDate = true;
1372 if (readingVerAndDate && tokens.capacity() >= 3)
1373 tokenize(tokens[2], updateStarted, "-");
1374 }
1375#ifndef WIN32
1376 if (updateStarted.capacity() < 3)
1377 needNewTrashDir = true;
1378 else
1379 {
1380 strTrashDir = strTrashDir + "Old_Edition_files_" + currentAE->AEVersion + "-" +
1381 updateStarted[0] + "-" + updateStarted[1] + "-" + updateStarted[2] + "/";
1382 if (!exists(strTrashDir))
1383 needNewTrashDir = true;
1384 }
1385#endif
1386 }
1387#ifndef WIN32
1388 if (!*installerJustUpdated || needNewTrashDir) // prepare a new directory for deleted files to go to
1389 {
1390 tm tmStartTime = to_tm(startTime);
1391 strTrashDir = strTrashDir + "Old_Edition_files_" + currentAE->AEVersion + "_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1392 boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec) + "/";
1393 create_directory(strTrashDir);
1394 }
1395#endif
1396 file.close();
1397 file.clear();
1398
1399 // Special code to replace our special files -- the Oni app, OniSplit, the Daodan DLL, and the GUI for OniSplit
1400 if (exists(strPathToEUFN + strOniApp))
1401 {
1402 if (exists("../" + strOniApp))
1403#ifdef WIN32
1404 remove((path)("../" + strOniApp));
1405#else
1406 rename((path)("../" + strOniApp), (path)(strTrashDir + strOniApp));
1407#endif
1408 rename((path)(strPathToEUFN + strOniApp), (path)("../" + strOniApp));
1409 }
1410 if (updateAE->OniSplitVersion.compare(currentAE->OniSplitVersion) >= 1)
1411 {
1412 if (exists(strPathToEUFNInstall + strOniSplit))
1413 {
1414 if (exists(strOniSplit))
1415#ifdef WIN32
1416 remove((path)strOniSplit);
1417#else
1418 rename((path)strOniSplit, (path)(strTrashDir + strOniSplit));
1419#endif
1420 rename((path)(strPathToEUFNInstall + strOniSplit), (path)strOniSplit);
1421 }
1422 }
1423#ifdef WIN32
1424 if (updateAE->DaodanVersion.compare(currentAE->DaodanVersion) >= 1)
1425 {
1426 if (exists(strPathToEUFN + strDaodan))
1427 {
1428 if (exists(("../" + strDaodan)))
1429 remove((path)("../" + strDaodan));
1430 rename((path)(strPathToEUFN + strDaodan), (path)("../" + strDaodan));
1431 }
1432 }
1433 if (updateAE->WinGUIVersion.compare(currentAE->WinGUIVersion) >= 1)
1434 {
1435 if (exists(strPathToEUFNInstall + strWinGUI))
1436 {
1437 if (exists((path)strWinGUI))
1438 remove((path)strWinGUI);
1439 if (exists(strWinGUILang))
1440 remove((path)strWinGUILang);
1441 rename((path)(strPathToEUFNInstall + strWinGUI), (path)strWinGUI);
1442 rename((path)(strPathToEUFNInstall + strWinGUILang), (path)strWinGUILang);
1443 }
1444 }
1445#else
1446 if (updateAE->MacGUIVersion.compare(currentAE->MacGUIVersion) >= 1)
1447 {
1448 if (exists(strPathToEUFN + strMacGUI))
1449 {
1450 if (exists(("../" + strMacGUI)))
1451 rename((path)("../" + strMacGUI), (path)(strTrashDir + strMacGUI));
1452 rename((path)(strPathToEUFN + strMacGUI), (path)("../" + strMacGUI));
1453 }
1454 }
1455#endif
1456
1457 // Now we trash whatever's in DeleteList; this allows us to clear out obsolete files in the previous AE install
1458 // Before moving a file to the Trash, we need to make sure each of the file's parent paths exists in the Trash...
1459 // ...so we iterate through the hierarchy of the file path, checking for each one and creating it if necessary
1460 for (vector<string>::iterator iter = updateAE->deleteList.begin(); iter != updateAE->deleteList.end(); iter++)
1461 {
1462 string thePath = *iter;
1463 if (exists((path)("../" + thePath)))
1464 {
1465 string aParentPath;
1466 string::size_type curPos = thePath.find("/", 0);
1467 if (curPos != string::npos)
1468 aParentPath = thePath.substr(0, curPos);
1469 string::size_type lastPos = curPos;
1470 while (curPos != string::npos && curPos < thePath.size())
1471 {
1472 aParentPath = aParentPath + thePath.substr(lastPos, curPos - lastPos);
1473#ifndef WIN32
1474 if (!exists(strTrashDir + aParentPath))
1475 create_directory(strTrashDir + aParentPath);
1476#endif
1477 lastPos = curPos + 1;
1478 curPos = thePath.find("/", lastPos);
1479 aParentPath = aParentPath + "/";
1480 }
1481#ifndef WIN32
1482 rename((path)("../" + thePath), (path)(strTrashDir + thePath));
1483#else
1484 remove((path)("../" + thePath));
1485#endif
1486 }
1487 }
1488
1489 ProcessPackageUpdates(strPathToEUFNPackages, strPathToPackages);
1490
1491 // Next, move over files in the update's Globalize folder; subfolders which do not exist in the current AE will be created by Boost's...
1492 // ...create_directories() function
1493 string strPath;
1494 path thePath;
1495 for (recursive_directory_iterator dir_itr(strPathToEUFNPackages + strGlobalize), end_itr; dir_itr != end_itr; ++dir_itr)
1496 {
1497 strPath = dir_itr->path().string();
1498 MakePathLocalToGlobalize(&strPath);
1499 thePath = (path)strPath;
1500 if (is_regular_file(dir_itr->status()))
1501 {
1502 if (thePath.filename().at(0) != '.') // skip over dot-files, which are invisible in Unix
1503 {
1504 if (exists(strPathToPackages + strGlobalize + strPath))
1505 {
1506#ifdef WIN32
1507 remove((path)(strPathToPackages + strGlobalize + strPath));
1508#else
1509 create_directories((path)(strTrashDir + thePath.parent_path().string()));
1510 rename((path)(strPathToPackages + strGlobalize + strPath), (path)(strTrashDir + strPath));
1511#endif
1512 rename((path)(strPathToEUFNPackages + strGlobalize + strPath), (path)(strPathToPackages + strGlobalize + strPath));
1513 }
1514 else
1515 {
1516 int slashLoc = 0;
1517 slashLoc = strPath.find("/", 0);
1518 if (slashLoc != string::npos) // then path contains slashes, so we need to make sure its parents' paths exist before moving it
1519 create_directories((path)(strPathToPackages + strGlobalize + thePath.parent_path().string()));
1520 rename((path)(strPathToEUFNPackages + strGlobalize + strPath), (path)(strPathToPackages + strGlobalize + strPath));
1521 }
1522 }
1523 }
1524 }
1525
1526 // Clean up after ourselves, trashing any packages or programs in the update package that are not newer than the current AE
1527#ifdef WIN32
1528 remove_all((path)strPathToEUFN);
1529#else
1530 create_directory(strTrashDir + "Unneeded update files");
1531 rename((path)strPathToEUFN, (path)(strTrashDir + "Unneeded update files/" + strEUFN));
1532#endif
1533 // Write to log that we are finished with update
1534 ptime end_time(second_clock::local_time());
1535 string progressMsg2 = "Edition was updated to:\n" +
1536 updateAE->AEVersion + " on " + to_simple_string(end_time);
1537
1538 file.open("Update.log");
1539
1540 if(!file.fail())
1541 file.write(progressMsg2.c_str(), sizeof(progressMsg2.c_str()));
1542
1543 file.close();
1544 file.clear();
1545
1546 if (updateAE->globalizationRequired)
1547 CheckForGlobalization(true); // the 'true' value forces re-globalization
1548
1549 globalPackages = getPackages(); // refresh the list in memory
1550 wxCommandEvent e;
1551 TheWindow->OnRefreshButtonClick( e );
1552 return true;
1553 }
1554 catch (exception & ex)
1555 {
1556 setStatusArea("Warning, handled exception: " + (string)ex.what());
1557 return false;
1558 }
1559}
1560
1561void ProcessPackageUpdates(string pathToUpdate, string strPathToPackages)
1562{
1563 ptime startTime(second_clock::local_time());
1564#ifdef WIN32
1565 string strTrashDir = "Trash\\"; // string unused in Windows because files are simply deleted
1566#else
1567 FILE *fUserName = NULL;
1568 char chrUserName[32];
1569 fUserName = popen("whoami", "r");
1570 fgets(chrUserName, sizeof(chrUserName), fUserName);
1571 pclose(fUserName);
1572 string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1573 int endOfName = strUserName.find("\n", 0);
1574 string strTrashDir = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1575 bool needNewTrashDir = true;
1576 tm tmStartTime = to_tm(startTime);
1577#endif
1578
1579 try
1580 {
1581 directory_iterator end;
1582 for (directory_iterator update_iter(pathToUpdate); update_iter != end; ++update_iter)
1583 {
1584 ModPackage installedPackage, updatePackage;
1585 string updtPath = update_iter->path().string();
1586 string updtFolder = update_iter->path().filename();
1587 string updtModInfo = updtPath + "/Mod_Info.cfg";
1588 string instModInfo = strPathToPackages + "/" + updtFolder + "/Mod_Info.cfg";
1589 if (!boost::iequals(updtFolder, "Edition")
1590 && !boost::iequals(updtFolder, "Edition-patch")
1591 && is_directory(update_iter->path())
1592 && exists(updtModInfo))
1593 {
1594 fstream file;
1595 file.open((updtModInfo).c_str());
1596 if (!file.fail())
1597 updatePackage = fileToModPackage(file, updtFolder);
1598 else
1599 {
1600 file.close();
1601 continue;
1602 }
1603 if (exists(instModInfo))
1604 {
1605 file.close();
1606 file.clear();
1607 file.open(instModInfo.c_str());
1608 if (!file.fail())
1609 {
1610 installedPackage = fileToModPackage(file, updtFolder);
1611 }
1612 file.close();
1613 }
1614 file.close();
1615 if (updatePackage.modStringVersion > installedPackage.modStringVersion)
1616 {
1617 if (updatePackage.installerVersion <= INSTALLER_VERSION)
1618 {
1619 if(exists(strPathToPackages + "/" + updatePackage.modStringName)) {
1620#ifdef WIN32
1621 remove_all((path)(strPathToPackages + "/" + updatePackage.modStringName));
1622#else
1623 if (needNewTrashDir)
1624 {
1625 strTrashDir = strTrashDir + "Old_packages_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1626 boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec) + "/";
1627 create_directory(strTrashDir);
1628 needNewTrashDir = false;
1629 }
1630 rename((path)(strPathToPackages + "/" + updatePackage.modStringName), (path)(strTrashDir + updatePackage.modStringName));
1631#endif
1632 }
1633 rename((path)(pathToUpdate + "/" + updatePackage.modStringName), (path)(strPathToPackages + "/" + updatePackage.modStringName));
1634 }
1635 }
1636 }
1637 }
1638 }
1639 catch (exception & ex)
1640 {
1641 setStatusArea("Warning, handled exception: " + (string)ex.what());
1642 }
1643 wxCommandEvent e;
1644 TheWindow->OnRefreshButtonClick( e );
1645}
1646
1647/* MakePathLocalToGlobalize is a function used once by ProcessAEUpdate() that takes a file in an \
1648| update's Globalize folder and changes its path, originally relative to the Installer, to be |
1649| relative to the structure of the Globalize folder; this makes it easier to have the Installer |
1650\ move said file from an update's Globalize folder to the current Globalize folder. */
1651void MakePathLocalToGlobalize(string *installerBasedPath)
1652{
1653 int deleteToHere = 0;
1654 deleteToHere = installerBasedPath->find("Globalize/");
1655 if (deleteToHere != 0)
1656 {
1657 deleteToHere += strlen("Globalize/");
1658 installerBasedPath->erase(0, deleteToHere);
1659 }
1660}
1661
1662/* SortBySize is a custom comparison function that we call when using the C++ sort() function in \
1663\ ProcessAEUpdate() on some strings that we want to sort by length. */
1664bool SortBySize(string a, string b)
1665{
1666 return (a.size() < b.size());
1667}
1668
1669//stolen token function...
1670void tokenize(const string& str, vector<string>& tokens, const string& delimiters)
1671{
1672 // Skip delimiters at beginning.
1673 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
1674 // Find first "non-delimiter".
1675 string::size_type pos = str.find_first_of(delimiters, lastPos);
1676
1677 while (string::npos != pos || string::npos != lastPos)
1678 {
1679 // Found a token, add it to the vector.
1680 tokens.push_back(str.substr(lastPos, pos - lastPos));
1681 // Skip delimiters. Note the "not_of"
1682 lastPos = str.find_first_not_of(delimiters, pos);
1683 // Find next "non-delimiter"
1684 pos = str.find_first_of(delimiters, lastPos);
1685 }
1686}
1687
1688/* StripNewlines() gets rids of any linebreaks that come from text returned by getline(); \
1689| getline() should be stripping those out, but Windows CR/LF files seem to be sneaking |
1690\ some extra return characters into strings in the ReadInstallInfoCfg() function. */
1691void StripNewlines(string *theLine)
1692{
1693 int deleteFromHere = 0;
1694 deleteFromHere = theLine->find("\r");
1695 if (deleteFromHere > 0)
1696 theLine->erase(deleteFromHere, theLine->size());
1697}
1698
1699void clearOldDats(void) {
1700 directory_iterator end_iter_gdf;
1701 for ( directory_iterator dir_itr_gdf( "../GameDataFolder" );
1702 dir_itr_gdf != end_iter_gdf;
1703 ++dir_itr_gdf )
1704 {
1705 if ( dir_itr_gdf->path().extension() == ".dat" || dir_itr_gdf->path().extension() == ".raw" || dir_itr_gdf->path().extension() == ".sep" ) {
1706 remove( dir_itr_gdf->path() );
1707 }
1708
1709 }
1710
1711}
1712
1713// this function copies files and directories. If copying a
1714// directory to a directory, it copies recursively.
1715
1716//pardon the mess, I did this at midnight, and had to fix a bug
1717void copy( const path & from_ph,
1718 const path & to_ph )
1719{
1720 cout << to_ph.string() << "\n";
1721 // Make sure that the destination, if it exists, is a directory
1722 if((exists(to_ph) && !is_directory(to_ph)) || (!exists(from_ph))) cout << "error";
1723 if(!is_directory(from_ph))
1724 {
1725
1726 if(exists(to_ph))
1727 {
1728 copy_file(from_ph,to_ph/from_ph.filename());
1729 }
1730 else
1731 {
1732 try{
1733
1734 copy_file(from_ph,to_ph);
1735 }
1736 catch (exception ex){
1737 cout << from_ph.string() << " to " << to_ph.string() << "\n";
1738 }
1739 }
1740
1741 }
1742 else if(from_ph.filename() != ".svn")
1743 {
1744 path destination;
1745 if(!exists(to_ph))
1746 {
1747 destination=to_ph;
1748 }
1749 else
1750 {
1751 destination=to_ph/from_ph.filename();
1752 }
1753
1754 for(directory_iterator i(from_ph); i!=directory_iterator(); ++i)
1755 {
1756 //the idiot who coded this in the first place (not me)
1757 //forgot to make a new directory. Exception city. x_x
1758 create_directory(destination);
1759 copy(*i, destination/i->filename());
1760 }
1761 }
1762}
1763
1764void copy_directory( const path &from_dir_ph,
1765 const path &to_dir_ph)
1766{
1767 if(!exists(from_dir_ph) || !is_directory(from_dir_ph)
1768 || exists(to_dir_ph))
1769 cout << !exists(from_dir_ph) << " " << !is_directory(from_dir_ph)
1770 << " " << exists(to_dir_ph);
1771
1772# ifdef BOOST_POSIX
1773 struct stat from_stat;
1774 if ( (::stat( from_dir_ph.string().c_str(), &from_stat ) != 0)
1775 || ::mkdir(to_dir_ph.native_directory_string().c_str(),
1776 from_stat.st_mode)!=0)
1777# endif
1778 }
1779
1780string escapePath(string input)
1781{
1782 string output;
1783 string escape_me = "& ;()|<>\"'\\#*?$";
1784 for (unsigned int i = 0; i < input.size(); i++)
1785 {
1786 for (unsigned int j = 0; j < escape_me.size(); j++)
1787 if (input[i] == escape_me[j])
1788 output += '\\';
1789 output += input[i];
1790 }
1791 return output;
1792}
1793
1794Install_info_cfg::Install_info_cfg()
1795{
1796 AEVersion = "2009-07b";
1797 InstallerVersion = "1.0.1";
1798 DaodanVersion = "1.0";
1799 OniSplitVersion = "0.9.38.0";
1800 WinGUIVersion = "0";
1801 MacGUIVersion = "0";
1802 patch = false;
1803 globalizationRequired = false;
1804 deleteList.reserve(255);
1805}
1806
1807ModPackage::ModPackage()
1808{
1809 isInstalled = true; // replace with function
1810 name = "";
1811 modStringName = "";
1812 modStringVersion = 0;
1813 platform = "Both";
1814 hasOnis = false;
1815 hasDeltas = false;
1816 hasBSL = false;
1817 hasAddon = false;
1818 hasDats = false;
1819 category = "";
1820 creator = "";
1821 isEngine = false;
1822 readme = "";
1823 globalNeeded = true;
1824}
1825#ifndef WIN32
1826void Sleep(int ms)
1827{
1828 sleep(ms / 1000);
1829}
1830#endif
1831#ifdef WIN32
1832
1833void RedirectIOToConsole()
1834{
1835 int hConHandle;
1836 long lStdHandle;
1837 CONSOLE_SCREEN_BUFFER_INFO coninfo;
1838 FILE *fp;
1839
1840 // allocate a console for this app
1841 AllocConsole();
1842
1843 // set the screen buffer to be big enough to let us scroll text
1844 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
1845 &coninfo);
1846 coninfo.dwSize.Y = MAX_CONSOLE_LINES;
1847 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
1848 coninfo.dwSize);
1849
1850 // redirect unbuffered STDOUT to the console
1851 lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
1852 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1853 fp = _fdopen( hConHandle, "w" );
1854 *stdout = *fp;
1855 setvbuf( stdout, NULL, _IONBF, 0 );
1856
1857 // redirect unbuffered STDIN to the console
1858 lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
1859 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1860 fp = _fdopen( hConHandle, "r" );
1861 *stdin = *fp;
1862 setvbuf( stdin, NULL, _IONBF, 0 );
1863
1864 // redirect unbuffered STDERR to the console
1865 lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
1866 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1867 fp = _fdopen( hConHandle, "w" );
1868 *stderr = *fp;
1869 setvbuf( stderr, NULL, _IONBF, 0 );
1870
1871 // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
1872 // point to console as well
1873 ios::sync_with_stdio();
1874}
1875#endif
Note: See TracBrowser for help on using the repository browser.