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

Last change on this file since 516 was 516, checked in by iritscen, 10 years ago

Removed TODO lines for things we've done; small fix to package update msg text.

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