Rev 1 | 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>#else#include "../spk/spk.h"#endif#include <time.h>#ifdef _WIN32#include <windows.h>#include <direct.h>#include <shlobj.h>#endif#define BETA 1class 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 "[-voctm][-d destination][-l langid]"CyString g_dir;bool g_debug = false;bool g_force = false;int g_indent = 0;/*Func: GetInputDesc: Gets an input from the user, ie, any settings required to be typed in*/CyString GetInput (){// g_read = true;CyString line;char c = getchar();while ( (c != '\n') && (c != '\0') ){line += c;c = getchar();}return line;}void PrintSyntax ( CyString cmd ){printf ( "Syntax: %s %s </command> [arguments]\n", cmd.c_str(), FLAGS );printf ( "\nCommands:\n" );printf ( " /list\n\t- Lists installed packages\n" );printf ( " /install <file>\n\t- Installs a package file\n" );printf ( " /uninstall <package#>\n\t- Uninstalls a package, use id number from list\n" );printf ( " /enable <package#>\n\t- Enables an installed package\n" );printf ( " /disable <package#>\n\t- Disables an installed package\n" );printf ( " /removeuninstall\n\t- Removes uninstall scripts\n" );printf ( " /removeshared\n\t- Removes unused sharded files\n" );printf ( "\nSwitchs:\n" );printf ( " -d (--directory) [directory]\n\tChange destination directory, otherwise uses current\n\n" );printf ( " -v (--verbose)\n\tTurns on verbose mode\n\n" );printf ( " -o (--override)\n\tOverride install warnings\n\tIE. allows you to install older scripts\n\n" );printf ( " -t (--textrename)\n\tForces text file renaming for installed packages\n\n" );printf ( " -l (--language) <language>\n\tSets the language id for text file renaming\n\totheriwse reads game lang.dat\n\n" );printf ( " -c (--enablechild)\n\tAuto Enabled all children when parent is enabled\n\n" );printf ( " -m (--forcemod\n\tForces a mod enabled even if theres one already enabled\n\n" );}void DisplayPackage(CBaseFile *p, int indent, int language){CyString version = p->GetVersion();if ( version.lower()[0] != 'v' )version.Prepend("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] ");printf ( "%s %s by %s\n", p->GetLanguageName(language).c_str(), version.c_str(), p->GetAuthor().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 childrenDoAllChildren(packages, p, &doneList, 1);}}int SplitArguments(char **argv, int argc, int start, CyStringList *argList){for ( int i = start; i < argc; i++ ){CyString arg = argv[i];if ( !arg.Empty() )argList->PushBack(arg);}return argList->Count();}CyString InstallPackage(CyStringList *lArguments, CyStringList *errors, CPackages *packages, bool disabled){CProgressConsole progress;int error;if ( !lArguments || !lArguments->Count() )return NullString;// append spk on the endfor ( SStringList *node = lArguments->Head(); node; node = node->next ){if ( !CFileIO(node->str).Exists() ){if ( CFileIO(node->str).GetFileExtension().lower() != "spk" )node->str += ".spk";}}CLinkList<CBaseFile> lPackages;// open the package fileprintf ( " - Opening Package \n" );for ( SStringList *node = lArguments->Head(); node; node = node->next ){CyString spkFilename = node->str;if ( spkFilename.Length() > 30 )printf ( " ..%28s ", spkFilename.Right(28).c_str() );elseprintf ( " %30s ", spkFilename.Right(30).c_str() );CLinkList<CBaseFile> lPackageList;CBaseFile *package = packages->OpenPackage(spkFilename, &error, &progress);// multi packagesif ( !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 versionsCyString 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:printf ( "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 addedcase INSTALLCHECK_WRONGGAME:printf ( "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:printf ( "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->IsThereInstallText() ){CyString installtext = packages->GetInstallBeforeText(package);if ( !installtext.Empty() ){installtext.StripHTML();printf ( "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{CyString input = GetInput().ToLower();if ( input != "y" && input != "yes" ){printf ( "\nInstallion aborted!!\n\n" );packages->RemovePreparedInstall(package);continue;}}}}lPackages.push_back(package);}}// is there any that couldn't installCLinkList<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();printf ( "\t%s V%s by %s (Requires: %s by %s)\n", spk->GetLanguageName(packages->GetLanguage()).c_str(), spk->GetVersion().c_str(), spk->GetAuthor().c_str(), spk->GetOtherName().c_str(), spk->GetOtherAuthor().c_str());}}// no packages will be installedif ( packages->GetNumPackagesInQueue() < 1 )return NullString;// install the package fileprintf ( " - Installing " );CLinkList<CBaseFile> erroredPackages;if ( packages->InstallPreparedPackages(errors, &progress, &erroredPackages) )progress.Finish();else{printf ( "ERROR!\n" );return NullString;}// delete any errored packagesfor ( CListNode<CBaseFile> *pNode = erroredPackages.Front(); pNode; pNode = pNode->next() ){lPackages.remove(pNode->Data());pNode->DeleteData();}// now display the packagesCyString retStr = "Packages Installed:\n";for ( CListNode<CBaseFile> *pNode = lPackages.Front(); pNode; pNode = pNode->next() ){CBaseFile *package = pNode->Data();retStr += " <> ";retStr += package->GetFullPackageName(packages->GetLanguage());retStr += "\n";if ( !packages->GetInstallAfterText(package).Empty() ){CyString afterText = packages->GetInstallAfterText(package).StripHTML();afterText = afterText.FindReplace("\n", "\n\t");retStr += "\t";retStr += afterText;retStr += "\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, CyStringList *errors, CPackages *packages, CyString *endMessage){CBaseFile *p = FindPackage(uninstallNum, packages);if ( !p )return false;// lets check for the uninstall textCyString uText = packages->GetUninstallBeforeText(p).StripHTML();if ( !uText.Empty() ){printf ( "Uninstalling: %s\n", uText.c_str() );printf ( "Do you wish to continue with the uninstall? " );if ( g_force )printf ( "(FORCED)\n" );else{CyString input = GetInput().ToLower();if ( input != "y" && input != "yes" ){printf ( "\nUninstallation has been aborted!!\n" );return false;}}}CProgressConsole progress;(*endMessage) = CyString("Uninstalled: ") + p->GetFullPackageName(packages->GetLanguage());// add the uninstall after textuText = packages->GetUninstallAfterText(p).StripHTML();if ( !uText.Empty() ){(*endMessage) += "\n\n";(*endMessage) += uText;(*endMessage) += "\n";}printf ( " - Unistalling " );packages->PrepareUninstallPackage(p);if ( packages->UninstallPreparedPackages(errors, &progress) ){progress.Finish();}else{(*endMessage) = "";printf ( "ERROR!\n" );return false;}return true;}bool EnablePackage(int uninstallNum, CyStringList *errors, CPackages *packages, CyString *endMessage){CBaseFile *p = FindPackage(uninstallNum, packages);if ( !p )return false;CProgressConsole progress;(*endMessage) = CyString("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, CyStringList *errors, CPackages *packages, CyString *endMessage){CBaseFile *p = FindPackage(uninstallNum, packages);if ( !p )return false;CProgressConsole progress;(*endMessage) = CyString("Disabled: ") + p->GetFullPackageName(packages->GetLanguage());printf ( " - Disabling " );if ( packages->DisablePackage(p, errors, &progress) ){progress.Finish();}else{(*endMessage) = "";printf ( "ERROR!\n" );return false;}return true;}void RemoveUninstallScripts(CPackages *packages, CyStringList *errors){CProgressConsole progress;printf ( " - Removing uninstall scripts " );packages->RemoveUninstallScripts(errors, &progress);progress.Finish();}void RemoveUnusedShared(CPackages *packages, CyStringList *errors){CProgressConsole progress;printf ( " - Removing unused shared files " );packages->RemoveUnusedSharedFiles(errors, &progress);progress.Finish();}void PrintDebug(CyStringList *errors){if ( !g_debug )return;if ( errors && errors->Count() )printf ( "\n");for ( SStringList *str = errors->Head(); str; str = str->next ){int errornum = str->str.ToInt();CyString rest = str->str.GetToken(" ", 2);CyString err = FormatErrorString(errornum, rest);printf ( " * %s\n", err.c_str() );}if ( errors && errors->Count() )printf ( "\n");}void Pause(){#ifdef _DEBUGchar pause;scanf ( "%s", &pause );#endif}int ParseCommandSwitchs(char c, CyString *destination, CPackages *packages, int start, int *arg, char **argv){switch ( c ){case 'o':g_force = true;break;case 'v':g_debug = true;break;case 'd':*destination = argv[*arg];*destination = destination->FindReplace("\\", "/");++(*arg);++start;break;case 't':packages->SetRenameText(true);break;case 'l':packages->SetLanguage(CyString(argv[*arg]).ToInt());++(*arg);++start;break;case 'c':packages->SetAutoEnable(true);break;case 'm':packages->SetForceModInstall(true);break;}return start;}/*TODO:Additional FeaturesPatch ModsUpdate Packages*//*Main entry point to program*/int main ( int argc, char **argv ){// display program header to command promptprintf ( "\nSPKInstall V0.90 (SPK Library Version %.2f) 18/10/2009 Created by Cycrow\n\n", GetLibraryVersion() );// parse the cmd nameCyString cmd (argv[0]);cmd = cmd.FindReplace ( "\\", "/" );g_dir = cmd.GetToken ( 0, cmd.NumToken('/') - 1, '/' );cmd = cmd.GetToken ( cmd.NumToken('/'), '/' );if ( g_dir.Empty() ){#ifdef _WIN32g_dir = CyString(_getcwd(NULL, 0));#elseg_dir = CyString(getcwd(NULL, 0));#endifif ( g_dir.Empty() )g_dir = "./";}// not enough arguments, display the syntax and exitif ( argc < 2 ){PrintSyntax(cmd);Pause();exit ( 1 );}CyString destination = g_dir;CyStringList errors;// get the command flagCyString command(argv[1]);command = command.lower();CPackages packages;CyString myDoc = g_dir;#ifdef _WIN32TCHAR pszPath[MAX_PATH];if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pszPath)))myDoc = (char *)pszPath;#endifpackages.Startup(g_dir, g_dir, myDoc);int start = 2;// check for switchswhile ( command[0] == '-' ){if ( argc < (start + 1) ){PrintSyntax(cmd);Pause();exit ( 1 );}++start;// single long commandsint arg = 2;if ( command.Left(2) == "--" ){CyString cmd = command.Right(-2);cmd = cmd.ToLower();char c = 0;if ( cmd == "override" )c = 'o';else if ( cmd == "verbose" )c = 'v';else if ( cmd == "directory" )c = 'd';else if ( cmd == "textrename" )c = 't';else if ( cmd == "enablechild" )c = 'c';else if ( cmd == "language" )c = 'l';else if ( cmd == "forcemod" )c = 'm';if ( c )start = ParseCommandSwitchs(c, &destination, &packages, start, &arg, argv);}else{// now parse argumentsfor ( 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] == '/' ){char c = command[1];bool disabled = false;CyString checkCmd = command.ToLower();if ( checkCmd == "/install" )c = 'i';else if ( checkCmd == "/installdisable" ){c = 'i';disabled = true;}else if ( checkCmd == "/uninstall" )c = 'u';else if ( checkCmd == "/enable" )c = 'e';else if ( checkCmd == "/disable" )c = 'd';else if ( checkCmd == "/list" )c = 'l';else if ( checkCmd == "/removeshared" )c = 's';else if ( checkCmd == "/removeunisntall" )c = 'r';if ( c == 'i' || c == 'l' || c == 'u' || c == 'e' || c == 'd' || c == 'r' || c == 's' ){CyString endMessage;printf ( " |0 100|\n\n");printf ( " - Reading game directory " );CProgressConsole progress;if ( packages.Read(destination, &progress) ){packages.UpdatePackages();packages.ReadGameLanguage(false);progress.Finish(false);CyString gameName = packages.GetGameName();if ( packages.GetLanguage() || !gameName.Empty()){printf ( "\n\t" );if ( !gameName.Empty() )printf ( "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();CyStringList lArguments;SplitArguments(argv, argc, start, &lArguments);switch ( c ){case 'i':if ( argc <= start )printf ( "Syntax: %s [flags] /i <file>\n\tInstalls a package to the destination\n", cmd.c_str() );else{CyString aftertext = InstallPackage(&lArguments, &errors, &packages, disabled);if ( !aftertext.Empty() ){prepare = true;endMessage = aftertext;}PrintDebug(&errors);}break;case 'u':if ( argc <= start )printf ( "Syntax: %s [flags] /u <package#\n\tUninstalls a package, package# is from the /l list command\n", cmd.c_str() );else{prepare = UninstallPackage(CyString(argv[start]).ToInt(), &errors, &packages, &endMessage);PrintDebug(&errors);}break;case 'e':if ( argc <= start )printf ( "Syntax: %s [flags] /u <package#\n\tEnabled an installed package thats been disabled\n", cmd.c_str() );else{prepare = EnablePackage(CyString(argv[start]).ToInt(), &errors, &packages, &endMessage);PrintDebug(&errors);}break;case 'd':if ( argc <= start )printf ( "Syntax: %s [flags] /u <package#\n\tDisabled an installed package\n", cmd.c_str() );else{prepare = DisablePackage(CyString(argv[start]).ToInt(), &errors, &packages, &endMessage);PrintDebug(&errors);}break;case 'l':ListPackages(&packages);break;case 'r':RemoveUninstallScripts(&packages, &errors);endMessage = "Removed all unused uninstall scripts";break;case 's':RemoveUnusedShared(&packages, &errors);endMessage = "Removed all unused shared files";break;}if ( prepare ){errors.Clear();printf ( " - Preparing game directory " );if ( packages.CloseDir(&errors, &progress, true) )progress.Finish();else{printf ( "ERROR!\n" );Pause();exit(1);}PrintDebug(&errors);}elsepackages.RestoreFakePatch();printf ( "\nDone!\n" );if ( !endMessage.Empty() )printf ( "\n%s\n", endMessage.c_str() );}elseprintf ( "Unknown Command: %c\n", c );}Pause();return 0;}