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

Last change on this file since 505 was 505, checked in by gumby, 11 years ago

More improvements.

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