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

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

Stuff?

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