1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/loader/loader.cpp Sun Mar 30 07:00:22 2008 +0000
1.3 @@ -0,0 +1,318 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <ISmmPluginExt.h>
1.36 +#include <stdarg.h>
1.37 +#include <string.h>
1.38 +#include <stdio.h>
1.39 +#include <malloc.h>
1.40 +
1.41 +#if defined _MSC_VER
1.42 + #define DLL_EXPORT extern "C" __declspec(dllexport)
1.43 + #define openlib(lib) LoadLibrary(lib)
1.44 + #define closelib(lib) FreeLibrary(lib)
1.45 + #define findsym(lib, sym) GetProcAddress(lib, sym)
1.46 + #define PLATFORM_EXT ".dll"
1.47 + #define vsnprintf _vsnprintf
1.48 + #define PATH_SEP_CHAR "\\"
1.49 + inline bool IsPathSepChar(char c)
1.50 + {
1.51 + return (c == '/' || c == '\\');
1.52 + }
1.53 + #include <Windows.h>
1.54 +#else
1.55 + #define DLL_EXPORT extern "C" __attribute__((visibility("default")))
1.56 + #define openlib(lib) dlopen(lib, RTLD_NOW)
1.57 + #define closelib(lib) dlclose(lib)
1.58 + #define findsym(lib, sym) dlsym(lib, sym)
1.59 + #define PLATFORM_EXT ".so"
1.60 + typedef void * HINSTANCE;
1.61 + #define PATH_SEP_CHAR "/"
1.62 + inline bool IsPathSepChar(char c)
1.63 + {
1.64 + return (c == '/');
1.65 + }
1.66 + #include <dlfcn.h>
1.67 +#endif
1.68 +
1.69 +#define METAMOD_API_MAJOR 2
1.70 +#define FILENAME_1_4_EP1 "sourcemod.1.ep1" PLATFORM_EXT
1.71 +#define FILENAME_1_6_EP2 "sourcemod.2.ep2" PLATFORM_EXT
1.72 +#define FILENAME_1_6_EP1 "sourcemod.2.ep1" PLATFORM_EXT
1.73 +
1.74 +HINSTANCE g_hCore = NULL;
1.75 +bool load_attempted = false;
1.76 +
1.77 +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
1.78 +
1.79 +class FailPlugin : public SourceMM::ISmmFailPlugin
1.80 +{
1.81 +public:
1.82 + int GetApiVersion()
1.83 + {
1.84 + return fail_version;
1.85 + }
1.86 +
1.87 + bool Load(SourceMM::PluginId id, SourceMM::ISmmAPI *ismm, char *error, size_t maxlength, bool late)
1.88 + {
1.89 + if (error != NULL && maxlength != 0)
1.90 + {
1.91 + UTIL_Format(error, maxlength, "%s", error_buffer);
1.92 + }
1.93 + return false;
1.94 + }
1.95 +
1.96 + int fail_version;
1.97 + char error_buffer[512];
1.98 +} s_FailPlugin;
1.99 +
1.100 +size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
1.101 +{
1.102 + va_list ap;
1.103 +
1.104 + va_start(ap, fmt);
1.105 + size_t len = vsnprintf(buffer, maxlength, fmt, ap);
1.106 + va_end(ap);
1.107 +
1.108 + if (len >= maxlength)
1.109 + {
1.110 + len = maxlength - 1;
1.111 + buffer[len] = '\0';
1.112 + }
1.113 +
1.114 + return len;
1.115 +}
1.116 +
1.117 +METAMOD_PLUGIN *_GetPluginPtr(const char *path, int fail_api)
1.118 +{
1.119 + METAMOD_FN_ORIG_LOAD fn;
1.120 + METAMOD_PLUGIN *pl;
1.121 + int ret;
1.122 +
1.123 + if (!(g_hCore=openlib(path)))
1.124 + {
1.125 +#if defined __linux__
1.126 + UTIL_Format(s_FailPlugin.error_buffer,
1.127 + sizeof(s_FailPlugin.error_buffer),
1.128 + "%s",
1.129 + dlerror());
1.130 +#else
1.131 + DWORD err = GetLastError();
1.132 +
1.133 + if (FormatMessageA(
1.134 + FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
1.135 + NULL,
1.136 + err,
1.137 + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1.138 + s_FailPlugin.error_buffer,
1.139 + sizeof(s_FailPlugin.error_buffer),
1.140 + NULL)
1.141 + == 0)
1.142 + {
1.143 + UTIL_Format(s_FailPlugin.error_buffer,
1.144 + sizeof(s_FailPlugin.error_buffer),
1.145 + "unknown error %x",
1.146 + err);
1.147 + }
1.148 +#endif
1.149 +
1.150 + s_FailPlugin.fail_version = fail_api;
1.151 +
1.152 + return (METAMOD_PLUGIN *)&s_FailPlugin;
1.153 + }
1.154 +
1.155 + if (!(fn=(METAMOD_FN_ORIG_LOAD)findsym(g_hCore, "CreateInterface")))
1.156 + {
1.157 + goto error;
1.158 + }
1.159 +
1.160 + pl = (METAMOD_PLUGIN *)fn(METAMOD_PLAPI_NAME, &ret);
1.161 + if (!pl)
1.162 + {
1.163 + goto error;
1.164 + }
1.165 +
1.166 + return pl;
1.167 +error:
1.168 + closelib(g_hCore);
1.169 + g_hCore = NULL;
1.170 + return NULL;
1.171 +}
1.172 +
1.173 +bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
1.174 +{
1.175 +#if defined _MSC_VER
1.176 + MEMORY_BASIC_INFORMATION mem;
1.177 + if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
1.178 + return false;
1.179 + if (mem.AllocationBase == NULL)
1.180 + return false;
1.181 + HMODULE dll = (HMODULE)mem.AllocationBase;
1.182 + GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
1.183 +#else
1.184 + Dl_info info;
1.185 + if (!dladdr(pAddr, &info))
1.186 + return false;
1.187 + if (!info.dli_fbase || !info.dli_fname)
1.188 + return false;
1.189 + const char *dllpath = info.dli_fname;
1.190 + snprintf(buffer, maxlength, "%s", dllpath);
1.191 +#endif
1.192 + return true;
1.193 +}
1.194 +
1.195 +DLL_EXPORT METAMOD_PLUGIN *CreateInterface_MMS(const MetamodVersionInfo *mvi, const MetamodLoaderInfo *mli)
1.196 +{
1.197 + char *filename;
1.198 +
1.199 + load_attempted = true;
1.200 +
1.201 + if (mvi->api_major > METAMOD_API_MAJOR)
1.202 + {
1.203 + return NULL;
1.204 + }
1.205 +
1.206 + switch (mvi->source_engine)
1.207 + {
1.208 + case SOURCE_ENGINE_ORANGEBOX:
1.209 + {
1.210 + filename = FILENAME_1_6_EP2;
1.211 + break;
1.212 + }
1.213 + case SOURCE_ENGINE_EPISODEONE:
1.214 + case SOURCE_ENGINE_ORIGINAL:
1.215 + {
1.216 + filename = FILENAME_1_6_EP1;
1.217 + break;
1.218 + }
1.219 + default:
1.220 + {
1.221 + return NULL;
1.222 + }
1.223 + }
1.224 +
1.225 + char abspath[256];
1.226 + UTIL_Format(abspath, sizeof(abspath), "%s" PATH_SEP_CHAR "%s", mli->pl_path, filename);
1.227 +
1.228 + return _GetPluginPtr(abspath, METAMOD_FAIL_API_V2);
1.229 +}
1.230 +
1.231 +DLL_EXPORT void UnloadInterface_MMS()
1.232 +{
1.233 + if (g_hCore)
1.234 + {
1.235 + closelib(g_hCore);
1.236 + g_hCore = NULL;
1.237 + }
1.238 +}
1.239 +
1.240 +DLL_EXPORT void *CreateInterface(const char *iface, int *ret)
1.241 +{
1.242 + /**
1.243 + * If a load has already been attempted, bail out immediately.
1.244 + */
1.245 + if (load_attempted)
1.246 + {
1.247 + return NULL;
1.248 + }
1.249 +
1.250 + if (strcmp(iface, METAMOD_PLAPI_NAME) == 0)
1.251 + {
1.252 + char thisfile[256];
1.253 + char targetfile[256];
1.254 +
1.255 + if (!GetFileOfAddress((void *)CreateInterface_MMS, thisfile, sizeof(thisfile)))
1.256 + {
1.257 + return NULL;
1.258 + }
1.259 +
1.260 + size_t len = strlen(thisfile);
1.261 + for (size_t iter=len-1; iter>=0 && iter<len; iter--)
1.262 + {
1.263 + if (IsPathSepChar(thisfile[iter]))
1.264 + {
1.265 + thisfile[iter] = '\0';
1.266 + break;
1.267 + }
1.268 + }
1.269 +
1.270 + UTIL_Format(targetfile, sizeof(targetfile), "%s" PATH_SEP_CHAR FILENAME_1_4_EP1, thisfile);
1.271 +
1.272 + return _GetPluginPtr(targetfile, METAMOD_FAIL_API_V1);
1.273 + }
1.274 +
1.275 + return NULL;
1.276 +}
1.277 +
1.278 +#if defined _MSC_VER
1.279 +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
1.280 +{
1.281 + if (fdwReason == DLL_PROCESS_DETACH)
1.282 + {
1.283 + UnloadInterface_MMS();
1.284 + }
1.285 + return TRUE;
1.286 +}
1.287 +#else
1.288 +__attribute__((destructor)) static void gcc_fini()
1.289 +{
1.290 + UnloadInterface_MMS();
1.291 +}
1.292 +#endif
1.293 +
1.294 +/* Overload a few things to prevent libstdc++ linking */
1.295 +#if defined __linux__
1.296 +extern "C" void __cxa_pure_virtual(void)
1.297 +{
1.298 +}
1.299 +
1.300 +void *operator new(size_t size)
1.301 +{
1.302 + return malloc(size);
1.303 +}
1.304 +
1.305 +void *operator new[](size_t size)
1.306 +{
1.307 + return malloc(size);
1.308 +}
1.309 +
1.310 +void operator delete(void *ptr)
1.311 +{
1.312 + free(ptr);
1.313 +}
1.314 +
1.315 +void operator delete[](void * ptr)
1.316 +{
1.317 + free(ptr);
1.318 +}
1.319 +#endif
1.320 +
1.321 +