faluco@1557: /** faluco@1557: * vim: set ts=4 : faluco@1557: * ============================================================================= faluco@1557: * SourceMod ds@1947: * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved. faluco@1557: * ============================================================================= faluco@1557: * faluco@1557: * This program is free software; you can redistribute it and/or modify it under faluco@1557: * the terms of the GNU General Public License, version 3.0, as published by the faluco@1557: * Free Software Foundation. faluco@1557: * faluco@1557: * This program is distributed in the hope that it will be useful, but WITHOUT faluco@1557: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS faluco@1557: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more faluco@1557: * details. faluco@1557: * faluco@1557: * You should have received a copy of the GNU General Public License along with faluco@1557: * this program. If not, see . faluco@1557: * faluco@1557: * As a special exception, AlliedModders LLC gives you permission to link the faluco@1557: * code of this program (as well as its derivative works) to "Half-Life 2," the faluco@1557: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software faluco@1557: * by the Valve Corporation. You must obey the GNU General Public License in faluco@1557: * all respects for all other code used. Additionally, AlliedModders LLC grants faluco@1557: * this exception to all derivative works. AlliedModders LLC defines further faluco@1557: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), faluco@1557: * or . faluco@1557: * faluco@1557: * Version: $Id$ faluco@1557: */ faluco@1557: faluco@1557: #include faluco@1557: #include faluco@1557: #include faluco@1557: #include dvander@2471: #include faluco@1557: faluco@1557: #if defined _MSC_VER faluco@1557: #define DLL_EXPORT extern "C" __declspec(dllexport) faluco@1557: #define openlib(lib) LoadLibrary(lib) faluco@1557: #define closelib(lib) FreeLibrary(lib) faluco@1557: #define findsym(lib, sym) GetProcAddress(lib, sym) faluco@1557: #define PLATFORM_EXT ".dll" faluco@1557: #define vsnprintf _vsnprintf faluco@1557: #define PATH_SEP_CHAR "\\" faluco@1557: inline bool IsPathSepChar(char c) faluco@1557: { faluco@1557: return (c == '/' || c == '\\'); faluco@1557: } faluco@1557: #include pred@2769: #define TF_PATH "\\tf\\" pred@2769: #define DOD_PATH "\\dod\\" faluco@1557: #else faluco@1557: #define DLL_EXPORT extern "C" __attribute__((visibility("default"))) faluco@1557: #define openlib(lib) dlopen(lib, RTLD_NOW) faluco@1557: #define closelib(lib) dlclose(lib) faluco@1557: #define findsym(lib, sym) dlsym(lib, sym) faluco@1557: #define PLATFORM_EXT ".so" faluco@1557: typedef void * HINSTANCE; faluco@1557: #define PATH_SEP_CHAR "/" faluco@1557: inline bool IsPathSepChar(char c) faluco@1557: { faluco@1557: return (c == '/'); faluco@1557: } faluco@1557: #include pred@2769: #define TF_PATH "/tf/" pred@2769: #define DOD_PATH "/dod/" faluco@1557: #endif faluco@1557: faluco@1557: #define METAMOD_API_MAJOR 2 faluco@1557: #define FILENAME_1_4_EP1 "sourcemod.1.ep1" PLATFORM_EXT faluco@1557: #define FILENAME_1_6_EP2 "sourcemod.2.ep2" PLATFORM_EXT dvander@2782: #define FILENAME_1_6_EP2VALVE "sourcemod.2.ep2v" PLATFORM_EXT faluco@1557: #define FILENAME_1_6_EP1 "sourcemod.2.ep1" PLATFORM_EXT ds@2583: #define FILENAME_1_6_L4D "sourcemod.2.l4d" PLATFORM_EXT ds@2583: #define FILENAME_1_6_DARKM "sourcemod.2.darkm" PLATFORM_EXT faluco@1557: faluco@1557: HINSTANCE g_hCore = NULL; dvander@1561: bool load_attempted = false; faluco@1557: dvander@1840: size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...); dvander@1840: dvander@1840: class FailPlugin : public SourceMM::ISmmFailPlugin dvander@1840: { dvander@1840: public: dvander@1840: int GetApiVersion() dvander@1840: { dvander@1840: return fail_version; dvander@1840: } dvander@1840: dvander@1840: bool Load(SourceMM::PluginId id, SourceMM::ISmmAPI *ismm, char *error, size_t maxlength, bool late) dvander@1840: { dvander@1840: if (error != NULL && maxlength != 0) dvander@1840: { dvander@1840: UTIL_Format(error, maxlength, "%s", error_buffer); dvander@1840: } dvander@1840: return false; dvander@1840: } dvander@1840: dvander@1840: int fail_version; dvander@1840: char error_buffer[512]; dvander@1840: } s_FailPlugin; dvander@1840: faluco@1557: size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...) faluco@1557: { faluco@1557: va_list ap; faluco@1557: faluco@1557: va_start(ap, fmt); faluco@1557: size_t len = vsnprintf(buffer, maxlength, fmt, ap); faluco@1557: va_end(ap); faluco@1557: faluco@1557: if (len >= maxlength) faluco@1557: { faluco@1557: len = maxlength - 1; faluco@1557: buffer[len] = '\0'; faluco@1557: } faluco@1557: faluco@1557: return len; faluco@1557: } faluco@1557: dvander@1840: METAMOD_PLUGIN *_GetPluginPtr(const char *path, int fail_api) faluco@1557: { faluco@1557: METAMOD_FN_ORIG_LOAD fn; faluco@1557: METAMOD_PLUGIN *pl; faluco@1557: int ret; faluco@1557: faluco@1557: if (!(g_hCore=openlib(path))) faluco@1557: { dvander@2471: #if defined __linux__ || defined __APPLE__ dvander@1840: UTIL_Format(s_FailPlugin.error_buffer, dvander@1840: sizeof(s_FailPlugin.error_buffer), dvander@1840: "%s", dvander@1840: dlerror()); dvander@1840: #else dvander@1840: DWORD err = GetLastError(); dvander@1840: dvander@1840: if (FormatMessageA( dvander@1840: FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, dvander@1840: NULL, dvander@1840: err, dvander@1840: MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), dvander@1840: s_FailPlugin.error_buffer, dvander@1840: sizeof(s_FailPlugin.error_buffer), dvander@1840: NULL) dvander@1840: == 0) dvander@1840: { dvander@1840: UTIL_Format(s_FailPlugin.error_buffer, dvander@1840: sizeof(s_FailPlugin.error_buffer), dvander@1840: "unknown error %x", dvander@1840: err); dvander@1840: } dvander@1840: #endif dvander@1840: dvander@1840: s_FailPlugin.fail_version = fail_api; dvander@1840: dvander@1840: return (METAMOD_PLUGIN *)&s_FailPlugin; faluco@1557: } faluco@1557: faluco@1557: if (!(fn=(METAMOD_FN_ORIG_LOAD)findsym(g_hCore, "CreateInterface"))) faluco@1557: { faluco@1557: goto error; faluco@1557: } faluco@1557: faluco@1557: pl = (METAMOD_PLUGIN *)fn(METAMOD_PLAPI_NAME, &ret); faluco@1557: if (!pl) faluco@1557: { faluco@1557: goto error; faluco@1557: } faluco@1557: faluco@1557: return pl; faluco@1557: error: faluco@1557: closelib(g_hCore); faluco@1557: g_hCore = NULL; faluco@1557: return NULL; faluco@1557: } faluco@1557: faluco@1557: bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength) faluco@1557: { faluco@1557: #if defined _MSC_VER faluco@1557: MEMORY_BASIC_INFORMATION mem; faluco@1557: if (!VirtualQuery(pAddr, &mem, sizeof(mem))) faluco@1557: return false; faluco@1557: if (mem.AllocationBase == NULL) faluco@1557: return false; faluco@1557: HMODULE dll = (HMODULE)mem.AllocationBase; faluco@1557: GetModuleFileName(dll, (LPTSTR)buffer, maxlength); faluco@1557: #else faluco@1557: Dl_info info; faluco@1557: if (!dladdr(pAddr, &info)) faluco@1557: return false; faluco@1557: if (!info.dli_fbase || !info.dli_fname) faluco@1557: return false; faluco@1557: const char *dllpath = info.dli_fname; faluco@1557: snprintf(buffer, maxlength, "%s", dllpath); faluco@1557: #endif faluco@1557: return true; faluco@1557: } faluco@1557: faluco@1557: DLL_EXPORT METAMOD_PLUGIN *CreateInterface_MMS(const MetamodVersionInfo *mvi, const MetamodLoaderInfo *mli) faluco@1557: { faluco@1557: char *filename; dvander@1561: dvander@1561: load_attempted = true; faluco@1557: faluco@1557: if (mvi->api_major > METAMOD_API_MAJOR) faluco@1557: { faluco@1557: return NULL; faluco@1557: } faluco@1557: faluco@1557: switch (mvi->source_engine) faluco@1557: { ds@2583: case SOURCE_ENGINE_ORIGINAL: ds@2583: case SOURCE_ENGINE_EPISODEONE: ds@2583: { ds@2583: filename = FILENAME_1_6_EP1; ds@2583: break; ds@2583: } faluco@1557: case SOURCE_ENGINE_ORANGEBOX: faluco@1557: { pred@2769: if (strstr(mli->pl_path, TF_PATH) || strstr(mli->pl_path, DOD_PATH)) pred@2768: { pred@2768: filename = FILENAME_1_6_EP2VALVE; pred@2768: break; pred@2768: } pred@2768: faluco@1557: filename = FILENAME_1_6_EP2; faluco@1557: break; faluco@1557: } ds@2583: case SOURCE_ENGINE_LEFT4DEAD: faluco@1557: { ds@2583: filename = FILENAME_1_6_L4D; faluco@1557: break; faluco@1557: } ds@2583: case SOURCE_ENGINE_DARKMESSIAH: ds@2400: { ds@2583: filename = FILENAME_1_6_DARKM; ds@2400: break; ds@2400: } faluco@1557: default: faluco@1557: { faluco@1557: return NULL; faluco@1557: } faluco@1557: } faluco@1557: faluco@1557: char abspath[256]; faluco@1557: UTIL_Format(abspath, sizeof(abspath), "%s" PATH_SEP_CHAR "%s", mli->pl_path, filename); faluco@1557: dvander@1840: return _GetPluginPtr(abspath, METAMOD_FAIL_API_V2); faluco@1557: } faluco@1557: faluco@1557: DLL_EXPORT void UnloadInterface_MMS() faluco@1557: { faluco@1557: if (g_hCore) faluco@1557: { faluco@1557: closelib(g_hCore); faluco@1557: g_hCore = NULL; faluco@1557: } faluco@1557: } faluco@1557: faluco@1557: DLL_EXPORT void *CreateInterface(const char *iface, int *ret) faluco@1557: { dvander@1561: /** dvander@1561: * If a load has already been attempted, bail out immediately. dvander@1561: */ dvander@1561: if (load_attempted) dvander@1561: { dvander@1561: return NULL; dvander@1561: } dvander@1561: dvander@1561: if (strcmp(iface, METAMOD_PLAPI_NAME) == 0) faluco@1557: { faluco@1557: char thisfile[256]; faluco@1557: char targetfile[256]; faluco@1557: faluco@1557: if (!GetFileOfAddress((void *)CreateInterface_MMS, thisfile, sizeof(thisfile))) faluco@1557: { faluco@1557: return NULL; faluco@1557: } faluco@1557: faluco@1557: size_t len = strlen(thisfile); faluco@1557: for (size_t iter=len-1; iter>=0 && iter