1
0
mirror of https://github.com/alliedmodders/metamod-source.git synced 2025-02-20 13:54:14 +01:00

Initial import of gameinfo loader.

This commit is contained in:
David Anderson 2008-11-23 21:21:49 -06:00
parent ce7a3beab0
commit ad6f271a71
11 changed files with 923 additions and 128 deletions

View File

@ -8,7 +8,9 @@
BINARY = server_i486.so
OBJECTS = loader.cpp \
serverplugin.cpp
utility.cpp \
serverplugin.cpp \
gamedll.cpp
##############################################
### CONFIGURE ANY OTHER FLAGS/OPTIONS HERE ###

436
loader/gamedll.cpp Normal file
View File

@ -0,0 +1,436 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <assert.h>
#include <stdlib.h>
#include <stddef.h>
#include "loader.h"
#include <sh_memfuncinfo.h>
#include <sh_memory.h>
#include "utility.h"
#include "gamedll.h"
#include "valve_commandline.h"
class IServerGameDLL;
typedef ICommandLine *(*GetCommandLine)();
#define MAX_GAMEDLL_PATHS 10
IGameDllBridge* gamedll_bridge = NULL;
static int game_info_detected = 0;
static char gamedll_paths[MAX_GAMEDLL_PATHS][PLATFORM_MAX_PATH];
static void *gamedll_libs[MAX_GAMEDLL_PATHS];
static unsigned int gamedll_path_count = 0;
static void *gamedll_lib = NULL;
static IServerGameDLL *gamedll_iface = NULL;
static QueryValveInterface gamedll_qvi = NULL;
static int gamedll_version = 0;
#if defined _WIN32
#define TIER0_NAME "bin\\tier0.dll"
#define VSTDLIB_NAME "bin\\vstdlib.dll"
#define SERVER_NAME "server.dll"
#elif defined __linux__
#define TIER0_NAME "bin/tier0_i486.so"
#define VSTDLIB_NAME "bin/vstdlib_i486.so"
#define SERVER_NAME "server_i486.so"
#endif
static bool
mm_DetectGameInformation()
{
void *lib;
char error[255];
GetCommandLine valve_cmdline;
char mm_path[PLATFORM_MAX_PATH];
char lib_path[PLATFORM_MAX_PATH];
char game_name[PLATFORM_MAX_PATH];
char game_path[PLATFORM_MAX_PATH];
if (game_info_detected)
return game_info_detected == 1 ? true : false;
game_info_detected = -1;
if (!mm_ResolvePath(TIER0_NAME, lib_path, sizeof(lib_path)))
{
mm_LogFatal("Could not find path for: " TIER0_NAME);
return false;
}
if ((lib = mm_LoadLibrary(lib_path, error, sizeof(error))) == NULL)
{
mm_LogFatal("Could not load %s: %s", lib_path, error);
return false;
}
valve_cmdline = (GetCommandLine)mm_GetLibAddress(lib, "CommandLine_Tier0");
if (valve_cmdline == NULL)
{
/* We probably have a Ship engine. */
mm_UnloadLibrary(lib);
if (!mm_ResolvePath(VSTDLIB_NAME, lib_path, sizeof(lib_path)))
{
mm_LogFatal("Could not find path for: " VSTDLIB_NAME);
return false;
}
if ((lib = mm_LoadLibrary(lib_path, error, sizeof(error))) == NULL)
{
mm_LogFatal("Could not load %s: %s", lib_path, error);
return false;
}
valve_cmdline = (GetCommandLine)mm_GetLibAddress(lib, "CommandLine");
}
mm_UnloadLibrary(lib);
if (valve_cmdline == NULL)
{
mm_LogFatal("Could not locate any command line functionality");
return false;
}
if (!mm_GetFileOfAddress((void*)mm_DetectGameInformation, mm_path, sizeof(mm_path)))
{
mm_LogFatal("Could not locate metamod loader library path");
return false;
}
mm_Format(game_name,
sizeof(game_name),
"%s",
valve_cmdline()->ParmValue("-game", "hl2"));
if (!mm_ResolvePath(game_name, game_path, sizeof(game_path)))
{
mm_LogFatal("Could not resolve path: %s", game_name);
return false;
}
FILE *fp;
char gameinfo_path[PLATFORM_MAX_PATH];
mm_PathFormat(gameinfo_path, sizeof(gameinfo_path), "%s/gameinfo.txt", game_path);
if ((fp = fopen(gameinfo_path, "rt")) == NULL)
{
mm_LogFatal("Could not read file: %s", gameinfo_path);
return false;
}
char temp_path[PLATFORM_MAX_PATH];
char cur_path[PLATFORM_MAX_PATH];
getcwd(cur_path, sizeof(cur_path));
char *ptr;
const char *lptr;
bool search = false;
char buffer[255], key[128], val[128];
while (!feof(fp) && fgets(buffer, sizeof(buffer), fp) != NULL)
{
mm_TrimComments(buffer);
mm_TrimLeft(buffer);
mm_TrimRight(buffer);
if (stricmp(buffer, "SearchPaths") == 0)
search = true;
if (!search)
continue;
mm_KeySplit(buffer, key, sizeof(key) - 1, val, sizeof(val) - 1);
if (stricmp(key, "Game") != 0 && stricmp(key, "GameBin") != 0)
continue;
if (strncmp(val, "|gameinfo_path|", sizeof("|gameinfo_path|") - 1) == 0)
{
ptr = &val[sizeof("|gameinfo_path|") - 1];
if (ptr[0] == '.')
ptr++;
lptr = game_path;
}
else
{
ptr = val;
lptr = cur_path;
}
if (stricmp(key, "GameBin") == 0)
mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s/" SERVER_NAME, lptr, ptr);
else if (!ptr[0])
mm_PathFormat(temp_path, sizeof(temp_path), "%s/bin/" SERVER_NAME, lptr);
else
mm_PathFormat(temp_path, sizeof(temp_path), "%s/%s/bin/" SERVER_NAME, lptr, ptr);
if (mm_PathCmp(mm_path, temp_path))
continue;
FILE *exists = fopen(temp_path, "rb");
if (!exists)
continue;
fclose(exists);
/* exists is still non-NULL... use this as a flag */
for (unsigned int i = 0; i < gamedll_path_count; i++)
{
if (mm_PathCmp(gamedll_paths[i], temp_path))
{
exists = NULL;
break;
}
}
if (!exists)
continue;
mm_Format(gamedll_paths[gamedll_path_count],
PLATFORM_MAX_PATH,
"%s",
temp_path);
gamedll_path_count++;
if (gamedll_path_count == MAX_GAMEDLL_PATHS)
break;
}
fclose(fp);
game_info_detected = 1;
return true;
}
static void
mm_FreeCachedLibraries()
{
for (unsigned int i = 0; i < gamedll_path_count; i++)
{
if (gamedll_libs[i] == NULL)
continue;
mm_UnloadLibrary(gamedll_libs[i]);
}
}
static void
mm_PatchDllInit(bool patch);
static void *isgd_orig_call = NULL;
class VEmptyClass
{
};
class IServerGameDLL
{
public:
virtual bool DLLInit(QueryValveInterface engineFactory,
QueryValveInterface physicsFactory,
QueryValveInterface fileSystemFactory,
void *pGlobals)
{
MetamodBackend backend = mm_DetermineBackend(engineFactory);
char error[255];
if (backend == MMBackend_UNKNOWN)
{
mm_LogFatal("Could not detect engine version");
}
else
{
if (!mm_LoadMetamodLibrary(backend, error, sizeof(error)))
{
mm_LogFatal("Detected engine %d but could not load: %s", backend, error);
}
else
{
typedef IGameDllBridge *(*GetGameDllBridge)();
GetGameDllBridge get_bridge = (GetGameDllBridge)mm_GetProcAddress("GetGameDllBridge");
if (get_bridge == NULL)
{
mm_UnloadMetamodLibrary();
mm_LogFatal("Detected engine %d but could not find GetGameDllBridge callback", backend);
}
gamedll_bridge = get_bridge();
}
}
if (gamedll_bridge)
{
gamedll_bridge_info info;
info.engineFactory = (QueryValveInterface)engineFactory;
info.physicsFactory = (QueryValveInterface)physicsFactory;
info.fsFactory = (QueryValveInterface)fileSystemFactory;
info.pGlobals = pGlobals;
info.dllVersion = gamedll_version;
info.isgd = gamedll_iface;
info.gsFactory = gamedll_qvi;
strcpy(error, "Unknown error");
if (!gamedll_bridge->DLLInit_Pre(&info, error, sizeof(error)))
{
gamedll_bridge = NULL;
mm_UnloadMetamodLibrary();
mm_LogFatal("Unknown error loading Metamod for engine %d: %s", backend, error);
}
}
/* Call the original */
bool result;
{
union
{
bool (VEmptyClass::*mfpnew)(QueryValveInterface engineFactory,
QueryValveInterface physicsFactory,
QueryValveInterface fileSystemFactory,
void *pGlobals);
#if defined _WIN32
void *addr;
} u;
u.addr = isgd_orig_call;
#else
struct
{
void *addr;
intptr_t adjustor;
} s;
} u;
u.s.addr = isgd_orig_call;
u.s.adjustor = 0;
#endif
result = (((VEmptyClass *)gamedll_iface)->*u.mfpnew)(engineFactory,
physicsFactory,
fileSystemFactory,
pGlobals);
}
/**
* :TODO: possible logic hole here, what happens if the gamedll REALLY returns false?
* I'm pretty sure we'll die horribly.
*/
if (!result)
{
gamedll_bridge->Unload();
mm_UnloadMetamodLibrary();
gamedll_bridge = NULL;
}
else if (gamedll_bridge != NULL)
{
gamedll_bridge->DLLInit_Post();
}
mm_PatchDllInit(false);
return result;
}
};
static IServerGameDLL isgd_thunk;
static void
mm_PatchDllInit(bool patch)
{
void **vtable_src;
void **vtable_dest;
SourceHook::MemFuncInfo mfp;
SourceHook::GetFuncInfo(&IServerGameDLL::DLLInit, mfp);
assert(mfp.isVirtual);
assert(mfp.thisptroffs == 0);
assert(mfp.vtbloffs == 0);
vtable_src = (void **)*(void **)&isgd_thunk;
vtable_dest = (void **)*(void **)gamedll_iface;
SourceHook::SetMemAccess(&vtable_dest[mfp.vtblindex],
sizeof(void*),
SH_MEM_READ|SH_MEM_WRITE|SH_MEM_EXEC);
if (patch)
{
assert(isgd_orig_call == NULL);
isgd_orig_call = vtable_dest[mfp.vtblindex];
vtable_dest[mfp.vtblindex] = vtable_src[mfp.vtblindex];
}
else
{
assert(isgd_orig_call != NULL);
vtable_dest[mfp.vtblindex] = isgd_orig_call;
isgd_orig_call = NULL;
}
}
static void
mm_PrepForGameLoad()
{
mm_PatchDllInit(true);
}
void *
mm_GameDllRequest(const char *name, int *ret)
{
if (gamedll_lib != NULL && gamedll_bridge == NULL)
{
mm_LogFatal("Requested unknown interface before game load: %s", name);
return gamedll_qvi(name, ret);
}
if (strncmp(name, "ServerGameDLL", 13) == 0)
{
if (!mm_DetectGameInformation())
{
if (ret != NULL)
*ret = 1;
return NULL;
}
void *lib;
char error[255];
void *ptr = NULL;
QueryValveInterface qvi;
for (unsigned int i = 0; i < gamedll_path_count; i++)
{
if (gamedll_libs[i] == NULL)
{
lib = mm_LoadLibrary(gamedll_paths[i], error, sizeof(error));
if (lib == NULL)
continue;
gamedll_libs[i] = lib;
}
lib = gamedll_libs[i];
qvi = (QueryValveInterface)mm_GetLibAddress(lib, "CreateInterface");
if (qvi == NULL)
continue;
ptr = qvi(name, ret);
if (ptr != NULL)
{
gamedll_libs[i] = NULL;
break;
}
}
if (ptr != NULL)
{
mm_FreeCachedLibraries();
gamedll_lib = lib;
gamedll_iface = (IServerGameDLL *)ptr;
gamedll_qvi = qvi;
gamedll_version = atoi(&name[13]);
mm_PrepForGameLoad();
if (ret != NULL)
*ret = 0;
return ptr;
}
}
else if (game_info_detected == 0)
{
mm_LogFatal("Received interface request too early: %s", name);
}
if (ret != NULL)
*ret = 1;
return NULL;
}

12
loader/gamedll.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_
#define _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_
#include "loader_bridge.h"
extern void *
mm_GameDllRequest(const char *name, int *ret);
extern IGameDllBridge* gamedll_bridge;
#endif /* _INCLUDE_METAMOD_SOURCE_GAMEDLLS_H_ */

View File

@ -1,10 +1,13 @@
#include <time.h>
#include <stdio.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "loader.h"
#include "serverplugin.h"
#include "gamedll.h"
#include "utility.h"
static HMODULE mm_library = NULL;
static char mm_fatal_logfile[PLATFORM_MAX_PATH] = "metamod-fatal.log";
@ -34,56 +37,6 @@ mm_LogFatal(const char *message, ...)
fclose(fp);
}
static size_t
mm_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
{
size_t len = vsnprintf(buffer, maxlength, fmt, params);
if (len >= maxlength)
{
len = maxlength - 1;
buffer[len] = '\0';
}
return len;
}
static size_t
mm_Format(char *buffer, size_t maxlength, const char *fmt, ...)
{
size_t len;
va_list ap;
va_start(ap, fmt);
len = mm_FormatArgs(buffer, maxlength, fmt, ap);
va_end(ap);
return len;
}
static bool
mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
{
#if defined _WIN32
MEMORY_BASIC_INFORMATION mem;
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
return false;
if (mem.AllocationBase == NULL)
return false;
HMODULE dll = (HMODULE)mem.AllocationBase;
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
#else
Dl_info info;
if (!dladdr(pAddr, &info))
return false;
if (!info.dli_fbase || !info.dli_fname)
return false;
const char *dllpath = info.dli_fname;
snprintf(buffer, maxlength, "%s", dllpath);
#endif
return true;
}
static const char *backend_names[3] =
{
"1.ep1",
@ -100,7 +53,7 @@ static const char *backend_names[3] =
#endif
#if defined _WIN32
static void
void
mm_GetPlatformError(char *buffer, size_t maxlength)
{
DWORD dw = GetLastError();
@ -143,35 +96,16 @@ mm_LoadMetamodLibrary(MetamodBackend backend, char *buffer, size_t maxlength)
"metamod.%s" LIBRARY_MINEXT,
backend_names[backend]);
#if defined _WIN32
mm_library = LoadLibrary(mm_path);
mm_library = mm_LoadLibrary(mm_path, buffer, maxlength);
if (mm_library == NULL)
{
mm_GetPlatformError(buffer, maxlength);
return false;
}
#elif defined __linux__
mm_library = dlopen(mm_path, RTLD_NOW);
if (mm_library == NULL)
{
mm_Format(buffer, maxlength, "%s", dlerror());
return false;
}
#endif
return true;
return (mm_library != NULL);
}
void
mm_UnloadMetamodLibrary()
{
#if defined _WIN32
FreeLibrary(mm_library);
#else
dlclose(mm_library);
#endif
mm_UnloadLibrary(mm_library);
mm_library = NULL;
}
#if defined _WIN32
@ -187,35 +121,63 @@ mm_UnloadMetamodLibrary()
EXPORT void *
CreateInterface(const char *name, int *ret)
{
if (mm_library != NULL)
/* If we've got a VSP bridge, do nothing. */
if (vsp_bridge != NULL)
{
if (ret != NULL)
*ret = 1;
return NULL;
}
/* If we've got a gamedll bridge, forward the request. */
if (gamedll_bridge != NULL)
return gamedll_bridge->QueryInterface(name, ret);
/* Otherwise, we're probably trying to load Metamod. */
void *ptr;
if (strncmp(name, "ISERVERPLUGINCALLBACKS", 22) == 0)
{
ptr = mm_GetVspCallbacks(atoi(&name[22]));
if (ret != NULL)
*ret = ptr != NULL ? 0 : 1;
return ptr;
}
else
ptr = mm_GameDllRequest(name, ret);
if (ret != NULL)
*ret = 1;
*ret = (ptr != NULL) ? 0 : 1;
return NULL;
return ptr;
}
extern void *
void *
mm_GetProcAddress(const char *name)
{
#if defined _WIN32
return GetProcAddress(mm_library, name);
#elif defined __linux__
return dlsym(mm_library, name);
#endif
return mm_GetLibAddress(mm_library, name);
}
MetamodBackend
mm_DetermineBackend(QueryValveInterface engineFactory)
{
/* Check for L4D */
if (engineFactory("VEngineServer022", NULL) != NULL &&
engineFactory("VEngineCvar007", NULL) != NULL)
{
return MMBackend_Left4Dead;
}
else if (engineFactory("VEngineServer021", NULL) != NULL)
{
/* Check for OB */
if (engineFactory("VEngineCvar004", NULL) != NULL &&
engineFactory("VModelInfoServer002", NULL) != NULL)
{
return MMBackend_Episode2;
}
/* Check for EP1 */
else if (engineFactory("VModelInfoServer001", NULL) != NULL &&
(engineFactory("VEngineCvar003", NULL) != NULL ||
engineFactory("VEngineCvar002", NULL) != NULL))
{
return MMBackend_Episode1;
}
}
return MMBackend_UNKNOWN;
}

View File

@ -9,17 +9,26 @@
#include <windows.h>
#define PLATFORM_MAX_PATH MAX_PATH
#define SH_COMP SH_COMP_MSVC
#define PATH_SEP_STR "\\"
#define PATH_SEP_CHAR '\\'
#define ALT_SEP_CHAR '/'
#elif defined __linux__
#include <dlfcn.h>
#include <dirent.h>
#include <stdint.h>
#include <unistd.h>
typedef void * HMODULE;
#define PLATFORM_MAX_PATH PATH_MAX
#define SH_COMP SH_COMP_GCC
#define PATH_SEP_STR "/"
#define PATH_SEP_CHAR '/'
#define ALT_SEP_CHAR '\\'
#else
#error "OS detection failed"
#endif
#include "loader_bridge.h"
#define SH_PTRSIZE sizeof(void*)
enum MetamodBackend
@ -42,5 +51,8 @@ mm_UnloadMetamodLibrary();
extern void
mm_LogFatal(const char *message, ...);
extern MetamodBackend
mm_DetermineBackend(QueryValveInterface qvi);
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_H_ */

View File

@ -20,5 +20,25 @@ public:
virtual const char *GetDescription() = 0;
};
struct gamedll_bridge_info
{
QueryValveInterface engineFactory;
QueryValveInterface fsFactory;
QueryValveInterface physicsFactory;
QueryValveInterface gsFactory;
void * pGlobals;
unsigned int dllVersion;
void * isgd;
};
class IGameDllBridge
{
public:
virtual bool DLLInit_Pre(const gamedll_bridge_info *info, char *buffer, size_t maxlength) = 0;
virtual void DLLInit_Post() = 0;
virtual void *QueryInterface(const char *name, int *ret) = 0;
virtual void Unload() = 0;
};
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_BRIDGE_H_ */

View File

@ -42,13 +42,14 @@ public:
}
};
IVspBridge *vsp_bridge = NULL;
/**
* The vtable must match the general layout for ISPC. We modify the vtable
* based on what we get back.
*/
class ServerPlugin
{
IVspBridge* bridge;
unsigned int vsp_version;
bool load_allowed;
public:
@ -58,39 +59,16 @@ public:
}
virtual bool Load(QueryValveInterface engineFactory, QueryValveInterface gsFactory)
{
MetamodBackend backend = MMBackend_UNKNOWN;
if (!load_allowed)
return false;
load_allowed = false;
/* Check for L4D */
if (engineFactory("VEngineServer022", NULL) != NULL &&
engineFactory("VEngineCvar007", NULL) != NULL)
{
backend = MMBackend_Left4Dead;
}
else if (engineFactory("VEngineServer021", NULL) != NULL)
{
/* Check for OB */
if (engineFactory("VEngineCvar004", NULL) != NULL &&
engineFactory("VModelInfoServer002", NULL) != NULL)
{
backend = MMBackend_Episode2;
}
/* Check for EP1 */
else if (engineFactory("VModelInfoServer001", NULL) != NULL &&
(engineFactory("VEngineCvar003", NULL) != NULL ||
engineFactory("VEngineCvar002", NULL) != NULL))
{
backend = MMBackend_Episode1;
}
}
MetamodBackend backend = mm_DetermineBackend(engineFactory);
if (backend == MMBackend_UNKNOWN)
{
mm_LogFatal("Could not detect engine version, spewing stats:");
mm_LogFatal("Could not detect engine version");
return false;
}
else if (backend >= MMBackend_Episode2)
@ -134,11 +112,11 @@ public:
if (get_bridge == NULL)
{
mm_UnloadMetamodLibrary();
mm_LogFatal("Detected engine %d but could not find GetVspBridge callback.", backend);
mm_LogFatal("Detected engine %d but could not find GetVspBridge callback", backend);
return false;
}
bridge = get_bridge();
vsp_bridge = get_bridge();
vsp_bridge_info info;
@ -148,8 +126,9 @@ public:
info.vsp_version = vsp_version;
strcpy(error, "Unknown error");
if (!bridge->Load(&info, error, sizeof(error)))
if (!vsp_bridge->Load(&info, error, sizeof(error)))
{
vsp_bridge = NULL;
mm_UnloadMetamodLibrary();
mm_LogFatal("Unknown error loading Metamod for engine %d: %s", backend, error);
return false;
@ -159,9 +138,9 @@ public:
}
virtual void Unload()
{
if (bridge == NULL)
if (vsp_bridge == NULL)
return;
bridge->Unload();
vsp_bridge->Unload();
mm_UnloadMetamodLibrary();
}
virtual void Pause()
@ -172,9 +151,9 @@ public:
}
virtual const char *GetPluginDescription()
{
if (bridge == NULL)
if (vsp_bridge == NULL)
return "Metamod:Source Loader Shim";
return bridge->GetDescription();
return vsp_bridge->GetDescription();
}
virtual void LevelInit(char const *pMapName)
{
@ -232,17 +211,13 @@ public:
vsp_version = version;
load_allowed = true;
}
bool IsLoaded()
{
return bridge != NULL;
}
};
ServerPlugin mm_vsp_callbacks;
void *mm_GetVspCallbacks(unsigned int version)
{
if (mm_vsp_callbacks.IsLoaded())
if (vsp_bridge != NULL)
return NULL;
/* Only support versions 1 or 2 right now */

View File

@ -6,5 +6,7 @@
extern void *
mm_GetVspCallbacks(unsigned int version);
extern IVspBridge *vsp_bridge;
#endif /* _INCLUDE_METAMOD_SOURCE_SERVERPLUGINS_H_ */

303
loader/utility.cpp Normal file
View File

@ -0,0 +1,303 @@
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include "loader.h"
#include "utility.h"
size_t
mm_FormatArgs(char *buffer, size_t maxlength, const char *fmt, va_list params)
{
size_t len = vsnprintf(buffer, maxlength, fmt, params);
if (len >= maxlength)
{
len = maxlength - 1;
buffer[len] = '\0';
}
return len;
}
size_t
mm_Format(char *buffer, size_t maxlength, const char *fmt, ...)
{
size_t len;
va_list ap;
va_start(ap, fmt);
len = mm_FormatArgs(buffer, maxlength, fmt, ap);
va_end(ap);
return len;
}
size_t
mm_PathFormat(char *buffer, size_t maxlen, const char *fmt, ...)
{
size_t len;
va_list ap;
va_start(ap, fmt);
len = mm_FormatArgs(buffer, maxlen, fmt, ap);
va_end(ap);
for (size_t i = 0; i < len; i++)
{
if (buffer[i] == ALT_SEP_CHAR)
buffer[i] = PATH_SEP_CHAR;
}
return len;
}
void
mm_TrimLeft(char *buffer)
{
/* Let's think of this as our iterator */
char *i = buffer;
/* Make sure the buffer isn't null */
if (i && *i)
{
/* Add up number of whitespace characters */
while(isspace((unsigned char) *i))
i++;
/* If whitespace chars in buffer then adjust string so first non-whitespace char is at start of buffer */
if (i != buffer)
memmove(buffer, i, (strlen(i) + 1) * sizeof(char));
}
}
void
mm_TrimRight(char *buffer)
{
/* Make sure buffer isn't null */
if (buffer)
{
size_t len = strlen(buffer);
/* Loop through buffer backwards while replacing whitespace chars with null chars */
for (size_t i = len - 1; i >= 0; i--)
{
if (isspace((unsigned char) buffer[i]))
buffer[i] = '\0';
else
break;
}
}
}
/* :TODO: this should skip string literals */
void
mm_TrimComments(char *buffer)
{
int num_sc = 0;
size_t len = strlen(buffer);
if (buffer)
{
for (int i = len - 1; i >= 0; i--)
{
if (buffer[i] == '/')
{
if (++num_sc >= 2 && i==0)
{
buffer[i] = '\0';
return;
}
}
else
{
if (num_sc >= 2)
{
buffer[i] = '\0';
return;
}
num_sc = 0;
}
/* size_t won't go below 0, manually break out */
if (i == 0)
break;
}
}
}
void
mm_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2)
{
size_t start;
size_t len = strlen(str);
for (start = 0; start < len; start++)
{
if (!isspace(str[start]))
break;
}
size_t end;
for (end = start; end < len; end++)
{
if (isspace(str[end]))
break;
}
size_t i, c = 0;
for (i = start; i < end; i++, c++)
{
if (c >= len1)
break;
buf1[c] = str[i];
}
buf1[c] = '\0';
for (start = end; start < len; start++)
{
if (!isspace(str[start]))
break;
}
for (c = 0; start < len; start++, c++)
{
if (c >= len2)
break;
buf2[c] = str[start];
}
buf2[c] = '\0';
}
bool
mm_PathCmp(const char *path1, const char *path2)
{
size_t pos1 = 0, pos2 = 0;
while (true)
{
if (path1[pos1] == '\0' || path2[pos2] == '\0')
return (path1[pos1] == path2[pos2]);
if (path1[pos1] == PATH_SEP_CHAR)
{
if (path2[pos2] != PATH_SEP_CHAR)
return false;
/* Look for extra path chars */
while (path1[++pos1])
{
if (path1[pos1] != PATH_SEP_CHAR)
break;
}
while (path2[++pos2])
{
if (path2[pos2] != PATH_SEP_CHAR)
break;
}
continue;
}
/* If we're at a different non-alphanumeric, the next character MUST match */
if ((((unsigned)path1[pos1] & 0x80) && path1[pos1] != path2[pos2])
||
!isalpha(path1[pos1]) && (path1[pos1] != path2[pos2])
)
{
return false;
}
#ifdef WIN32
if (toupper(path1[pos1]) != toupper(path2[pos2]))
#else
if (path1[pos1] != path2[pos2])
#endif
{
return false;
}
pos1++;
pos2++;
}
}
bool
mm_ResolvePath(const char *path, char *buffer, size_t maxlength)
{
#if defined _WIN32
return _fullpath(buffer, path, maxlength) != NULL;
#elif defined __linux__
assert(maxlength >= PATH_MAX);
return realpath(path, buffer) != NULL;
#endif
}
void *
mm_LoadLibrary(const char *path, char *buffer, size_t maxlength)
{
void *lib;
#if defined _WIN32
lib = LoadLibrary(path);
if (lib == NULL)
{
mm_GetPlatformError(buffer, maxlength);
return NULL;
}
#elif defined __linux__
lib = dlopen(path, RTLD_NOW);
if (lib == NULL)
{
mm_Format(buffer, maxlength, "%s", dlerror());
return NULL;
}
#endif
return lib;
}
void *
mm_GetLibAddress(void *lib, const char *name)
{
#if defined _WIN32
return GetProcAddress(lib, name);
#elif defined __linux__
return dlsym(lib, name);
#endif
}
void
mm_UnloadLibrary(void *lib)
{
#if defined _WIN32
FreeLibrary(lib);
#else
dlclose(lib);
#endif
}
bool
mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
{
#if defined _WIN32
MEMORY_BASIC_INFORMATION mem;
if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
return false;
if (mem.AllocationBase == NULL)
return false;
HMODULE dll = (HMODULE)mem.AllocationBase;
GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
#elif defined __linux__
Dl_info info;
if (!dladdr(pAddr, &info))
return false;
if (!info.dli_fbase || !info.dli_fname)
return false;
const char *dllpath = info.dli_fname;
snprintf(buffer, maxlength, "%s", dllpath);
#endif
return true;
}

43
loader/utility.h Normal file
View File

@ -0,0 +1,43 @@
#ifndef _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_
#define _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_
#include <stddef.h>
extern size_t
mm_Format(char *buffer, size_t maxlength, const char *fmt, ...);
extern void *
mm_LoadLibrary(const char *path, char *buffer, size_t maxlength);
extern void *
mm_GetLibAddress(void *lib, const char *name);
extern void
mm_UnloadLibrary(void *lib);
extern bool
mm_ResolvePath(const char *path, char *buffer, size_t maxlength);
extern size_t
mm_PathFormat(char *buffer, size_t len, const char *fmt, ...);
extern void
mm_TrimLeft(char *buffer);
extern void
mm_TrimRight(char *buffer);
extern void
mm_TrimComments(char *buffer);
extern void
mm_KeySplit(const char *str, char *buf1, size_t len1, char *buf2, size_t len2);
extern bool
mm_PathCmp(const char *path1, const char *path2);
extern bool
mm_GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength);
#endif /* _INCLUDE_METAMOD_SOURCE_LOADER_UTILITY_H_ */

View File

@ -0,0 +1,28 @@
#ifndef _INCLUDE_VALVE_COMMAND_LINE_H_
#define _INCLUDE_VALVE_COMMAND_LINE_H_
class ICommandLine
{
public:
virtual void CreateCmdLine( const char *commandline ) = 0;
virtual void CreateCmdLine( int argc, char **argv ) = 0;
virtual const char *GetCmdLine( void ) const = 0;
// Check whether a particular parameter exists
virtual const char *CheckParm( const char *psz, const char **ppszValue = 0 ) const = 0;
virtual void RemoveParm( const char *parm ) = 0;
virtual void AppendParm( const char *pszParm, const char *pszValues ) = 0;
// Returns the argument after the one specified, or the default if not found
virtual const char *ParmValue( const char *psz, const char *pDefaultVal = 0 ) const = 0;
virtual int ParmValue( const char *psz, int nDefaultVal ) const = 0;
virtual float ParmValue( const char *psz, float flDefaultVal ) const = 0;
// Gets at particular parameters
virtual int ParmCount() const = 0;
virtual int FindParm( const char *psz ) const = 0; // Returns 0 if not found.
virtual const char* GetParm( int nIndex ) const = 0;
};
#endif /* _INCLUDE_VALVE_COMMAND_LINE_H_ */