diff -r 000000000000 -r c24a6fa957db loader/loader.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/loader/loader.cpp Sun Jul 06 04:49:55 2008 +0000 @@ -0,0 +1,318 @@ +/** + * vim: set ts=4 : + * ============================================================================= + * SourceMod + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. + * ============================================================================= + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, version 3.0, as published by the + * Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + * + * As a special exception, AlliedModders LLC gives you permission to link the + * code of this program (as well as its derivative works) to "Half-Life 2," the + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software + * by the Valve Corporation. You must obey the GNU General Public License in + * all respects for all other code used. Additionally, AlliedModders LLC grants + * this exception to all derivative works. AlliedModders LLC defines further + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), + * or . + * + * Version: $Id$ + */ + +#include +#include +#include +#include +#include + +#if defined _MSC_VER + #define DLL_EXPORT extern "C" __declspec(dllexport) + #define openlib(lib) LoadLibrary(lib) + #define closelib(lib) FreeLibrary(lib) + #define findsym(lib, sym) GetProcAddress(lib, sym) + #define PLATFORM_EXT ".dll" + #define vsnprintf _vsnprintf + #define PATH_SEP_CHAR "\\" + inline bool IsPathSepChar(char c) + { + return (c == '/' || c == '\\'); + } + #include +#else + #define DLL_EXPORT extern "C" __attribute__((visibility("default"))) + #define openlib(lib) dlopen(lib, RTLD_NOW) + #define closelib(lib) dlclose(lib) + #define findsym(lib, sym) dlsym(lib, sym) + #define PLATFORM_EXT ".so" + typedef void * HINSTANCE; + #define PATH_SEP_CHAR "/" + inline bool IsPathSepChar(char c) + { + return (c == '/'); + } + #include +#endif + +#define METAMOD_API_MAJOR 2 +#define FILENAME_1_4_EP1 "sourcemod.1.ep1" PLATFORM_EXT +#define FILENAME_1_6_EP2 "sourcemod.2.ep2" PLATFORM_EXT +#define FILENAME_1_6_EP1 "sourcemod.2.ep1" PLATFORM_EXT + +HINSTANCE g_hCore = NULL; +bool load_attempted = false; + +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); + +class FailPlugin : public SourceMM::ISmmFailPlugin +{ +public: + int GetApiVersion() + { + return fail_version; + } + + bool Load(SourceMM::PluginId id, SourceMM::ISmmAPI *ismm, char *error, size_t maxlength, bool late) + { + if (error != NULL && maxlength != 0) + { + UTIL_Format(error, maxlength, "%s", error_buffer); + } + return false; + } + + int fail_version; + char error_buffer[512]; +} s_FailPlugin; + +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; +} + +METAMOD_PLUGIN *_GetPluginPtr(const char *path, int fail_api) +{ + METAMOD_FN_ORIG_LOAD fn; + METAMOD_PLUGIN *pl; + int ret; + + if (!(g_hCore=openlib(path))) + { +#if defined __linux__ + UTIL_Format(s_FailPlugin.error_buffer, + sizeof(s_FailPlugin.error_buffer), + "%s", + dlerror()); +#else + DWORD err = GetLastError(); + + if (FormatMessageA( + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + s_FailPlugin.error_buffer, + sizeof(s_FailPlugin.error_buffer), + NULL) + == 0) + { + UTIL_Format(s_FailPlugin.error_buffer, + sizeof(s_FailPlugin.error_buffer), + "unknown error %x", + err); + } +#endif + + s_FailPlugin.fail_version = fail_api; + + return (METAMOD_PLUGIN *)&s_FailPlugin; + } + + if (!(fn=(METAMOD_FN_ORIG_LOAD)findsym(g_hCore, "CreateInterface"))) + { + goto error; + } + + pl = (METAMOD_PLUGIN *)fn(METAMOD_PLAPI_NAME, &ret); + if (!pl) + { + goto error; + } + + return pl; +error: + closelib(g_hCore); + g_hCore = NULL; + return NULL; +} + +bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength) +{ +#if defined _MSC_VER + 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; +} + +DLL_EXPORT METAMOD_PLUGIN *CreateInterface_MMS(const MetamodVersionInfo *mvi, const MetamodLoaderInfo *mli) +{ + char *filename; + + load_attempted = true; + + if (mvi->api_major > METAMOD_API_MAJOR) + { + return NULL; + } + + switch (mvi->source_engine) + { + case SOURCE_ENGINE_ORANGEBOX: + { + filename = FILENAME_1_6_EP2; + break; + } + case SOURCE_ENGINE_EPISODEONE: + case SOURCE_ENGINE_ORIGINAL: + { + filename = FILENAME_1_6_EP1; + break; + } + default: + { + return NULL; + } + } + + char abspath[256]; + UTIL_Format(abspath, sizeof(abspath), "%s" PATH_SEP_CHAR "%s", mli->pl_path, filename); + + return _GetPluginPtr(abspath, METAMOD_FAIL_API_V2); +} + +DLL_EXPORT void UnloadInterface_MMS() +{ + if (g_hCore) + { + closelib(g_hCore); + g_hCore = NULL; + } +} + +DLL_EXPORT void *CreateInterface(const char *iface, int *ret) +{ + /** + * If a load has already been attempted, bail out immediately. + */ + if (load_attempted) + { + return NULL; + } + + if (strcmp(iface, METAMOD_PLAPI_NAME) == 0) + { + char thisfile[256]; + char targetfile[256]; + + if (!GetFileOfAddress((void *)CreateInterface_MMS, thisfile, sizeof(thisfile))) + { + return NULL; + } + + size_t len = strlen(thisfile); + for (size_t iter=len-1; iter>=0 && iter