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

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

fix?

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