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

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

Allowed single packages to be updated
Changed the modversion to be a float
Fixed a possible crash on Macs
Fixed batch file to move instead of copy

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