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

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

Stuff?

File size: 67.6 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                                        fstream file;
979                                        file.open((install_iter->path().string() + "/Mod_Info.cfg").c_str());
980                                        if (!file.fail())
981                                                ModPackage updatePackage = fileToModPackage(file, install_iter->path().filename());
982                                        else
983                                        {
984                                                file.close();
985                                                continue;
986                                        }
987                                        if (exists("packages" + install_iter->path().filename() + "/Mod_Info.cfg"))
988                                        {
989                                                file.close();
990                                                file.open(("packages" + install_iter->path().filename() + "/Mod_Info.cfg").c_str());
991                                                if (!file.fail())
992                                                        ModPackage installedPackage = fileToModPackage(file, install_iter->path().filename());
993                                                file.close();
994                                                if (updatePackage.modStringVersion > installedPackage.modStringVersion)
995                                                {
996                                                        if (updatePackage.installerVersion <= INSTALLER_VERSION)
997                                                                return UPDATE_PKG_AVAIL;
998                                                }
999                                        }
1000                                        else
1001                                        {
1002                                                file.close();
1003                                                return UPDATE_PKG_AVAIL;
1004                                        }
1005                                }
1006                        }
1007                        else 
1008                        {
1009                                file.close();
1010                                continue;
1011                        }
1012                        file.close();
1013                                               
1014                        file.open( ("packages" + install_iter->path().filename() + "/Mod_Info.cfg").c_str());
1015                        if (!file.fail())
1016                        {
1017                                ModPackage installedPackage = fileToModPackage(file, install_iter->path().filename());
1018                        }
1019                        else
1020                        {
1021                                file.close();
1022                                return UPDATE_THIRD_PARTY;
1023                        }
1024                        file.close();
1025                        if(((string)INSTALLER_VERSION).compare(updatePackage.installerVersion) < 1 && updatePackage.modStringVersion > installedPackage.modStringVersion) {
1026                                return UPDATE_THIRD_PARTY;
1027                        }
1028                }
1029        }
1030        catch (exception & ex) {
1031        //      setStatusArea("Warning, handled exception: " + (string)ex.what());
1032        }
1033
1034        return UPDATE_NO_UPD_AVAIL;
1035}
1036
1037bool ReadInstallInfoCfg(fstream *fileHandler, Install_info_cfg *info_cfg)
1038{
1039        vector<string> tokens;
1040        vector<string>::iterator iter;
1041        string line;
1042        string strAEVersion = "AE_Version";
1043        string strInstallerVersion = "Installer_Version";
1044        string strDaodanVersion = "Daodan_Version";
1045        string strOniSplitVersion = "OniSplit_Version";
1046        string strGUIWinVersion = "GUI_Win_Version";
1047        string strGUIMacVersion = "GUI_Mac_Version";
1048        string strReglobalize = "Reglobalize";
1049        string strDeleteList = "Delete_List";
1050        string strArrow = "->";
1051        string strDoubleSlash = "//";
1052        string strYes = "Yes"; // this is getting silly
1053       
1054        while (getline(*fileHandler, line))
1055        {
1056                StripNewlines(&line);
1057                tokenize(line, tokens);
1058                iter = tokens.begin();
1059               
1060                if (tokens.size() >= 3)
1061                {
1062                        if (!strAEVersion.compare(*iter))
1063                        {
1064                                if (!strArrow.compare(*++iter))
1065                                        info_cfg->AEVersion = *++iter;
1066                                else
1067                                        return false;
1068                        }
1069                        else if (!strInstallerVersion.compare(*iter))
1070                        {
1071                                if (!strArrow.compare(*++iter))
1072                                        info_cfg->InstallerVersion = *++iter;
1073                                else
1074                                        return false;
1075                        }
1076                        else if (!strDaodanVersion.compare(*iter))
1077                        {
1078                                if (!strArrow.compare(*++iter))
1079                                        info_cfg->DaodanVersion = *++iter;
1080                                else
1081                                        return false;
1082                        }
1083                        else if (!strOniSplitVersion.compare(*iter))
1084                        {
1085                                if (!strArrow.compare(*++iter))
1086                                        info_cfg->OniSplitVersion = *++iter;
1087                                else
1088                                        return false;
1089                        }
1090                        else if (!strGUIWinVersion.compare(*iter))
1091                        {
1092                                if (!strArrow.compare(*++iter))
1093                                        info_cfg->WinGUIVersion = *++iter;
1094                                else
1095                                        return false;
1096                        }
1097                        else if (!strGUIMacVersion.compare(*iter))
1098                        {
1099                                if (!strArrow.compare(*++iter))
1100                                        info_cfg->MacGUIVersion = *++iter;
1101                                else
1102                                        return false;
1103                        }
1104                        else if (!strReglobalize.compare(*iter))
1105                        {
1106                                if (!strArrow.compare(*++iter))
1107                                {
1108                                        if (!strYes.compare(*++iter))
1109                                                info_cfg->globalizationRequired = true;
1110                                }
1111                                else
1112                                        return false;
1113                        }
1114                        else if (!strDeleteList.compare(*iter))
1115                        {
1116                                // We need to perform a totally customized parsing process on this data
1117                                if (!strArrow.compare(*++iter))
1118                                {
1119                                        vector<string> tokens2;
1120                                        tokenize(line, tokens2, ","); // the paths on this line are comma-delimited, so we parse it again
1121                                        vector<string>::iterator iter2 = tokens2.begin();
1122                                        string finalPath = "";
1123                                        for (; iter2 != tokens2.end(); iter2++)
1124                                        {
1125                                                finalPath = finalPath + *iter2;
1126                                               
1127                                                string::size_type loc = finalPath.find("->", 0); // the first word will have "Delete_List ->" at the front, so let's cut that off
1128                                                if (loc != string::npos)
1129                                                        finalPath = finalPath.substr(loc + 3, finalPath.size());
1130                                               
1131                                                // If a path has '//' in it, it must contain some optional comments that were at the end of the Delete_List line
1132                                                loc = finalPath.find("//", 0);
1133                                                if (loc != string::npos)
1134                                                        finalPath = finalPath.substr(0, loc);
1135                                               
1136                                                // Trim a single space if it exists at the start or finish; putting more than one space after a comma will break this
1137                                                if (finalPath.at(0) == ' ')
1138                                                        finalPath = finalPath.substr(1, finalPath.size());
1139                                                if (finalPath.at(finalPath.size() - 1) == ' ')
1140                                                        finalPath = finalPath.substr(0, finalPath.size() - 1);
1141
1142                                                // If the tokenized path ends with a '\', then we assume it was followed by a comma
1143                                                if (finalPath.at(finalPath.size() - 1) == '\\')
1144                                                {
1145                                                        finalPath = finalPath.substr(0, finalPath.size() - 1); // clip the '\' off the end of the string now that it served its purpose...
1146                                                        finalPath = finalPath + ","; // ...and add the actual comma back at the end
1147                                                }
1148                                                else // we can add the path to deleteList, and clear the path; otherwise it will be added to on the next iteration
1149                                                {
1150                                                        if (StringIsLegalPathForDeletion(finalPath)) // ...and it's not violating any of our security rules as to what can be deleted...
1151                                                                info_cfg->deleteList.push_back(finalPath); // ...then add it to our deleteList in memory
1152                                                        finalPath.clear(); // clear the token we were building up before the next pass
1153                                                }
1154                                        }
1155                                }
1156                                else
1157                                        return false;
1158                        }
1159                }
1160                tokens.clear();
1161        }
1162       
1163        return true;
1164}
1165
1166// TODO: Fix security holes here
1167/* There is currently a security hole in this function; the first occurrence of a '.' not followed by a second '.' will prevent the function from
1168 noticing an actual occurrence of '..' later in the string; iow, it only looks after the first period it finds for a second period.
1169 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
1170 possibly be interpreted by the Boost file functions as "the current directory". Iow, both of these checks need to be iterative, not one-time.
1171 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 */
1172
1173/* This function serves as a barrier against the Installer deleting files it shouldn't. *\
1174|  It tests for each of the following conditions in the path it is passed:                               |
1175|   A. '..' as the whole path or '/..', '\..' anywhere in the path                                               |
1176|        Reason: Moving up from the parent directory, the Edition folder, would allow one        |
1177|        to delete anything on the hard drive, so all "parent path" references are illegal.      |
1178|   B. '/' at the beginning of the path                                                                                                  |
1179|        Reason: In Unix, this means the path starts from root level, as opposed to the          |
1180|        directory we will evaluate these paths as being relative to, which is Edition/.         |
1181|   C. '.' as the whole path                                                                                                                     |
1182|        Reason: This would mean "the Edition folder", which is not allowed to be deleted.       |
1183|   D. 'GameDataFolder' at the end of the path                                                                                   |
1184|        Reason: We don't allow the entire GDF to be deleted, only specific files in it.         |
1185|   E. '*' anywhere in the path                                                                                                                  |
1186|        Reason: We don't want this interpreted as a wildcard; it's best to only delete          |
1187*\       files by name.                                                                                                                                         */
1188bool StringIsLegalPathForDeletion(string word)
1189{
1190        string::size_type loc1, loc2;
1191       
1192        // Trim ending slashes in order to simplify the test
1193        // Note that we're only altering the local copy of the string here
1194        loc1 = word.find_last_of("\\", word.size());
1195        if (loc1 == word.size() - 1)
1196                word.resize(word.size() - 1);
1197        loc1 = word.find_last_of("/", word.size());
1198        if (loc1 == word.size() - 1)
1199                word.resize(word.size() - 1);
1200       
1201        // Test B
1202        loc1 = word.find_first_of("\\", 0);
1203        if (loc1 == 0)
1204                return false; // path begins with a slash, meaning root level of HD in Unix, an illegal path
1205        loc1 = word.find_first_of("/", 0);
1206        if (loc1 == 0)
1207                return false; // path begins with a slash, meaning root level of HD in Unix, an illegal path
1208       
1209        // Test E
1210        loc1 = word.find("*", 0);
1211        if (loc1 != string::npos) // if we found our character before reaching the end of the string
1212                return false; // path cannot contain the '*' character
1213       
1214        // Tests A (part 1) and C
1215        loc1 = word.find(".", 0);
1216        if (loc1 != string::npos)
1217        {
1218                if (word.size() == 1)
1219                        return false; // path cannot be simply '.', referring to Edition folder itself
1220                loc2 = word.find(".", loc1 + 1);
1221                if (loc2 == loc1 + 1) // make sure this second period comes after the first one
1222                        if (word.size() == 2)
1223                                return false; // not allowed to reference a parent directory
1224        }
1225       
1226        // Test A (part 2)
1227        loc1 = word.find("/..", 0);
1228        if (loc1 != string::npos)
1229                return false; // not allowed to reference a parent directory
1230        loc1 = word.find("\\..", 0);
1231        if (loc1 != string::npos)
1232                return false; // not allowed to reference a parent directory
1233       
1234        // Test D
1235        loc1 = word.find("GameDataFolder", 0);
1236        if (loc1 == word.size() - 14) // if "GameDataFolder" is the last 14 characters of the string...
1237                return false; // not allowed to delete the GDF
1238
1239        return true;
1240}
1241
1242bool ProcessInstallerUpdate(Install_info_cfg *currentAE, Install_info_cfg *updateAE)
1243{
1244        ofstream file;
1245        string shellScript;
1246       
1247        ptime startTime(second_clock::local_time());
1248        string strStartTime = to_simple_string(startTime);
1249        string progressMsg = "Installer being updated to:\n" +
1250                                                 updateAE->InstallerVersion + " on " + strStartTime;
1251        file.open("Update.log");
1252        if (!file.fail())
1253                file << progressMsg.c_str();
1254        file.close();
1255        file.clear();
1256       
1257        string popenCommand = "../updates/" + strEUFN + "/install/";
1258#ifdef WIN32
1259        popenCommand = "replace_installer.bat";
1260#else
1261        // We can't just use '~' to mean "the home directory" because we need to check the path in C...
1262        // ...so we actually get the current user's shortname and manually construct the path to home
1263        FILE *fUserName = NULL;
1264        char chrUserName[32];
1265        fUserName = popen("whoami", "r");
1266        fgets(chrUserName, sizeof(chrUserName), fUserName);
1267        pclose(fUserName);
1268        string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1269        int endOfName = strUserName.find("\n", 0);
1270        string pathToTrash = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1271        tm tmStartTime = to_tm(startTime);
1272        pathToTrash = pathToTrash + "Old_Edition_files_" + currentAE->AEVersion + "_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1273        boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec); // lol
1274        create_directory(pathToTrash);
1275        // The script takes as a parameter the path the old Installer should go to, in quotes
1276        popenCommand = "bash " + popenCommand + "replace_installer.sh " + pathToTrash + "/Installer.app";
1277                                   
1278#endif
1279        file.close();
1280        file.clear();
1281#ifdef WIN32
1282        system(popenCommand.c_str());
1283#else
1284        popen(popenCommand.c_str(), "r");
1285#endif
1286        return true; // returning 'true' tells the Installer to quit itself ASAP so it can be replaced by the process that is now running
1287}
1288
1289
1290void CrawlPackages(string pathToUpdate, string strPathToPackages) {
1291        try{
1292                directory_iterator end;
1293                for ( directory_iterator update_iter( pathToUpdate );
1294                        update_iter != end;
1295                        ++update_iter )
1296                {
1297
1298                        ModPackage installedPackage, updatePackage;
1299                        string updateStr = update_iter->path().string() + "/Mod_Info.cfg";
1300                        if ( !boost::iequals(update_iter->path().filename(),"Edition")
1301                                && !boost::iequals(update_iter->path().filename(),"Edition-patch")
1302                                && is_directory( update_iter->path() ) 
1303                                && exists( update_iter->path().string() + "/Mod_Info.cfg" ) ) 
1304                        {
1305                                bool update = 0;
1306                                fstream file;
1307                                file.open( (update_iter->path().string() + "/Mod_Info.cfg").c_str());   
1308                                if (!file.fail())
1309                                {
1310                                        updatePackage = fileToModPackage(file, update_iter->path().filename());
1311                                }
1312                                else 
1313                                {
1314                                        file.close();
1315                                        continue;
1316                                }
1317                                file.close();
1318                                file.clear();
1319                                if(exists(strPathToPackages + "/" + update_iter->path().filename() + "/Mod_Info.cfg"))
1320                                {
1321                                file.open((strPathToPackages + "/" + update_iter->path().filename() + "/Mod_Info.cfg").c_str());
1322                                if (!file.fail())
1323                                {
1324                                        installedPackage = fileToModPackage(file, update_iter->path().filename());
1325                                        file.close();
1326                                        if(updatePackage.modStringVersion > installedPackage.modStringVersion) {
1327                                                update = 1;
1328                                        }
1329                                }
1330                                else
1331                                {
1332                                        file.close();
1333                                        update = 1;
1334                                }
1335                                file.close();
1336                                }
1337                                else update = 1;
1338                                if(update) {
1339                                        if(exists((path)(strPathToPackages +  "/" + updatePackage.modStringName)))
1340                                                remove_all((path)(strPathToPackages +  "/" + updatePackage.modStringName));                     
1341                                        rename((path)(pathToUpdate + "/" + updatePackage.modStringName), (path)(strPathToPackages + "/" + updatePackage.modStringName));
1342
1343                                }
1344                        }
1345                }
1346        }
1347        catch (exception & ex) {
1348                //      ex.what();
1349                setStatusArea("Warning, handled exception: " + (string)ex.what());
1350        }
1351}
1352
1353
1354bool ProcessThirdPartyUpdates() {
1355CrawlPackages( "../updates",  "./packages");
1356return true;
1357        //      globalPackages = getPackages();
1358//      refreshMods(globalInstalledMods);
1359}
1360
1361
1362bool ProcessAEUpdate(Install_info_cfg *currentAE, Install_info_cfg *updateAE, bool *installerJustUpdated)
1363{
1364        fstream file;
1365        string line;
1366        vector<string> tokens, updateStarted;
1367        string strInstaller = "Installer";
1368        string strWas = "was";
1369        string strPathToEUFN = ("../updates/" + strEUFN + "/"); // strEUFN is set by GetUpdateStatus()
1370        string strPathToEUFNInstall = ("../updates/" + strEUFN + "/install/");
1371        string strPathToEUFNPackages = ("../updates/" + strEUFN + "/install/packages/");
1372        string strPathToPackages = "packages/";
1373        string strGlobalize = "Globalize/";
1374        string strOniSplit = "OniSplit.exe";
1375        string strDaodan = "binkw32.dll";
1376        string strWinGUI = "onisplit_gui.exe";
1377        string strWinGUILang = "ospgui_lang.ini";
1378        string strMacGUI = "AETools.app";
1379#ifdef WIN32
1380        string strOniApp = "Oni.exe";
1381#else
1382        string strOniApp = "Oni.app";
1383#endif
1384        bool needNewTrashDir = false;
1385        bool readingVerAndDate = false;
1386       
1387#ifdef WIN32
1388        string strTrashDir = "Trash\\"; // string unused in Windows because files are simply deleted
1389#else
1390        FILE *fUserName = NULL;
1391        char chrUserName[32];
1392        fUserName = popen("whoami", "r");
1393        fgets(chrUserName, sizeof(chrUserName), fUserName);
1394        pclose(fUserName);
1395        string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1396        int endOfName = strUserName.find("\n", 0);
1397        string strTrashDir = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1398#endif
1399       
1400        // Write to log that we are beginning the update process
1401        ptime startTime(second_clock::local_time());
1402        string strStartTime = to_simple_string(startTime);
1403        string progressMsg = "\nEdition being updated to:\n" +
1404                                                 updateAE->AEVersion + " on " + strStartTime;
1405        file.open("Update.log");
1406        if (!file.fail())
1407                file << progressMsg.c_str();
1408       
1409        if (*installerJustUpdated) // then we want to know what folder in the Trash the Installer was placed in...
1410        {
1411                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
1412                {
1413                        getline(file, line);
1414                        tokenize(line, tokens);
1415                       
1416                        if (tokens.capacity() >= 4)
1417                                if (!strInstaller.compare(tokens[0]))
1418                                        if (!strWas.compare(tokens[1]))
1419                                                readingVerAndDate = true;
1420                        if (readingVerAndDate && tokens.capacity() >= 3)
1421                                tokenize(tokens[2], updateStarted, "-");
1422                }
1423                if (updateStarted.capacity() < 3)
1424                        needNewTrashDir = true;
1425                else
1426                {
1427                        strTrashDir = strTrashDir + "Old_Edition_files_" + currentAE->AEVersion + "-" +
1428                                                  updateStarted[0] + "-" + updateStarted[1] + "-" + updateStarted[2] + "/";
1429                        if (!exists(strTrashDir))
1430                                needNewTrashDir = true;
1431                }
1432        }
1433#ifndef WIN32
1434        if (!*installerJustUpdated || needNewTrashDir) // prepare a new directory for deleted files to go to
1435        {
1436                tm tmStartTime = to_tm(startTime);
1437                strTrashDir = strTrashDir + "Old_Edition_files_" + currentAE->AEVersion + "_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1438                                          boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec) + "/";
1439                create_directory(strTrashDir);
1440        }
1441#endif
1442        file.close();
1443        file.clear();
1444
1445        // Special code to replace our special files -- the Oni app, OniSplit, the Daodan DLL, and the GUI for OniSplit
1446        if (exists(strPathToEUFN + strOniApp))
1447        {
1448                if (exists(strOniApp))
1449                        rename((path)strOniApp, (path)(strTrashDir + strOniApp));
1450                rename((path)(strPathToEUFN + strOniApp), (path)strOniApp);
1451        }
1452        if (updateAE->OniSplitVersion.compare(currentAE->OniSplitVersion) >= 1)
1453        {
1454                if (exists(strPathToEUFNInstall + strOniSplit))
1455                {
1456                        if (exists(strOniSplit))
1457                                rename((path)strOniSplit, (path)(strTrashDir + strOniSplit));
1458                        rename((path)(strPathToEUFNInstall + strOniSplit), (path)strOniSplit);
1459                }
1460        }
1461#ifdef WIN32
1462        if (updateAE->DaodanVersion.compare(currentAE->DaodanVersion) >= 1)
1463        {
1464                if (exists(strPathToEUFN + strDaodan))
1465                {
1466                        if (exists(("../" + strDaodan)))
1467                                rename((path)("../" + strDaodan), (path)(strTrashDir + strDaodan));
1468                        rename((path)(strPathToEUFN + strDaodan), (path)("../" + strDaodan));
1469                }
1470        }
1471        if (updateAE->WinGUIVersion.compare(currentAE->WinGUIVersion) >= 1)
1472        {
1473                if (exists(strPathToEUFNInstall + strWinGUI))
1474                {
1475                        if (exists((path)strWinGUI))
1476                                rename((path)strWinGUI, (path)(strTrashDir + strWinGUI));
1477                        if (exists(strWinGUILang))
1478                                rename((path)strWinGUILang, (path)(strTrashDir + strWinGUILang));
1479                        rename((path)(strPathToEUFNInstall + strWinGUI), (path)strWinGUI);
1480                        rename((path)(strPathToEUFNInstall + strWinGUILang), (path)strWinGUILang);
1481                }
1482        }
1483#else
1484        if (updateAE->MacGUIVersion.compare(currentAE->MacGUIVersion) >= 1)
1485        {
1486                if (exists(strPathToEUFN + strMacGUI))
1487                {
1488                        if (exists(("../" + strMacGUI)))
1489                                rename((path)("../" + strMacGUI), (path)(strTrashDir + strMacGUI));
1490                        rename((path)(strPathToEUFN + strMacGUI), (path)("../" + strMacGUI));
1491                }
1492        }
1493#endif
1494       
1495        // Now we trash whatever's in DeleteList; this allows us to clear out obsolete files in the previous AE install
1496        // Before moving a file to the Trash, we need to make sure each of the file's parent paths exists in the Trash...
1497        // ...so we iterate through the hierarchy of the file path, checking for each one and creating it if necessary
1498        for (vector<string>::iterator iter = updateAE->deleteList.begin(); iter != updateAE->deleteList.end(); iter++)
1499        {
1500                string thePath = *iter;
1501                if (exists((path)("../" + thePath)))
1502                {
1503                        string aParentPath;
1504                        string::size_type curPos = thePath.find("/", 0);
1505                        if (curPos != string::npos)
1506                                aParentPath = thePath.substr(0, curPos);
1507                        string::size_type lastPos = curPos;
1508                        while (curPos != string::npos && curPos < thePath.size())
1509                        {
1510                                aParentPath = aParentPath + thePath.substr(lastPos, curPos - lastPos);
1511                                if (!exists(strTrashDir + aParentPath))
1512                                        create_directory(strTrashDir + aParentPath);
1513                                lastPos = curPos + 1;
1514                                curPos = thePath.find("/", lastPos);
1515                                aParentPath = aParentPath + "/";
1516                        }
1517#ifndef WIN32
1518                        rename((path)("../" + thePath), (path)(strTrashDir + thePath));
1519#else
1520                        remove((path)("../" + thePath));
1521#endif
1522                }
1523        }
1524       
1525        ProcessPackageUpdates(strPathToEUFNPackages, strPathToPackages);
1526       
1527        // 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...
1528        // ...and folders which do not exist in the current AE will be created there
1529        vector<string> foldersToMake, filesToMove;
1530        string thePath;
1531        for (recursive_directory_iterator dir_itr(strPathToEUFNPackages + strGlobalize), end_itr; dir_itr != end_itr; ++dir_itr)
1532        {
1533                thePath = dir_itr->path().string();
1534                MakePathLocalToGlobalize(&thePath);
1535                if (is_regular_file(dir_itr->status()))
1536                {
1537                        if (dir_itr->filename().at(0) != '.') // skip over dot-files, which are invisible in Unix
1538                                filesToMove.push_back(thePath);
1539                }
1540                else if (is_directory(dir_itr->status()))
1541                {
1542                        if (!exists(strPathToPackages + strGlobalize + thePath))
1543                                foldersToMake.push_back(thePath);
1544                }
1545        }
1546        // Sort the foldersToMake strings by length, which is a fast solution to the problem of "How do we make sure we create folder 'parent/'...
1547        // ...before folder 'parent/child/'"?
1548        sort(foldersToMake.begin(), foldersToMake.end(), SortBySize); // SortBySize is a custom comparison function found later in this source file
1549        // First make the folders that don't exist in the current AE, so all the files have a place to go
1550        for (vector<string>::iterator iter = foldersToMake.begin(); iter != foldersToMake.end(); iter++)
1551        {
1552                create_directory(strPathToPackages + strGlobalize + *iter);
1553        }
1554        for (vector<string>::iterator iter = filesToMove.begin(); iter != filesToMove.end(); iter++)
1555        {
1556                if (exists(strPathToPackages + strGlobalize + *iter))
1557                        rename((path)(strPathToPackages + strGlobalize + *iter), (path)(strTrashDir + *iter));
1558                rename((path)(strPathToEUFNPackages + strGlobalize + *iter), (path)(strPathToPackages + strGlobalize + *iter));
1559        }
1560       
1561        // Clean up after ourselves, trashing any packages or programs in the update package that are not newer than the current AE
1562        create_directory(strTrashDir + "Unneeded update files");
1563        rename((path)strPathToEUFN, (path)(strTrashDir + "Unneeded update files/" + strEUFN));
1564       
1565        // Write to log that we are finished with update
1566        ptime end_time(second_clock::local_time());
1567        string progressMsg2 = "Edition was updated to:\n" +
1568                                                  updateAE->AEVersion + " on " + to_simple_string(end_time);
1569       
1570        file.open("Update.log");
1571       
1572        if(!file.fail())
1573                file.write(progressMsg2.c_str(), sizeof(progressMsg2.c_str()));
1574       
1575        file.close();
1576        file.clear();
1577       
1578        if (updateAE->globalizationRequired)
1579                CheckForGlobalization(true); // the 'true' value forces re-globalization
1580       
1581        globalPackages = getPackages(); // refresh the list in memory
1582        // TODO: Refresh the packages list in the window
1583
1584        return true;
1585}
1586
1587void ProcessPackageUpdates(string pathToUpdate, string strPathToPackages)
1588{
1589        ptime startTime(second_clock::local_time());
1590#ifdef WIN32
1591        string strTrashDir = "Trash\\"; // string unused in Windows because files are simply deleted
1592#else
1593        FILE *fUserName = NULL;
1594        char chrUserName[32];
1595        fUserName = popen("whoami", "r");
1596        fgets(chrUserName, sizeof(chrUserName), fUserName);
1597        pclose(fUserName);
1598        string strUserName = (string)chrUserName; // stringsblaaarrrgggghhhh
1599        int endOfName = strUserName.find("\n", 0);
1600        string strTrashDir = "/Users/" + strUserName.substr(0, endOfName) + "/.Trash/";
1601        bool needNewTrashDir = true;
1602        tm tmStartTime = to_tm(startTime);
1603#endif
1604       
1605        try
1606        {
1607                directory_iterator end;
1608                for (directory_iterator update_iter(pathToUpdate); update_iter != end; ++update_iter)
1609                {
1610                        ModPackage installedPackage, updatePackage;
1611                        string updtPath = update_iter->path().string();
1612                        string updtFolder = update_iter->path().filename();
1613                        string updtModInfo = updtPath + "/Mod_Info.cfg";
1614                        string instModInfo = strPathToPackages + "/" + updtFolder + "/Mod_Info.cfg";
1615                        if (!boost::iequals(updtFolder, "Edition")
1616                                && !boost::iequals(updtFolder, "Edition-patch")
1617                                && is_directory(update_iter->path()) 
1618                                && exists(updtModInfo)) 
1619                        {
1620                                fstream file;
1621                                file.open((updtModInfo).c_str());       
1622                                if (!file.fail())
1623                                        updatePackage = fileToModPackage(file, updtFolder);
1624                                else
1625                                {
1626                                        file.close();
1627                                        continue;
1628                                }
1629                                if (exists(instModInfo))
1630                                {
1631                                        file.close();
1632                                        file.clear();
1633                                        file.open(instModInfo.c_str());
1634                                        if (!file.fail())
1635                                        {
1636                                                installedPackage = fileToModPackage(file, updtFolder);
1637                                                file.close();
1638                                                if (updatePackage.modStringVersion > installedPackage.modStringVersion)
1639                                                {
1640                                                        if (updatePackage.installerVersion <= INSTALLER_VERSION)
1641                                                        {
1642#ifdef WIN32
1643                                                                remove_all((path)(strPathToPackages +  "/" + installedPackage.modStringName));
1644#else
1645                                                                if (needNewTrashDir)
1646                                                                {
1647                                                                        strTrashDir = strTrashDir + "Old_packages_" + boost::lexical_cast<string>(tmStartTime.tm_hour) + "-" +
1648                                                                                                  boost::lexical_cast<string>(tmStartTime.tm_min) + "-" + boost::lexical_cast<string>(tmStartTime.tm_sec) + "/";
1649                                                                        create_directory(strTrashDir);
1650                                                                        needNewTrashDir = false;
1651                                                                }
1652                                                                rename((path)(strPathToPackages +  "/" + installedPackage.modStringName), (path)(strTrashDir + installedPackage.modStringName));
1653#endif
1654                                                                rename((path)(pathToUpdate + "/" + updatePackage.modStringName), (path)(strPathToPackages + "/" + updatePackage.modStringName));
1655                                                        }
1656                                                }
1657                                        }
1658                                        else
1659                                                file.close();
1660                                }
1661                                file.close();
1662                                file.clear();
1663                        }
1664                }
1665        }
1666        catch (exception & ex)
1667        {
1668                setStatusArea("Warning, handled exception: " + (string)ex.what());
1669        }
1670}
1671
1672/* MakePathLocalToGlobalize is a function used once by ProcessAEUpdate() that takes a file in an        \
1673|  update's Globalize folder and changes its path, originally relative to the Installer, to be          |
1674|  relative to the structure of the Globalize folder; this makes it easier to have the Installer        |
1675\  move said file from an update's Globalize folder to the current Globalize folder.               */
1676void MakePathLocalToGlobalize(string *installerBasedPath)
1677{
1678        int deleteToHere = 0;
1679        deleteToHere = installerBasedPath->find("Globalize/");
1680        if (deleteToHere != 0)
1681        {
1682                deleteToHere += strlen("Globalize/");
1683                installerBasedPath->erase(0, deleteToHere);
1684        }
1685}
1686
1687/* SortBySize is a custom comparison function that we call when using the C++ sort() function in \
1688\  ProcessAEUpdate() on some strings that we want to sort by length.                                                    */
1689bool SortBySize(string a, string b)
1690{
1691        return (a.size() < b.size());
1692}
1693
1694//stolen token function...
1695void tokenize(const string& str, vector<string>& tokens, const string& delimiters)
1696{
1697        // Skip delimiters at beginning.
1698        string::size_type lastPos = str.find_first_not_of(delimiters, 0);
1699        // Find first "non-delimiter".
1700        string::size_type pos     = str.find_first_of(delimiters, lastPos);
1701       
1702        while (string::npos != pos || string::npos != lastPos)
1703        {
1704                // Found a token, add it to the vector.
1705                tokens.push_back(str.substr(lastPos, pos - lastPos));
1706                // Skip delimiters.  Note the "not_of"
1707                lastPos = str.find_first_not_of(delimiters, pos);
1708                // Find next "non-delimiter"
1709                pos = str.find_first_of(delimiters, lastPos);
1710        }
1711}
1712
1713/* StripNewlines() gets rids of any linebreaks that come from text returned by getline(); \
1714|  getline() should be stripping those out, but Windows CR/LF files seem to be sneaking   |
1715\  some extra return characters into strings in the ReadInstallInfoCfg() function.               */
1716void StripNewlines(string *theLine)
1717{
1718        int deleteFromHere = 0;
1719        deleteFromHere = theLine->find("\r");
1720        if (deleteFromHere > 0)
1721                theLine->erase(deleteFromHere, theLine->size());
1722}
1723
1724void clearOldDats(void) {
1725        directory_iterator end_iter_gdf;
1726        for ( directory_iterator dir_itr_gdf( "../GameDataFolder" );
1727                 dir_itr_gdf != end_iter_gdf;
1728                 ++dir_itr_gdf )
1729        {
1730                if ( dir_itr_gdf->path().extension() == ".dat" || dir_itr_gdf->path().extension() == ".raw" || dir_itr_gdf->path().extension() == ".sep" ) {
1731                        remove( dir_itr_gdf->path() );
1732                }
1733               
1734        }
1735       
1736}
1737
1738// this function copies files and directories. If copying a
1739// directory to a directory, it copies recursively.
1740
1741//pardon the mess, I did this at midnight, and had to fix a bug
1742void copy( const path & from_ph, 
1743                  const path & to_ph ) 
1744{ 
1745        cout << to_ph.string() << "\n";
1746        // Make sure that the destination, if it exists, is a directory
1747        if((exists(to_ph) && !is_directory(to_ph)) || (!exists(from_ph))) cout << "error";
1748        if(!is_directory(from_ph)) 
1749        { 
1750               
1751                if(exists(to_ph)) 
1752                { 
1753                        copy_file(from_ph,to_ph/from_ph.filename()); 
1754                } 
1755                else 
1756                { 
1757                        try{
1758                               
1759                                copy_file(from_ph,to_ph);
1760                        }
1761                        catch (exception ex){
1762                                cout << from_ph.string() << " to " << to_ph.string() << "\n";
1763                        }
1764                }
1765               
1766        } 
1767        else if(from_ph.filename() != ".svn")
1768        { 
1769                path destination; 
1770                if(!exists(to_ph)) 
1771                { 
1772                        destination=to_ph; 
1773                } 
1774                else 
1775                { 
1776                        destination=to_ph/from_ph.filename(); 
1777                } 
1778               
1779                for(directory_iterator i(from_ph); i!=directory_iterator(); ++i) 
1780                { 
1781                        //the idiot who coded this in the first place (not me)
1782                        //forgot to make a new directory. Exception city. x_x
1783                        create_directory(destination); 
1784                        copy(*i,destination/i->filename()); 
1785                } 
1786        } 
1787} 
1788
1789void copy_directory( const path &from_dir_ph, 
1790                                        const path &to_dir_ph) 
1791{ 
1792        if(!exists(from_dir_ph) || !is_directory(from_dir_ph) 
1793           || exists(to_dir_ph)) 
1794                cout << !exists(from_dir_ph) << " " << !is_directory(from_dir_ph) 
1795                << " " << exists(to_dir_ph);
1796       
1797# ifdef BOOST_POSIX
1798        struct stat from_stat; 
1799        if ( (::stat( from_dir_ph.string().c_str(), &from_stat ) != 0) 
1800                || ::mkdir(to_dir_ph.native_directory_string().c_str(), 
1801                                   from_stat.st_mode)!=0) 
1802# endif
1803                } 
1804
1805string escapePath(string input)
1806{
1807        string output;
1808        string escape_me = "& ;()|<>\"'\\#*?$";
1809        for (unsigned int i = 0; i < input.size(); i++)
1810        {
1811                for (unsigned int j = 0; j < escape_me.size(); j++)
1812                        if (input[i] == escape_me[j])
1813                                output += '\\';
1814                output += input[i];
1815        }
1816        return output;
1817}
1818
1819Install_info_cfg::Install_info_cfg()
1820{
1821        AEVersion = "2009-07b";
1822        InstallerVersion = "1.0.1";
1823        DaodanVersion = "1.0";
1824        OniSplitVersion = "0.9.38.0";
1825        WinGUIVersion = "0";
1826        MacGUIVersion = "0";
1827        patch = false;
1828        globalizationRequired = false;
1829        deleteList.reserve(255);
1830}
1831
1832ModPackage::ModPackage()
1833{
1834        isInstalled = true; // replace with function
1835        name = "";
1836        modStringName = "";
1837        modStringVersion = 0;
1838        platform = "Both";
1839        hasOnis = false;
1840        hasDeltas = false;
1841        hasBSL = false;
1842        hasAddon = false;
1843        hasDats = false;
1844        category = "";
1845        creator = "";
1846        isEngine = false;
1847        readme = "";
1848        globalNeeded = true;
1849}
1850#ifndef WIN32
1851void Sleep(int ms)
1852{
1853        sleep(ms / 1000);
1854}
1855#endif
1856#ifdef WIN32
1857
1858void RedirectIOToConsole()
1859{
1860        int hConHandle; 
1861        long lStdHandle;
1862        CONSOLE_SCREEN_BUFFER_INFO coninfo;
1863        FILE *fp;
1864       
1865        // allocate a console for this app
1866        AllocConsole();
1867       
1868        // set the screen buffer to be big enough to let us scroll text
1869        GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), 
1870                                                           &coninfo);
1871        coninfo.dwSize.Y = MAX_CONSOLE_LINES;
1872        SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), 
1873                                                           coninfo.dwSize);
1874       
1875        // redirect unbuffered STDOUT to the console
1876        lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
1877        hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1878        fp = _fdopen( hConHandle, "w" );
1879        *stdout = *fp;
1880        setvbuf( stdout, NULL, _IONBF, 0 );
1881       
1882        // redirect unbuffered STDIN to the console
1883        lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
1884        hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1885        fp = _fdopen( hConHandle, "r" );
1886        *stdin = *fp;
1887        setvbuf( stdin, NULL, _IONBF, 0 );
1888       
1889        // redirect unbuffered STDERR to the console
1890        lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
1891        hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
1892        fp = _fdopen( hConHandle, "w" );
1893        *stderr = *fp;
1894        setvbuf( stderr, NULL, _IONBF, 0 );
1895       
1896        // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
1897        // point to console as well
1898        ios::sync_with_stdio();
1899}
1900#endif
Note: See TracBrowser for help on using the repository browser.