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

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

Allows new levels

File size: 67.3 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 //string strTrashDir = "Trash\\"; // string unused in Windows because files are simply deleted
1342#else
1343 FILE *fUserName = NULL;
1344 char chrUserName[32];
1345 fUserName = popen("whoami", "r");
1346 fgets(chrUserName, sizeof(chrUserName), fUserName);
1347 pclose(fUserName);
1348 string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1349 int endOfName = strUserName.find("\n", 0);
1350 string strTrashDir = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1351#endif
1352
1353 // Write to log that we are beginning the update process
1354 ptime startTime(second_clock::local_time());
1355 string strStartTime = to_simple_string(startTime);
1356 string progressMsg = "\nEdition being updated to:\n" +
1357 updateAE->AEVersion + " on " + strStartTime;
1358 file.open("Update.log");
1359 if (!file.fail())
1360 file << progressMsg.c_str();
1361
1362 if (*installerJustUpdated) // then we want to know what folder in the Trash the Installer was placed in...
1363 {
1364 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
1365 {
1366 getline(file, line);
1367 tokenize(line, tokens);
1368
1369 if (tokens.capacity() >= 4)
1370 if (!strInstaller.compare(tokens[0]))
1371 if (!strWas.compare(tokens[1]))
1372 readingVerAndDate = true;
1373 if (readingVerAndDate && tokens.capacity() >= 3)
1374 tokenize(tokens[2], updateStarted, "-");
1375 }
1376#ifndef WIN32
1377 if (updateStarted.capacity() < 3)
1378 needNewTrashDir = true;
1379 else
1380 {
1381 strTrashDir = strTrashDir + "Old_Edition_files_" + currentAE->AEVersion + "-" +
1382 updateStarted[0] + "-" + updateStarted[1] + "-" + updateStarted[2] + "/";
1383 if (!exists(strTrashDir))
1384 needNewTrashDir = true;
1385 }
1386#endif
1387 }
1388#ifndef WIN32
1389 if (!*installerJustUpdated || needNewTrashDir) // prepare a new directory for deleted files to go to
1390 {
1391 tm tmStartTime = to_tm(startTime);
1392 strTrashDir = strTrashDir + "Old_Edition_files_" + currentAE->AEVersion + "_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1393 boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec) + "/";
1394 create_directory(strTrashDir);
1395 }
1396#endif
1397 file.close();
1398 file.clear();
1399
1400 // Special code to replace our special files -- the Oni app, OniSplit, the Daodan DLL, and the GUI for OniSplit
1401 if (exists(strPathToEUFN + strOniApp))
1402 {
1403 if (exists("../" + strOniApp))
1404#ifdef WIN32
1405 remove((path)("../" + strOniApp));
1406#else
1407 rename((path)("../" + strOniApp), (path)(strTrashDir + strOniApp));
1408#endif
1409 rename((path)(strPathToEUFN + strOniApp), (path)("../" + strOniApp));
1410 }
1411 if (updateAE->OniSplitVersion.compare(currentAE->OniSplitVersion) >= 1)
1412 {
1413 if (exists(strPathToEUFNInstall + strOniSplit))
1414 {
1415 if (exists(strOniSplit))
1416#ifdef WIN32
1417 remove((path)strOniSplit);
1418#else
1419 rename((path)strOniSplit, (path)(strTrashDir + strOniSplit));
1420#endif
1421 rename((path)(strPathToEUFNInstall + strOniSplit), (path)strOniSplit);
1422 }
1423 }
1424#ifdef WIN32
1425 if (updateAE->DaodanVersion.compare(currentAE->DaodanVersion) >= 1)
1426 {
1427 if (exists(strPathToEUFN + strDaodan))
1428 {
1429 if (exists(("../" + strDaodan)))
1430 remove((path)("../" + strDaodan));
1431 rename((path)(strPathToEUFN + strDaodan), (path)("../" + strDaodan));
1432 }
1433 }
1434 if (updateAE->WinGUIVersion.compare(currentAE->WinGUIVersion) >= 1)
1435 {
1436 if (exists(strPathToEUFNInstall + strWinGUI))
1437 {
1438 if (exists((path)strWinGUI))
1439 remove((path)strWinGUI);
1440 if (exists(strWinGUILang))
1441 remove((path)strWinGUILang);
1442 rename((path)(strPathToEUFNInstall + strWinGUI), (path)strWinGUI);
1443 rename((path)(strPathToEUFNInstall + strWinGUILang), (path)strWinGUILang);
1444 }
1445 }
1446#else
1447 if (updateAE->MacGUIVersion.compare(currentAE->MacGUIVersion) >= 1)
1448 {
1449 if (exists(strPathToEUFN + strMacGUI))
1450 {
1451 if (exists(("../" + strMacGUI)))
1452 rename((path)("../" + strMacGUI), (path)(strTrashDir + strMacGUI));
1453 rename((path)(strPathToEUFN + strMacGUI), (path)("../" + strMacGUI));
1454 }
1455 }
1456#endif
1457
1458 // Now we trash whatever's in DeleteList; this allows us to clear out obsolete files in the previous AE install
1459 // Before moving a file to the Trash, we need to make sure each of the file's parent paths exists in the Trash...
1460 // ...so we iterate through the hierarchy of the file path, checking for each one and creating it if necessary
1461 for (vector<string>::iterator iter = updateAE->deleteList.begin(); iter != updateAE->deleteList.end(); iter++)
1462 {
1463 string thePath = *iter;
1464 if (exists((path)("../" + thePath)))
1465 {
1466 string aParentPath;
1467 string::size_type curPos = thePath.find("/", 0);
1468 if (curPos != string::npos)
1469 aParentPath = thePath.substr(0, curPos);
1470 string::size_type lastPos = curPos;
1471 while (curPos != string::npos && curPos < thePath.size())
1472 {
1473 aParentPath = aParentPath + thePath.substr(lastPos, curPos - lastPos);
1474#ifndef WIN32
1475 if (!exists(strTrashDir + aParentPath))
1476 create_directory(strTrashDir + aParentPath);
1477#endif
1478 lastPos = curPos + 1;
1479 curPos = thePath.find("/", lastPos);
1480 aParentPath = aParentPath + "/";
1481 }
1482#ifndef WIN32
1483 rename((path)("../" + thePath), (path)(strTrashDir + thePath));
1484#else
1485 remove((path)("../" + thePath));
1486#endif
1487 }
1488 }
1489
1490 ProcessPackageUpdates(strPathToEUFNPackages, strPathToPackages);
1491
1492 // 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...
1493 // ...and folders which do not exist in the current AE will be created there
1494 vector<string> foldersToMake, filesToMove;
1495 string thePath;
1496 for (recursive_directory_iterator dir_itr(strPathToEUFNPackages + strGlobalize), end_itr; dir_itr != end_itr; ++dir_itr)
1497 {
1498 thePath = dir_itr->path().string();
1499 MakePathLocalToGlobalize(&thePath);
1500 if (is_regular_file(dir_itr->status()))
1501 {
1502 if (dir_itr->filename().at(0) != '.') // skip over dot-files, which are invisible in Unix
1503 filesToMove.push_back(thePath);
1504 }
1505 else if (is_directory(dir_itr->status()))
1506 {
1507 if (!exists(strPathToPackages + strGlobalize + thePath))
1508 foldersToMake.push_back(thePath);
1509 }
1510 }
1511 // Sort the foldersToMake strings by length, which is a fast solution to the problem of "How do we make sure we create folder 'parent/'...
1512 // ...before folder 'parent/child/'"?
1513 sort(foldersToMake.begin(), foldersToMake.end(), SortBySize); // SortBySize is a custom comparison function found later in this source file
1514 // First make the folders that don't exist in the current AE, so all the files have a place to go
1515 for (vector<string>::iterator iter = foldersToMake.begin(); iter != foldersToMake.end(); iter++)
1516 {
1517 create_directory(strPathToPackages + strGlobalize + *iter);
1518 }
1519 for (vector<string>::iterator iter = filesToMove.begin(); iter != filesToMove.end(); iter++)
1520 {
1521 if (exists(strPathToPackages + strGlobalize + *iter))
1522#ifdef WIN32
1523 remove((path)(strPathToPackages + strGlobalize + *iter));
1524#else
1525 rename((path)(strPathToPackages + strGlobalize + *iter), (path)(strTrashDir + *iter));
1526#endif
1527 rename((path)(strPathToEUFNPackages + strGlobalize + *iter), (path)(strPathToPackages + strGlobalize + *iter));
1528 }
1529
1530 // Clean up after ourselves, trashing any packages or programs in the update package that are not newer than the current AE
1531#ifdef WIN32
1532 remove_all((path)strPathToEUFN);
1533#else
1534 create_directory(strTrashDir + "Unneeded update files");
1535 rename((path)strPathToEUFN, (path)(strTrashDir + "Unneeded update files/" + strEUFN));
1536#endif
1537 // Write to log that we are finished with update
1538 ptime end_time(second_clock::local_time());
1539 string progressMsg2 = "Edition was updated to:\n" +
1540 updateAE->AEVersion + " on " + to_simple_string(end_time);
1541
1542 file.open("Update.log");
1543
1544 if(!file.fail())
1545 file.write(progressMsg2.c_str(), sizeof(progressMsg2.c_str()));
1546
1547 file.close();
1548 file.clear();
1549
1550 if (updateAE->globalizationRequired)
1551 CheckForGlobalization(true); // the 'true' value forces re-globalization
1552
1553 globalPackages = getPackages(); // refresh the list in memory
1554 wxCommandEvent e;
1555 TheWindow->OnRefreshButtonClick( e );
1556 return true;
1557 }
1558 catch (exception & ex)
1559 {
1560 setStatusArea("Warning, handled exception: " + (string)ex.what());
1561 return false;
1562 }
1563
1564}
1565
1566void ProcessPackageUpdates(string pathToUpdate, string strPathToPackages)
1567{
1568 ptime startTime(second_clock::local_time());
1569#ifdef WIN32
1570 string strTrashDir = "Trash\\"; // string unused in Windows because files are simply deleted
1571#else
1572 FILE *fUserName = NULL;
1573 char chrUserName[32];
1574 fUserName = popen("whoami", "r");
1575 fgets(chrUserName, sizeof(chrUserName), fUserName);
1576 pclose(fUserName);
1577 string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1578 int endOfName = strUserName.find("\n", 0);
1579 string strTrashDir = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1580 bool needNewTrashDir = true;
1581 tm tmStartTime = to_tm(startTime);
1582#endif
1583
1584 try
1585 {
1586 directory_iterator end;
1587 for (directory_iterator update_iter(pathToUpdate); update_iter != end; ++update_iter)
1588 {
1589 ModPackage installedPackage, updatePackage;
1590 string updtPath = update_iter->path().string();
1591 string updtFolder = update_iter->path().filename();
1592 string updtModInfo = updtPath + "/Mod_Info.cfg";
1593 string instModInfo = strPathToPackages + "/" + updtFolder + "/Mod_Info.cfg";
1594 if (!boost::iequals(updtFolder, "Edition")
1595 && !boost::iequals(updtFolder, "Edition-patch")
1596 && is_directory(update_iter->path())
1597 && exists(updtModInfo))
1598 {
1599 fstream file;
1600 file.open((updtModInfo).c_str());
1601 if (!file.fail())
1602 updatePackage = fileToModPackage(file, updtFolder);
1603 else
1604 {
1605 file.close();
1606 continue;
1607 }
1608 if (exists(instModInfo))
1609 {
1610 file.close();
1611 file.clear();
1612 file.open(instModInfo.c_str());
1613 if (!file.fail())
1614 {
1615 installedPackage = fileToModPackage(file, updtFolder);
1616 }
1617 file.close();
1618 }
1619 file.close();
1620 if (updatePackage.modStringVersion > installedPackage.modStringVersion)
1621 {
1622 if (updatePackage.installerVersion <= INSTALLER_VERSION)
1623 {
1624 if(exists(strPathToPackages + "/" + updatePackage.modStringName)) {
1625#ifdef WIN32
1626 remove_all((path)(strPathToPackages + "/" + updatePackage.modStringName));
1627#else
1628 if (needNewTrashDir)
1629 {
1630 strTrashDir = strTrashDir + "Old_packages_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1631 boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec) + "/";
1632 create_directory(strTrashDir);
1633 needNewTrashDir = false;
1634 }
1635 rename((path)(strPathToPackages + "/" + updatePackage.modStringName), (path)(strTrashDir + updatePackage.modStringName));
1636#endif
1637 }
1638 rename((path)(pathToUpdate + "/" + updatePackage.modStringName), (path)(strPathToPackages + "/" + updatePackage.modStringName));
1639 }
1640 }
1641 }
1642 }
1643 }
1644 catch (exception & ex)
1645 {
1646 setStatusArea("Warning, handled exception: " + (string)ex.what());
1647 }
1648 wxCommandEvent e;
1649 TheWindow->OnRefreshButtonClick( e );
1650}
1651
1652/* MakePathLocalToGlobalize is a function used once by ProcessAEUpdate() that takes a file in an \
1653| update's Globalize folder and changes its path, originally relative to the Installer, to be |
1654| relative to the structure of the Globalize folder; this makes it easier to have the Installer |
1655\ move said file from an update's Globalize folder to the current Globalize folder. */
1656void MakePathLocalToGlobalize(string *installerBasedPath)
1657{
1658 int deleteToHere = 0;
1659 deleteToHere = installerBasedPath->find("Globalize/");
1660 if (deleteToHere != 0)
1661 {
1662 deleteToHere += strlen("Globalize/");
1663 installerBasedPath->erase(0, deleteToHere);
1664 }
1665}
1666
1667/* SortBySize is a custom comparison function that we call when using the C++ sort() function in \
1668\ ProcessAEUpdate() on some strings that we want to sort by length. */
1669bool SortBySize(string a, string b)
1670{
1671 return (a.size() < b.size());
1672}
1673
1674//stolen token function...
1675void tokenize(const string& str, vector<string>& tokens, const string& delimiters)
1676{
1677 // Skip delimiters at beginning.
1678 string::size_type lastPos = str.find_first_not_of(delimiters, 0);
1679 // Find first "non-delimiter".
1680 string::size_type pos = str.find_first_of(delimiters, lastPos);
1681
1682 while (string::npos != pos || string::npos != lastPos)
1683 {
1684 // Found a token, add it to the vector.
1685 tokens.push_back(str.substr(lastPos, pos - lastPos));
1686 // Skip delimiters. Note the "not_of"
1687 lastPos = str.find_first_not_of(delimiters, pos);
1688 // Find next "non-delimiter"
1689 pos = str.find_first_of(delimiters, lastPos);
1690 }
1691}
1692
1693/* StripNewlines() gets rids of any linebreaks that come from text returned by getline(); \
1694| getline() should be stripping those out, but Windows CR/LF files seem to be sneaking |
1695\ some extra return characters into strings in the ReadInstallInfoCfg() function. */
1696void StripNewlines(string *theLine)
1697{
1698 int deleteFromHere = 0;
1699 deleteFromHere = theLine->find("\r");
1700 if (deleteFromHere > 0)
1701 theLine->erase(deleteFromHere, theLine->size());
1702}
1703
1704void clearOldDats(void) {
1705 directory_iterator end_iter_gdf;
1706 for ( directory_iterator dir_itr_gdf( "../GameDataFolder" );
1707 dir_itr_gdf != end_iter_gdf;
1708 ++dir_itr_gdf )
1709 {
1710 if ( dir_itr_gdf->path().extension() == ".dat" || dir_itr_gdf->path().extension() == ".raw" || dir_itr_gdf->path().extension() == ".sep" ) {
1711 remove( dir_itr_gdf->path() );
1712 }
1713
1714 }
1715
1716}
1717
1718// this function copies files and directories. If copying a
1719// directory to a directory, it copies recursively.
1720
1721//pardon the mess, I did this at midnight, and had to fix a bug
1722void copy( const path & from_ph,
1723 const path & to_ph )
1724{
1725 cout << to_ph.string() << "\n";
1726 // Make sure that the destination, if it exists, is a directory
1727 if((exists(to_ph) && !is_directory(to_ph)) || (!exists(from_ph))) cout << "error";
1728 if(!is_directory(from_ph))
1729 {
1730
1731 if(exists(to_ph))
1732 {
1733 copy_file(from_ph,to_ph/from_ph.filename());
1734 }
1735 else
1736 {
1737 try{
1738
1739 copy_file(from_ph,to_ph);
1740 }
1741 catch (exception ex){
1742 cout << from_ph.string() << " to " << to_ph.string() << "\n";
1743 }
1744 }
1745
1746 }
1747 else if(from_ph.filename() != ".svn")
1748 {
1749 path destination;
1750 if(!exists(to_ph))
1751 {
1752 destination=to_ph;
1753 }
1754 else
1755 {
1756 destination=to_ph/from_ph.filename();
1757 }
1758
1759 for(directory_iterator i(from_ph); i!=directory_iterator(); ++i)
1760 {
1761 //the idiot who coded this in the first place (not me)
1762 //forgot to make a new directory. Exception city. x_x
1763 create_directory(destination);
1764 copy(*i,destination/i->filename());
1765 }
1766 }
1767}
1768
1769void copy_directory( const path &from_dir_ph,
1770 const path &to_dir_ph)
1771{
1772 if(!exists(from_dir_ph) || !is_directory(from_dir_ph)
1773 || exists(to_dir_ph))
1774 cout << !exists(from_dir_ph) << " " << !is_directory(from_dir_ph)
1775 << " " << exists(to_dir_ph);
1776
1777# ifdef BOOST_POSIX
1778 struct stat from_stat;
1779 if ( (::stat( from_dir_ph.string().c_str(), &from_stat ) != 0)
1780 || ::mkdir(to_dir_ph.native_directory_string().c_str(),
1781 from_stat.st_mode)!=0)
1782# endif
1783 }
1784
1785string escapePath(string input)
1786{
1787 string output;
1788 string escape_me = "& ;()|<>\"'\\#*?$";
1789 for (unsigned int i = 0; i < input.size(); i++)
1790 {
1791 for (unsigned int j = 0; j < escape_me.size(); j++)
1792 if (input[i] == escape_me[j])
1793 output += '\\';
1794 output += input[i];
1795 }
1796 return output;
1797}
1798
1799Install_info_cfg::Install_info_cfg()
1800{
1801 AEVersion = "2009-07b";
1802 InstallerVersion = "1.0.1";
1803 DaodanVersion = "1.0";
1804 OniSplitVersion = "0.9.38.0";
1805 WinGUIVersion = "0";
1806 MacGUIVersion = "0";
1807 patch = false;
1808 globalizationRequired = false;
1809 deleteList.reserve(255);
1810}
1811
1812ModPackage::ModPackage()
1813{
1814 isInstalled = true; // replace with function
1815 name = "";
1816 modStringName = "";
1817 modStringVersion = 0;
1818 platform = "Both";
1819 hasOnis = false;
1820 hasDeltas = false;
1821 hasBSL = false;
1822 hasAddon = false;
1823 hasDats = false;
1824 category = "";
1825 creator = "";
1826 isEngine = false;
1827 readme = "";
1828 globalNeeded = true;
1829}
1830#ifndef WIN32
1831void Sleep(int ms)
1832{
1833 sleep(ms / 1000);
1834}
1835#endif
1836#ifdef WIN32
1837
1838void RedirectIOToConsole()
1839{
1840 int hConHandle;
1841 long lStdHandle;
1842 CONSOLE_SCREEN_BUFFER_INFO coninfo;
1843 FILE *fp;
1844
1845 // allocate a console for this app
1846 AllocConsole();
1847
1848 // set the screen buffer to be big enough to let us scroll text
1849 GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),
1850 &coninfo);
1851 coninfo.dwSize.Y = MAX_CONSOLE_LINES;
1852 SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),
1853 coninfo.dwSize);
1854
1855 // redirect unbuffered STDOUT to the console
1856 lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
1857 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1858 fp = _fdopen( hConHandle, "w" );
1859 *stdout = *fp;
1860 setvbuf( stdout, NULL, _IONBF, 0 );
1861
1862 // redirect unbuffered STDIN to the console
1863 lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
1864 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1865 fp = _fdopen( hConHandle, "r" );
1866 *stdin = *fp;
1867 setvbuf( stdin, NULL, _IONBF, 0 );
1868
1869 // redirect unbuffered STDERR to the console
1870 lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
1871 hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1872 fp = _fdopen( hConHandle, "w" );
1873 *stderr = *fp;
1874 setvbuf( stderr, NULL, _IONBF, 0 );
1875
1876 // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
1877 // point to console as well
1878 ios::sync_with_stdio();
1879}
1880#endif
Note: See TracBrowser for help on using the repository browser.