From 32dc2d619f8360e9e738bb46f4b55b2fe63fe887 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Sat, 31 Mar 2007 16:23:19 +0000 Subject: [PATCH] initial import of the updater tool --HG-- extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/trunk%40353 --- update_tool/api_link.asm | 92 +++++++++++ update_tool/msvc8/update_tool.sln | 20 +++ update_tool/msvc8/update_tool.vcproj | 203 +++++++++++++++++++++++ update_tool/update_tool.cpp | 230 +++++++++++++++++++++++++++ 4 files changed, 545 insertions(+) create mode 100644 update_tool/api_link.asm create mode 100644 update_tool/msvc8/update_tool.sln create mode 100644 update_tool/msvc8/update_tool.vcproj create mode 100644 update_tool/update_tool.cpp diff --git a/update_tool/api_link.asm b/update_tool/api_link.asm new file mode 100644 index 0000000..f57c629 --- /dev/null +++ b/update_tool/api_link.asm @@ -0,0 +1,92 @@ +;;;; +;; (C)2005-2007 AlliedModders LLC +;; By the Metamod:Source Development Team +;; This software is licensed under the zlib/libpng free software license. +;; +;; This assembly file is a short thunk wrapper to let us load as a VSP and exit quietly, +;; without any overhead of the rest of the interface, and also to prevent linking against +;; tierX or vstdlib +;;;; + +;;Exports: +;; void GetBaseDir(char *buffer, maxlength); +;; void *GetThisPointer(); +;;Imports: +;; void LoadFunction(); + +section .text + +global GetThisPointer, GetGameDir +global _GetThisPointer, _GetGameDir +extern _LoadFunction + +GetThisPointer: +_GetThisPointer: + mov eax, GLOBAL_POINTER + ret + +GetGameDir: +_GetGameDir: + push ebp + mov ebp, esp + + mov ecx, [engine] ;get this pointer + mov edx, [ecx] ;get the vtable + %ifdef LINUX + push ecx ;push this pointer + %endif + push dword [ebp+12] ;push maxlenth + push dword [ebp+8] ;push buffer + call dword [edx+216] ;call IVEngineServer::GetGameDir + %ifdef LINUX + add esp, 8 ;correct stack + %endif + + pop ebp + ret + +thisLoadFunction: + push ebp + mov ebp, esp + + ;get factory + mov eax, [ebp+8] + + push dword 0 ;NULL + push dword VENGINESERVER ;iface name + call eax ;call factory + add esp, 8 ;correct stack + + test eax, eax ;do we have a valid pointer? + jz .end ;no, bail out + + mov [engine], eax ;store the engine pointer + + call _LoadFunction + +.end: + ;We never load, never ever ever! + xor eax, eax + pop ebp + %ifdef LINUX + ret + %else + retn 8 + %endif + +thisUnloadFunction: + ret + +section .data + INTERFACE_NAME DB "ISERVERPLUGINCALLBACKS001", 0 + VENGINESERVER DB "VEngineServer021", 0 + + VIRTUAL_TABLE DD thisLoadFunction + DD thisUnloadFunction + ;We don't need any more of the vtable here + + GLOBAL_POINTER DD VIRTUAL_TABLE + + temp_ret DD 0 + temp_ptr DD temp_ret + engine DD 0 diff --git a/update_tool/msvc8/update_tool.sln b/update_tool/msvc8/update_tool.sln new file mode 100644 index 0000000..5250f8a --- /dev/null +++ b/update_tool/msvc8/update_tool.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "update_tool", "update_tool.vcproj", "{DDD1563F-7EE2-4E76-BE57-ED84A2664A51}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Debug|Win32.ActiveCfg = Debug|Win32 + {DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Debug|Win32.Build.0 = Debug|Win32 + {DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Release|Win32.ActiveCfg = Release|Win32 + {DDD1563F-7EE2-4E76-BE57-ED84A2664A51}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/update_tool/msvc8/update_tool.vcproj b/update_tool/msvc8/update_tool.vcproj new file mode 100644 index 0000000..690bac3 --- /dev/null +++ b/update_tool/msvc8/update_tool.vcproj @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/update_tool/update_tool.cpp b/update_tool/update_tool.cpp new file mode 100644 index 0000000..799fde3 --- /dev/null +++ b/update_tool/update_tool.cpp @@ -0,0 +1,230 @@ +#include +#include +#include +#include + +extern "C" void GetGameDir(char *buffer, int maxlength); +extern "C" void *GetThisPointer(); + +#if defined _MSC_VER +#define SEPCHAR "\\" +#define MMPATH "|gameinfo_path|addons\\metamod\\bin" +#define WINDOWS_LEAN_AND_MEAN +#include +#elif defined __linux__ +#define SEPCHAR "/" +#define MMPATH "|gameinfo_path|addons/metamod/bin" +#include +#endif + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); +bool s_isspace(char c); +bool RenameFile(const char *old, const char *newf); + +/* This will be called by the thunk */ +#if defined _MSC_VER +extern "C" void LoadFunction() +#elif defined __linux__ +extern "C" void _LoadFunction() +#endif +{ + char gamedir[260]; + + GetGameDir(gamedir, sizeof(gamedir)); + + char old_path[260]; + char new_path[260]; + + UTIL_Format(old_path, sizeof(old_path), "%s" SEPCHAR "gameinfo.txt", gamedir); + UTIL_Format(new_path, sizeof(new_path), "%s" SEPCHAR "gameinfo.new.txt", gamedir); + + FILE *fp = fopen(old_path, "rt"); + + if (!fp) + { + return; + } + + FILE *op = fopen(new_path, "wt"); + if (!op) + { + fclose(fp); + return; + } + + enum ParseState + { + Parse_None, + Parse_Root, + Parse_GameInfo, + Parse_FileSystem, + Parse_SearchPaths, + }; + + ParseState ps = Parse_Root; + + char input[1024]; + char backup[1024]; + + while (!feof(fp) && fgets(input, sizeof(input), fp) != NULL) + { + UTIL_Format(backup, sizeof(backup), "%s", input); + + if (ps != Parse_None) + { + char *inbuf = input; + + /* Strip beginning whitespace */ + while (*inbuf != '\0' && s_isspace(*inbuf)) + { + inbuf++; + } + + /* Strip ending whitespace */ + size_t len = strlen(inbuf); + for (size_t i = len - 1; + i >= 0 && i < len; + i--) + { + if (s_isspace(inbuf[i])) + { + inbuf[i] = '\0'; + len--; + } else { + break; + } + } + + /* Strip quotation marks */ + if (inbuf[0] == '"' + && inbuf[len-1] == '"') + { + inbuf[len - 1] = '\0'; + inbuf = &inbuf[1]; + len -= 2; + } + + /* Do tests */ + if (ps == Parse_Root && strcmp(inbuf, "GameInfo") == 0) + { + ps = Parse_GameInfo; + } else if (ps == Parse_GameInfo && strcmp(inbuf, "FileSystem") == 0) { + ps = Parse_FileSystem; + } else if (ps == Parse_FileSystem && strcmp(inbuf, "SearchPaths") == 0) { + ps = Parse_SearchPaths; + } else if (ps == Parse_SearchPaths) { + const char *game = strstr(inbuf, "Game"); + if (game) + { + if (strstr(game, "GameBin") != NULL + && strstr(game, MMPATH) != NULL) + { + fclose(op); + op = NULL; + break; /* Nothing more to do! */ + } else { + fputs("\t\t\t\tGameBin\t\t" MMPATH "\n", op); + ps = Parse_None; + } + } + } + } + + fputs(backup, op); + } + + if (!op) + { + /* Well, we can't really do anything else. Give up. */ + fclose(fp); + return; + } + + /* Close all streams */ + fclose(op); + fclose(fp); + + /* Move the old file to a backup name */ + char backup_name[260]; + UTIL_Format(backup_name, sizeof(backup_name), "%s" SEPCHAR "gameinfo.backup.txt", gamedir); + + if (!RenameFile(old_path, backup_name)) + { + /* If we can't rename, just bail out. + * We don't want to overwrite the client's default + * without backing it up first! + */ + return; + } + if (!RenameFile(new_path, old_path)) + { + /* Since this failed, we really have no choice. + * Try and rename the old back. + */ + RenameFile(backup_name, old_path); + return; + } +#if defined _MSC_VER + _unlink(new_path); +#else + unlink(new_path); +#endif +} + +bool s_isspace(char c) +{ + if ((unsigned)c & 0x80) + { + return false; + } else { + return isspace(c) ? true : false; + } +} + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + size_t len = vsnprintf(buffer, maxlength, fmt, ap); + va_end(ap); + + if (len >= maxlength) + { + len = maxlength - 1; + buffer[len] = '\0'; + } + + return len; +} + +bool RenameFile(const char *old, const char *newf) +{ +#if defined __linux__ + return (rename(old, newf) == 0); +#elif defined WIN32 + return (MoveFileA(old, newf) != 0); +#endif +} + +#if defined _MSC_VER +extern "C" __declspec(dllexport) void *CreateInterface(const char *iface, int *ret) +#elif defined __linux__ +extern "C" __attribute__((visibility("default"))) void *CreateInterface(const char *iface, int *ret) +#endif +{ + if (strcmp(iface, "ISERVERPLUGINCALLBACKS001") == 0) + { + if (ret) + { + *ret = 0; + } + return GetThisPointer(); + } + + if (ret) + { + *ret = 1; + } + return NULL; +}