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

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

Installer removes all read only attributes in install folder and a few other files.

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