Subversion Repositories spk

Rev

Rev 329 | 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>
#include "Utils/CommandLine.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][--dir:destination][--lang: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;
}

bool OpenDestination(Utils::CommandLine& cmd, const Utils::WString& destination)
{
        Utils::WString endMessage;

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

        CProgressConsole progress;

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

                Utils::WString gameName = packages.getGameName();
                if (packages.GetLanguage() || !gameName.empty())
                {
                        wprintf(L"\n\t");
                        if (!gameName.empty())
                                wprintf(L"Game: %s ", gameName.c_str());
                        if (packages.GetLanguage())
                                wprintf(L"(Language: %d)", packages.GetLanguage());
                }
                wprintf(L"\n");
                packages.AssignPackageNumbers();
                return true;
        }
        else
        {
                wprintf(L"ERROR!\n");
                wprintf(L"\nFailed to open destination directory: %s\n", destination.c_str());
                exit(1);
        }

        return false;
}

bool CloseDestination(Utils::CommandLine& cmd, bool isPrepare)
{
        CProgressConsole progress;
        Utils::WStringList lErrors;

        if (isPrepare)
                wprintf(L"  - Preparing game directory       ");
        else
                wprintf(L"  - Closing game directory         ");

        if (cmd.packages().closeDir(&lErrors, &progress, true))
                progress.Finish();
        else
        {
                wprintf(L"ERROR!\n");
                exit(1);
        }

        cmd.packages().RestoreFakePatch();

        wprintf(L"\nDone!\n");

        return true;
}


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"   info <package#>\n\t- Info about an installed package, use id number from list\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"   --dir:<directory>\n\tChange destination directory, otherwise uses current\n\n" );
        wprintf(L"   --lang:<language>\n\tSets the language id for text file renaming\n\totheriwse reads game lang.dat\n\n");
        wprintf(L"\nFlags:\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"   -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", p->name(language).c_str(), version.c_str(), p->author().c_str());

        switch (p->GetType())
        {
        case TYPE_XSP:
                wprintf(L" (Ship)");
                break;
        case TYPE_SPK:
        {
                CSpkFile* spk = dynamic_cast<CSpkFile*>(p);
                wprintf(L" (%s)", spk->scriptTypeString(language).c_str());
                break;
        }
        }

        wprintf(L"\n");
}

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;
        wprintf(L"\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);
        }
        wprintf(L"\n");
}

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();
}

bool GetAllFiles(const Utils::CommandLine& cmd, int start, Utils::WStringList &files, const Utils::WString &ext, bool showError)
{
        for (int i = start; i < cmd.argCount(); i++)
        {
                if (cmd.arg(i).containsAny(L"?*"))
                {
                        CFileIO File(cmd.fullFilename(cmd.arg(i)));
                        if (File.dirIO().exists())
                        {
                                Utils::WStringList fileList;
                                if (File.dirIO().dirList(fileList, Utils::WString::Null(), File.filename(), true))
                                {
                                        for (auto itr = fileList.begin(); itr != fileList.end(); itr++)
                                        {
                                                // check if the file exists
                                                if (CFileIO::Exists((*itr)->str))                                               
                                                        files.pushBack((*itr)->str);
                                        }
                                }
                        }
                }
                else
                {
                        // check if the file exists
                        if (CFileIO::Exists(cmd.fullFilename(cmd.arg(i))))
                        {
                                files.pushBack(cmd.fullFilename(cmd.arg(i)));
                                continue;
                        }

                        // otherwise, try to append extension to the filename
                        if (!ext.empty())
                        {
                                if (CFileIO(cmd.fullFilename(cmd.arg(i))).extension().lower() != ext.lower())
                                {
                                        Utils::WString filename = cmd.fullFilename(cmd.arg(i)) + L"." + ext;
                                        if (CFileIO::Exists(filename))
                                        {
                                                files.pushBack(filename);
                                                continue;
                                        }
                                }
                        }

                        if (showError)
                                wprintf(L"Error: Unable to find package file %s\n", cmd.arg(i).c_str());
                }

        }

        return !files.empty();
}

Utils::WString InstallPackage(Utils::CommandLine &cmd, const Utils::WString &destination, Utils::WStringList *errors, CPackages *packages, bool disabled)
{
        if (cmd.argCount() < 2)
        {
                wprintf(L"Syntax: %s [flags] install <file>\n\tInstalls a package to the destination\n", cmd.cmdName().c_str());
                return Utils::WString::Null();
        }

        CProgressConsole progress;

        int error;

        Utils::WStringList files;
        if(!GetAllFiles(cmd, 1, files, L"spk", true))
        {
                wprintf(L"Error: No package files specified to install\n");
                return Utils::WString::Null();
        }

        if (!OpenDestination(cmd, destination))
                return Utils::WString::Null();

        CLinkList<CBaseFile> lPackages;

        // open the package file
        printf ( "  - Opening Package                \n" );
        for (auto itr = files.begin(); itr != files.end(); itr++)
        {
                CFileIO spkFile((*itr)->str);

                if(spkFile.filename().length() > 30 )
                        wprintf(L"    %28s.. ", spkFile.filename().left(28).c_str() );
                else
                        wprintf(L"    %30s ", spkFile.filename().c_str() );

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

                // multi packages
                if ( !package && error == INSTALLERR_NOMULTI )
                {
                        if ( !packages->openMultiPackage(spkFile.fullFilename(), &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:\n", spk->name(packages->GetLanguage()).c_str(), spk->version().c_str(), spk->author().c_str());
                        if(!spk->otherName().empty())
                                wprintf(L"\t\t%s by %s\n", spk->otherName().c_str(), spk->otherAuthor().c_str());
                        for (auto lNode = spk->GetNeededLibraries()->Front(); lNode; lNode = lNode->next())
                                wprintf(L"\t\t%s by %s (Minimum Version: %s)\n", lNode->Data()->sName.c_str(), lNode->Data()->sAuthor.c_str(), lNode->Data()->sMinVersion.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" );
                CloseDestination(cmd, false);
                return Utils::WString::Null();
        }

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

        CloseDestination(cmd, true);

        // 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, const CPackages *packages)
{
        for(auto node = packages->packageList()->Front(); node; node = node->next())
        {
                if (node->Data() && node->Data()->GetNum() == (packageNum - 1))
                        return node->Data();
        }

        return nullptr;
}

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();
                //Check this?
                //Utils::WString rest = (*itr)->str.tokens(L" ", 2);
                Utils::WString rest = (*itr)->str;

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

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

void ShowInfo(const Utils::CommandLine& cmd)
{
        int package = Utils::WString(cmd.arg(1)).toInt();
        CBaseFile* p = FindPackage(package, &cmd.packages());
        if (!p)
        {
                wprintf(L"Error: Unable to find package #%d\n", package);
                return;
        }
        wprintf(L"\n============================\n");
        wprintf(L"Package #%d: %s\n", package, p->name(cmd.packages().language()).c_str());
        wprintf(L"\t%15s: %s\n", L"Author", p->author().c_str());
        wprintf(L"\t%15s: %s\n", L"Version", p->version().c_str());
        wprintf(L"\t%15s: %s\n", L"Description", p->description().c_str());
        if (p->GetType() == TYPE_SPK)
        {
                CSpkFile* spk = dynamic_cast<CSpkFile*>(p);
                wprintf(L"\t%15s: %s\n", L"Type", spk->scriptTypeString(cmd.packages().language()).c_str());
        }
        else if (p->GetType() == TYPE_XSP)
                wprintf(L"\t%15s: %s\n", L"Type", L"Ship");

        wprintf(L"\t%15s: %s\n", L"Status", p->isEnabled() ? L"Enabled" : L"Disabled");

        if (p->anyDependacies())
        {
                wprintf(L"\t%15s:\n", L"Dependancies");
                for (auto needed = p->GetNeededLibraries()->First(); needed; needed = p->GetNeededLibraries()->Next())
                        wprintf(L"\t\t%s by %s (Min Version: %s)", needed->sName.c_str(), needed->sAuthor.c_str(), needed->sMinVersion.c_str());
        }

        wprintf(L"\n============================\n\b");
}


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 V1.00 (SPK Library Version %.2f) 31/05/2025 Created by Cycrow\n\n", GetLibraryVersion() );

        Utils::CommandLine cmd(argc, argv, true);

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

        Utils::WString destination = cmd.cmdDir();
        Utils::WStringList lErrors;

        // do the flags and switchs
        // get the destination directory
        if(cmd.hasSwitch(L"dir"))
                destination = cmd.switchData(L"dir").findReplace("\\", "/");
        else if (cmd.hasSwitch(L"directory"))
                destination = cmd.switchData(L"directory").findReplace("\\", "/");
        else if (cmd.hasSwitch(L"destination"))
                destination = cmd.switchData(L"destination").findReplace("\\", "/");

        // get the game language
        auto& packages = cmd.packages();
        if (cmd.hasSwitch(L"lang"))
                packages.SetLanguage(cmd.switchData(L"lang").toInt());
        else if (cmd.hasSwitch(L"language"))
                packages.SetLanguage(cmd.switchData(L"language").toInt());

        // check for verbose mode
        g_debug = cmd.hasSwitch(L"verbose") || cmd.hasFlag('v');
        g_force = cmd.hasSwitch(L"override") || cmd.hasFlag('o');

        if (cmd.hasSwitch(L"textrename") || cmd.hasFlag('t'))
                packages.SetRenameText(true);

        if (cmd.hasSwitch(L"enablechild") || cmd.hasFlag('c'))
                packages.SetAutoEnable(true);
        if (cmd.hasSwitch(L"forcemod") || cmd.hasFlag('m'))
                packages.SetForceModInstall(true);

        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];
        }
        */

        // check for valid command
        Utils::WString command = cmd.arg(0).toLower();
        if (command.Compare(L"list"))
        {
                if (OpenDestination(cmd, destination))
                {
                        ListPackages(&packages);
                        CloseDestination(cmd, false);
                }
        }
        else if (command.Compare(L"info"))
        {
                if (cmd.argCount() < 2)
                {
                        wprintf(L"Syntax: %s [flags] info <package#>\n\tDisplays info about an installed package\n", cmd.cmdName().c_str());
                        wprintf(L"\tUse the <list> command to get the package number to use");
                }
                else
                {
                        if (OpenDestination(cmd, destination))
                        {
                                ShowInfo(cmd);
                                CloseDestination(cmd, false);
                        }
                }
        }
        else if (command.Compare(L"install"))
        {
                Utils::WString aftertext = InstallPackage(cmd, destination, &lErrors, &packages, false);
                PrintDebug(&lErrors);
                if (!aftertext.empty())
                        wprintf(L"\n%s\n", aftertext.c_str());
        }
        else if (command.Compare(L"uninstall"))
        {
                if (cmd.argCount() < 2)
                {
                        wprintf(L"Syntax: %s [flags] uninstall <package#>\n\tUninstalls a package, package# is from the /l list command\n", cmd.cmdName().c_str());
                        Pause();
                        exit(1);
                }
                else
                {
                        if (OpenDestination(cmd, destination))
                        {
                                bool prepare = UninstallPackage(Utils::WString(cmd.arg(1)).toInt(), &lErrors, &packages, command);
                                PrintDebug(&lErrors);
                                if (prepare)
                                        CloseDestination(cmd, true);
                                else
                                        packages.RestoreFakePatch();
                        }
                }
        }
        else if (command.Compare(L"enable"))
        {
                if (cmd.argCount() < 2)
                {
                        wprintf(L"Syntax: %s [flags] enable <package#>\n\tEnables an installed package thats been disabled\n", cmd.cmdName().c_str());
                        Pause();
                        exit(1);
                }
                else
                {
                        if (OpenDestination(cmd, destination))
                        {
                                bool prepare = EnablePackage(Utils::WString(cmd.arg(1)).toInt(), &lErrors, &packages, command);
                                PrintDebug(&lErrors);
                                if (prepare)
                                        CloseDestination(cmd, true);
                                else
                                        packages.RestoreFakePatch();
                        }
                }
        }

        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 'u':
                                        if ( argc <= start )
                                                wprintf(L"Syntax: %s [flags] /u <package#>\n\tUninstalls a package, package# is from the /l list command\n", cmd.cmdName().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.cmdName().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.cmdName().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;
}