Subversion Repositories spk

Rev

Rev 297 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

/*
 SPKInstall V1.00 Created by Cycrow (Matthew Gravestock)
*/

// Main Spk File Library Include
#ifdef _WIN32
#include <spk.h>
#include <StringList.h>
#else
#include "../spk/spk.h"
#endif
#include <time.h>

#ifdef _WIN32
#include <windows.h>
#include <direct.h>
#include <shlobj.h>
#endif

#include <Package/InstallText.h>

#define BETA 1

class CProgressConsole : public CProgressInfo
{
public:
        CProgressConsole() : CProgressInfo()
        {
                m_iCount = 0;
                m_fNextPercent = 0.0f;
        }

        void Finish(bool newline = true)
        {
                for ( int i = m_iCount; i < 20; i++ )
                        printf ( "*" );
                if ( newline )
                        printf ( "\n");
                m_fNextPercent = 0.0f;
                m_iCount = 0;
        }

protected:
        virtual void ProgressUpdated ( const long cur, const long max )
        {
                float percent = ((float)cur / (float)max) * 100.0f;
                if ( m_bDoHalf )
                {
                        percent /= 2.0f;
                        if ( m_bSecondHalf )
                                percent += 50.0f;
                        else if ( percent > 50.0f )
                                percent = 50.0f;
                }
                if ( (percent - m_fNextPercent) >= 5.0f )
                {
                        printf ( "*" );
                        m_fNextPercent += 5.0f;
                        ++m_iCount;
                }
        }
        virtual void DoingFile ( C_File *file )
        {
        }

private:
        float m_fNextPercent;
        int   m_iCount;
};

#define FLAGS L"[-voctm][-d destination][-l langid]"

Utils::WString  g_dir;
bool    g_debug = false;
bool    g_force = false;
int             g_indent = 0;
/*
        Func:   GetInput
        Desc:   Gets an input from the user, ie, any settings required to be typed in
*/
Utils::WString GetInput ()
{
//      g_read = true;

        Utils::WString line;
        char c = getchar();

        while ( (c != '\n') && (c != '\0') )
        {
                line += Utils::WString(c);
                c = getchar();
        }

        return line;
}

void PrintSyntax(const Utils::WString &cmd)
{
        wprintf(L"Syntax: %s %s </command> [arguments]\n", cmd.c_str(), FLAGS );
        wprintf(L"\nCommands:\n" );
        wprintf(L"   /list\n\t- Lists installed packages\n" );
        wprintf(L"   /install <file>\n\t- Installs a package file\n" );
        wprintf(L"   /uninstall <package#>\n\t- Uninstalls a package, use id number from list\n" );
        wprintf(L"   /enable <package#>\n\t- Enables an installed package\n" );
        wprintf(L"   /disable <package#>\n\t- Disables an installed package\n" );
        wprintf(L"   /removeuninstall\n\t- Removes uninstall scripts\n" );
        wprintf(L"   /removeshared\n\t- Removes unused sharded files\n" );
        wprintf(L"\nSwitchs:\n" );
        wprintf(L"   -d (--directory) [directory]\n\tChange destination directory, otherwise uses current\n\n" );
        wprintf(L"   -v (--verbose)\n\tTurns on verbose mode\n\n" );
        wprintf(L"   -o (--override)\n\tOverride install warnings\n\tIE. allows you to install older scripts\n\n" );
        wprintf(L"   -t (--textrename)\n\tForces text file renaming for installed packages\n\n" );
        wprintf(L"   -l (--language) <language>\n\tSets the language id for text file renaming\n\totheriwse reads game lang.dat\n\n" );
        wprintf(L"   -c (--enablechild)\n\tAuto Enabled all children when parent is enabled\n\n" );
        wprintf(L"   -m (--forcemod)\n\tForces a mod enabled even if theres one already enabled\n\n" );
}

void DisplayPackage(CBaseFile *p, int indent, int language)
{
        Utils::WString version = p->version();
        if ( version.lower()[0] != 'v' )
                version.prepend(L"v");

        printf ( "  [%5d] ", p->GetNum() + 1 );

        if ( indent > g_indent )
        {
                printf (" \\->");
        }
        for ( int i = 0; i < indent; i++ )
                printf("\t");

        g_indent = indent;

        if ( !p->IsEnabled() )
                printf("[D] ");

        wprintf(L"%s %s by %s\n", p->name(language).c_str(), version.c_str(), p->author().c_str() );
}

void DoAllChildren(CPackages *packages, CBaseFile *p, CLinkList<CBaseFile> *doneList, int indent)
{
        CLinkList<CBaseFile> children;
        if ( packages->GetChildPackages(p, &children) )
        {
                for ( CBaseFile *child = children.First(); p; p = children.Next() )
                {
                        DisplayPackage(child, indent, packages->GetLanguage());
                        doneList->push_back(child);

                        DoAllChildren(packages, child, doneList, indent + 1);
                }
        }
}

void ListPackages(CPackages *packages)
{
        CProgressConsole progress;

        CLinkList<CBaseFile> doneList;

        g_indent = 0;
        printf ( "\nPackages:\n" );
        for ( CBaseFile *p = packages->PackageList()->First(); p; p = packages->PackageList()->Next() )
        {
                // already done?
                if ( doneList.FindData(p) )
                        continue;

                if ( p->GetType() != TYPE_SPK )
                        continue;

                DisplayPackage(p, 0, packages->GetLanguage());
                doneList.push_back(p);

                // find all children
                DoAllChildren(packages, p, &doneList, 1);
        }
}

size_t SplitArguments(char **argv, int argc, int start, Utils::WStringList *argList)
{
        for ( int i = start; i < argc; i++ )
        {
                Utils::WString arg = argv[i];
                if (!arg.empty())
                        argList->pushBack(arg);
        }

        return argList->size();
}

Utils::WString InstallPackage(const Utils::WStringList &lArguments, Utils::WStringList *errors, CPackages *packages, bool disabled)
{
        CProgressConsole progress;

        int error;

        if (lArguments.empty())
                return Utils::WString::Null();

        // append spk on the end
        for (auto itr = lArguments.begin(); itr != lArguments.end(); itr++)
        {
                if (!CFileIO::Exists((*itr)->str))
                {
                        if (CFileIO((*itr)->str).extension().lower() != L"spk")
                                (*itr)->str += L".spk";
                }
        }

        CLinkList<CBaseFile> lPackages;

        // open the package file
        printf ( "  - Opening Package                \n" );
        for (auto itr = lArguments.begin(); itr != lArguments.end(); itr++)
        {
                Utils::WString spkFilename = (*itr)->str;

                if ( spkFilename.length() > 30 )
                        wprintf(L"    ..%28s ", spkFilename.right(28).c_str() );
                else
                        wprintf(L"    %30s ", spkFilename.right(30).c_str() );

                CLinkList<CBaseFile> lPackageList;
                CBaseFile *package = packages->openPackage(spkFilename, &error, &progress);

                // multi packages
                if ( !package && error == INSTALLERR_NOMULTI )
                {
                        if ( !packages->openMultiPackage(spkFilename, &lPackageList, &error, &progress) )
                        {
                                printf ( "Error!\n");
                                continue;
                        }
                        progress.Finish();
                }

                else if ( package )
                {
                        progress.Finish();
                        lPackageList.push_back(package);
                }
                else
                {
                        printf ( "ERROR!  " );
                        switch ( error )
                        {
                                case INSTALLERR_OLD:
                                        printf ( "File is in old format no longer supported" );
                                        break;
                                case INSTALLERR_NOEXIST:
                                        printf ( "file doesn't exist" );
                                        break;
                                case INSTALLERR_INVALID:
                                        printf ( "Invalid package file" );
                                        break;
                                case INSTALLERR_NOSHIP:
                                        printf ( "Ship Packages are currently not supported" );
                                        break;
                                case INSTALLERR_VERSION:
                                        printf ( "Package file was created in a newer version, unable to open" );
                                        break;
                        }
                        printf ( "\n");
                        continue;
                }

                for ( CListNode<CBaseFile> *pNode = lPackageList.Front(); pNode; pNode = pNode->next() )
                {
                        CBaseFile *package = pNode->Data();

                        // compare versions
                        Utils::WString packageName = package->getFullPackageName(packages->GetLanguage());

                        int checkFlags = IC_ALL;
                        int check = packages->PrepareInstallPackage(package, (disabled) ? true : !package->IsEnabled(), false, checkFlags);

                        switch (check)
                        {
                                case INSTALLCHECK_OLDVERSION:
                                        wprintf(L"Newer version of \"%s\" already installed", packageName.c_str() );
                                        if ( !g_force )
                                        {
                                                printf ( ", Unable to install older, use -o to force installation\n" );
                                                continue;
                                        }
                                        else
                                        {
                                                printf ( ", Overriding install\n" );
                                                if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
                                                        continue;
                                                break;
                                        }
                                        break;
                                        // wait for the rest to be added
                                case INSTALLCHECK_WRONGGAME:
                                        wprintf ( L"ERROR! \"%s\" Wrong Game (Requires: %s)", packageName.c_str(), packages->getGameTypesString(package, false).c_str() );
                                        if ( g_force )
                                        {
                                                printf ( " [FORCED]\n" );
                                                if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
                                                        continue;
                                        }
                                        else
                                        {
                                                printf("\n");
                                                continue;
                                        }
                                        break;

                                case INSTALLCHECK_WRONGVERSION:
                                        wprintf ( L"ERROR! \"%s\" Wrong Game Version (Requires: %s)\n", packageName.c_str(), packages->getGameVersionString(package).c_str() );
                                        if ( g_force )
                                        {
                                                printf ( " [FORCED]\n" );
                                                if ( packages->PrepareInstallPackage(package, disabled, true) != INSTALLCHECK_OK )
                                                        continue;
                                        }
                                        else
                                        {
                                                printf("\n");
                                                continue;
                                        }
                                        break;
                        }

                        if ( package->installText()->any() )
                        {
                                Utils::WString installtext = packages->getInstallBeforeText(package);
                                if ( !installtext.empty() )
                                {
                                        installtext = installtext.stripHtml();
                                        wprintf(L"Installing %s: %s\n", packageName.c_str(), installtext.c_str() );
                                        printf ( "Do you want to continue with the install? " );

                                        if ( g_force )
                                                printf ( "(FORCED)\n" );
                                        else
                                        {
                                                Utils::WString input = GetInput().lower();

                                                if ( input != "y" && input != "yes" )
                                                {
                                                        printf ( "\nInstallion aborted!!\n\n" );
                                                        packages->RemovePreparedInstall(package);
                                                        continue;
                                                }
                                        }
                                }
                        }

                        lPackages.push_back(package);
                }
        }

        // is there any that couldn't install
        CLinkList<CBaseFile> lCheckPackages;
        if ( packages->CheckPreparedInstallRequired(&lCheckPackages) )
        {
                printf ( "\nError! Some packages are missing dependacies:\n" );
                for ( CListNode<CBaseFile> *pNode = lCheckPackages.Front(); pNode; pNode = pNode->next() )
                {
                        CSpkFile *spk = (CSpkFile *)pNode->Data();
                        wprintf(L"\t%s V%s by %s (Requires: %s by %s)\n", spk->name(packages->GetLanguage()).c_str(), spk->version().c_str(), spk->author().c_str(), spk->otherName().c_str(), spk->otherAuthor().c_str());
                }
        }

        // no packages will be installed
        if ( packages->GetNumPackagesInQueue() < 1 )
                return Utils::WString::Null();

        // install the package file
        printf ( "  - Installing                     " );
        CLinkList<CBaseFile> erroredPackages;
        if ( packages->installPreparedPackages(errors, &progress, &erroredPackages) )
                progress.Finish();
        else
        {
                printf ( "ERROR!\n" );
                return Utils::WString::Null();
        }

        // delete any errored packages
        for ( CListNode<CBaseFile> *pNode = erroredPackages.Front(); pNode; pNode = pNode->next() )
        {
                lPackages.remove(pNode->Data());
                pNode->DeleteData();
        }

        // now display the packages
        Utils::WString retStr = L"Packages Installed:\n";
        for ( CListNode<CBaseFile> *pNode = lPackages.Front(); pNode; pNode = pNode->next() )
        {
                CBaseFile *package = pNode->Data();

                retStr += L"  <> ";
                retStr += package->getFullPackageName(packages->GetLanguage());
                retStr += L"\n";

                if ( !packages->getInstallAfterText(package).empty() )
                {
                        Utils::WString afterText = packages->getInstallAfterText(package).stripHtml();
                        afterText = afterText.findReplace(L"\n", L"\n\t");
                        retStr += L"\t";
                        retStr += afterText;
                        retStr += L"\n";
                }
        }

        return retStr;
}

CBaseFile *FindPackage(int packageNum, CPackages *packages)
{
        for ( CBaseFile *p = packages->PackageList()->First(); p; p = packages->PackageList()->Next() )
        {
                if ( p->GetNum() == (packageNum - 1) )
                        return p;
        }

        return 0;
}

bool UninstallPackage(int uninstallNum, Utils::WStringList *errors, CPackages *packages, Utils::WString &endMessage)
{
        CBaseFile *p = FindPackage(uninstallNum, packages);
        if ( !p )
                return false;

        // lets check for the uninstall text
        Utils::WString uText = packages->getUninstallBeforeText(p).stripHtml();
        if (!uText.empty())
        {
                wprintf(L"Uninstalling: %s\n", uText.c_str() );
                printf ( "Do you wish to continue with the uninstall? " );
                if ( g_force )
                        printf ( "(FORCED)\n" );
                else
                {
                        Utils::WString input = GetInput().lower();
                        if ( input != "y" && input != "yes" )
                        {
                                printf ( "\nUninstallation has been aborted!!\n" );
                                return false;
                        }
                }
        }

        CProgressConsole progress;

        endMessage = L"Uninstalled: " + p->getFullPackageName(packages->GetLanguage());
        // add the uninstall after text
        uText = packages->getUninstallAfterText(p).stripHtml();
        if (!uText.empty())
        {
                endMessage += L"\n\n";
                endMessage += uText;
                endMessage += L"\n";
        }

        printf ( "  - Unistalling                    " );
        packages->PrepareUninstallPackage(p);
        if ( packages->uninstallPreparedPackages(errors, &progress) )
        {
                progress.Finish();
        }
        else
        {
                endMessage = L"";
                printf ( "ERROR!\n" );
                return false;
        }


        return true;
}

bool EnablePackage(int uninstallNum, Utils::WStringList *errors, CPackages *packages, Utils::WString &endMessage)
{
        CBaseFile *p = FindPackage(uninstallNum, packages);
        if ( !p )
                return false;

        CProgressConsole progress;

        endMessage = L"Enabled: " + p->getFullPackageName(packages->GetLanguage());

        printf ( "  - Enabling                       " );
        if ( packages->enablePackage(p, errors, &progress) )
        {
                progress.Finish();
        }
        else
        {
                int error = packages->GetError();
                endMessage = "";
                printf ( "ERROR! " );
                if ( error == PKERR_NOPARENT )
                        printf ( "Parent package is disabled" );
                printf ( "\n" );
                return false;
        }
        return true;
}

bool DisablePackage(int uninstallNum, Utils::WStringList *errors, CPackages *packages, Utils::WString &endMessage)
{
        CBaseFile *p = FindPackage(uninstallNum, packages);
        if ( !p )
                return false;

        CProgressConsole progress;

        endMessage = L"Disabled: " + p->getFullPackageName(packages->GetLanguage());

        printf ( "  - Disabling                      " );
        if ( packages->disablePackage(p, errors, &progress) )
        {
                progress.Finish();
        }
        else
        {
                endMessage = L"";
                printf ( "ERROR!\n" );
                return false;
        }
        return true;
}

void RemoveUninstallScripts(CPackages *packages, Utils::WStringList *errors)
{
        CProgressConsole progress;
        printf ( "  - Removing uninstall scripts     " );
        packages->removeUninstallScripts(errors, &progress);
        progress.Finish();
}

void RemoveUnusedShared(CPackages *packages, Utils::WStringList *errors)
{
        CProgressConsole progress;
        printf ( "  - Removing unused shared files   " );
        packages->removeUnusedSharedFiles(errors, &progress);
        progress.Finish();
}


void PrintDebug(Utils::WStringList *errors)
{
        if ( !g_debug )
                return;

        if (errors && errors->size())
                printf ( "\n");

        for(auto itr = errors->begin(); itr != errors->end(); itr++)
        {
                int errornum = (*itr)->data.toInt();
                Utils::WString rest = (*itr)->str.tokens(L" ", 2);

                Utils::WString err = FormatErrorString(errornum, rest);
                wprintf(L"  * %s\n", err.c_str());
        }

        if (errors && errors->size())
                printf ( "\n");
}




void Pause()
{
#ifdef _DEBUG
        char pause;
        scanf ( "%s", &pause );
#endif
}


int ParseCommandSwitchs(wchar_t c, Utils::WString &destination, CPackages *packages, int start, int *arg, char **argv)
{
        switch ( c )
        {
                case L'o':
                        g_force = true;
                        break;
                case L'v':
                        g_debug = true;
                        break;
                case L'd':
                        destination = argv[*arg];
                        destination = destination.findReplace("\\", "/");
                        ++(*arg);
                        ++start;
                        break;
                case L't':
                        packages->SetRenameText(true);
                        break;
                case L'l':
                        packages->SetLanguage(Utils::WString(argv[*arg]).toInt());
                        ++(*arg);
                        ++start;
                        break;
                case L'c':
                        packages->SetAutoEnable(true);
                        break;
                case L'm':
                        packages->SetForceModInstall(true);
                        break;
        }

        return start;
}

/*
TODO:
Additional Features
        Patch Mods
        Update Packages
*/

/*
        Main entry point to program
*/
int main ( int argc, char **argv )
{
        // display program header to command prompt
        printf ( "\nSPKInstall V0.90 (SPK Library Version %.2f) 18/10/2009 Created by Cycrow\n\n", GetLibraryVersion() );

        // parse the cmd name
        Utils::WString cmd (argv[0]);

        cmd = cmd.findReplace(L"\\", L"/");
        g_dir = cmd.tokens(L"/", 1, cmd.countToken(L"/") - 1);
        cmd = cmd.token(L"/", -1);

        if (g_dir.empty())
        {
            #ifdef _WIN32
                g_dir = Utils::WString(_getcwd(NULL, 0));
                #else
                g_dir = Utils::WString(getcwd(NULL, 0));
                #endif
                if (g_dir.empty())
                        g_dir = "./";
        }

        // not enough arguments, display the syntax and exit
        if ( argc < 2 )
        {
                PrintSyntax(cmd);
                Pause();
                exit ( 1 );
        }

        Utils::WString destination = g_dir;
        Utils::WStringList lErrors;

        // get the command flag
        Utils::WString command(argv[1]);
        command = command.lower();

        CPackages packages;
        Utils::WString myDoc = g_dir;
#ifdef _WIN32
        TCHAR pszPath[MAX_PATH];
        if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pszPath)))
                myDoc = (char *)pszPath;
#endif
        packages.startup(g_dir.c_str(), g_dir.c_str(), myDoc.c_str());

        int start = 2;
        // check for switchs
        while ( command[0] == '-' )
        {
                if ( argc < (start + 1) )
                {
                        PrintSyntax(cmd);
                        Pause();
                        exit ( 1 );
                }
                ++start;

                // single long commands
                int arg = 2;
                if ( command.left(2) == L"--" )
                {
                        Utils::WString cmd = command.right(-2);
                        cmd.toLower();

                        char c = 0;
                        if ( cmd == L"override" )
                                c = 'o';
                        else if ( cmd == L"verbose" )
                                c = 'v';
                        else if ( cmd == L"directory" )
                                c = 'd';
                        else if ( cmd == L"textrename" )
                                c = 't';
                        else if ( cmd == L"enablechild" )
                                c = 'c';
                        else if ( cmd == L"language" )
                                c = 'l';
                        else if ( cmd == L"forcemod" )
                                c = 'm';

                        if ( c )
                                start = ParseCommandSwitchs(c, destination, &packages, start, &arg, argv);
                }
                else
                {
                        // now parse arguments
                        for ( int i = 1; i < (int)command.length(); i++ )
                                start = ParseCommandSwitchs(command[i], destination, &packages, start, &arg, argv);
                }

                if ( argc < start )
                {
                        PrintSyntax(cmd);
                        exit( 1 );
                }
                command = argv[start - 1];
        }

        if ( command[0] == '/' )
        {
                wchar_t c = command[1];

                bool disabled = false;

                Utils::WString checkCmd = command.lower();
                if ( checkCmd == L"/install" )
                        c = L'i';
                else if ( checkCmd == L"/installdisable" )
                {
                        c = L'i';
                        disabled = true;
                }
                else if ( checkCmd == L"/uninstall" )
                        c = L'u';
                else if ( checkCmd == L"/enable" )
                        c = L'e';
                else if ( checkCmd == L"/disable" )
                        c = L'd';
                else if ( checkCmd == L"/list" )
                        c = L'l';
                else if ( checkCmd == L"/removeshared" )
                        c = L's';
                else if ( checkCmd == L"/removeunisntall" )
                        c = L'r';

                if ( c == L'i' || c == L'l' || c == L'u' || c == L'e' || c == L'd' || c == L'r' || c == L's' )
                {
                        Utils::WString endMessage;

                        wprintf(L"                                   |0              100|\n\n");
                        wprintf(L"  - Reading game directory         ");

                        CProgressConsole progress;

                        if ( packages.read(destination, &progress) )
                        {
                                packages.UpdatePackages();
                                packages.ReadGameLanguage(false);
                                progress.Finish(false);

                                Utils::WString gameName = packages.getGameName();
                                if ( packages.GetLanguage() || !gameName.empty())
                                {
                                        printf ( "\n\t" );
                                        if ( !gameName.empty() )
                                                wprintf ( L"Game: %s ", gameName.c_str());
                                        if ( packages.GetLanguage() )
                                                printf ( "(Language: %d)", packages.GetLanguage() );
                                }
                                printf ( "\n" );
                        }
                        else
                        {
                                printf ( "ERROR!\n" );
                                exit(1);
                        }

                        bool prepare = false;

                        packages.AssignPackageNumbers();

                        Utils::WStringList lArguments;
                        SplitArguments(argv, argc, start, &lArguments);

                        switch ( c )
                        {
                                case 'i':
                                        if ( argc <= start )
                                                wprintf(L"Syntax: %s [flags] /i <file>\n\tInstalls a package to the destination\n", cmd.c_str() );
                                        else
                                        {
                                                Utils::WString aftertext = InstallPackage(lArguments, &lErrors, &packages, disabled);
                                                if(!aftertext.empty())
                                                {
                                                        prepare = true;
                                                        endMessage = aftertext;
                                                }
                                                PrintDebug(&lErrors);
                                        }
                                        break;

                                case 'u':
                                        if ( argc <= start )
                                                wprintf(L"Syntax: %s [flags] /u <package#>\n\tUninstalls a package, package# is from the /l list command\n", cmd.c_str() );
                                        else
                                        {
                                                prepare = UninstallPackage(Utils::WString(argv[start]).toInt(), &lErrors, &packages, endMessage);
                                                PrintDebug(&lErrors);
                                        }
                                        break;

                                case 'e':
                                        if ( argc <= start )
                                                wprintf(L"Syntax: %s [flags] /u <package#>\n\tEnabled an installed package thats been disabled\n", cmd.c_str() );
                                        else
                                        {
                                                prepare = EnablePackage(Utils::WString(argv[start]).toInt(), &lErrors, &packages, endMessage);
                                                PrintDebug(&lErrors);
                                        }
                                        break;

                                case 'd':
                                        if ( argc <= start )
                                                wprintf(L"Syntax: %s [flags] /u <package#>\n\tDisabled an installed package\n", cmd.c_str() );
                                        else
                                        {
                                                prepare = DisablePackage(Utils::WString(argv[start]).toInt(), &lErrors, &packages, endMessage);
                                                PrintDebug(&lErrors);
                                        }
                                        break;

                                case 'l':
                                        ListPackages(&packages);
                                        break;

                                case 'r':
                                        RemoveUninstallScripts(&packages, &lErrors);
                                        endMessage = "Removed all unused uninstall scripts";
                                        break;

                                case 's':
                                        RemoveUnusedShared(&packages, &lErrors);
                                        endMessage = "Removed all unused shared files";
                                        break;
                        }

                        if ( prepare )
                        {
                                lErrors.clear();
                                printf ( "  - Preparing game directory       " );
                                if ( packages.closeDir(&lErrors, &progress, true) )
                                        progress.Finish();
                                else
                                {
                                        printf ( "ERROR!\n" );
                                        Pause();
                                        exit(1);
                                }

                                PrintDebug(&lErrors);
                        }
                        else
                                packages.RestoreFakePatch();

                        printf ( "\nDone!\n" );
                        if ( !endMessage.empty() )
                                wprintf(L"\n%s\n", endMessage.c_str() );
                }
                else
                        printf ( "Unknown Command: %c\n", c );
        }

        Pause();

        return 0;
}