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

Last change on this file since 509 was 509, checked in by gumby, 10 years ago

Fixed broken update code

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