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

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

really really depreciated ModString
Fixed bug with detelist on windows systems

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