loader/loader.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2289 44045ead61cd
permissions -rw-r--r--
Spring Cleaning, Part Ichi (1)
Various minor things done to project files
Updated sample extension project file and updated makefile to the new unified version (more changes likely on the way)
Updated regex project file and makefile
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <ISmmPluginExt.h>
    33 #include <stdarg.h>
    34 #include <string.h>
    35 #include <stdio.h>
    36 #include <malloc.h>
    37 
    38 #if defined _MSC_VER
    39 	#define DLL_EXPORT				extern "C" __declspec(dllexport)
    40 	#define openlib(lib)			LoadLibrary(lib)
    41 	#define closelib(lib)			FreeLibrary(lib)
    42 	#define findsym(lib, sym)		GetProcAddress(lib, sym)
    43 	#define PLATFORM_EXT			".dll"
    44 	#define vsnprintf				_vsnprintf
    45 	#define PATH_SEP_CHAR			"\\"
    46 	inline bool IsPathSepChar(char c) 
    47 	{
    48 		return (c == '/' || c == '\\');
    49 	}
    50 	#include <Windows.h>
    51 #else
    52 	#define DLL_EXPORT				extern "C" __attribute__((visibility("default")))
    53 	#define openlib(lib)			dlopen(lib, RTLD_NOW)
    54 	#define closelib(lib)			dlclose(lib)
    55 	#define findsym(lib, sym)		dlsym(lib, sym)
    56 	#define PLATFORM_EXT			".so"
    57 	typedef void *					HINSTANCE;
    58 	#define PATH_SEP_CHAR			"/"
    59 	inline bool IsPathSepChar(char c) 
    60 	{
    61 		return (c == '/');
    62 	}
    63 	#include <dlfcn.h>
    64 #endif
    65 
    66 #define METAMOD_API_MAJOR			2
    67 #define FILENAME_1_4_EP1			"sourcemod.1.ep1" PLATFORM_EXT
    68 #define FILENAME_1_6_EP2			"sourcemod.2.ep2" PLATFORM_EXT
    69 #define FILENAME_1_6_EP1			"sourcemod.2.ep1" PLATFORM_EXT
    70 
    71 HINSTANCE g_hCore = NULL;
    72 bool load_attempted = false;
    73 
    74 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...);
    75 
    76 class FailPlugin : public SourceMM::ISmmFailPlugin
    77 {
    78 public:
    79 	int GetApiVersion()
    80 	{
    81 		return fail_version;
    82 	}
    83 
    84 	bool Load(SourceMM::PluginId id, SourceMM::ISmmAPI *ismm, char *error, size_t maxlength, bool late)
    85 	{
    86 		if (error != NULL && maxlength != 0)
    87 		{
    88 			UTIL_Format(error, maxlength, "%s", error_buffer);
    89 		}
    90 		return false;
    91 	}
    92 
    93 	int fail_version;
    94 	char error_buffer[512];
    95 } s_FailPlugin;
    96 
    97 size_t UTIL_Format(char *buffer, size_t maxlength, const char *fmt, ...)
    98 {
    99 	va_list ap;
   100 
   101 	va_start(ap, fmt);
   102 	size_t len = vsnprintf(buffer, maxlength, fmt, ap);
   103 	va_end(ap);
   104 
   105 	if (len >= maxlength)
   106 	{
   107 		len = maxlength - 1;
   108 		buffer[len] = '\0';
   109 	}
   110 
   111 	return len;
   112 }
   113 
   114 METAMOD_PLUGIN *_GetPluginPtr(const char *path, int fail_api)
   115 {
   116 	METAMOD_FN_ORIG_LOAD fn;
   117 	METAMOD_PLUGIN *pl;
   118 	int ret;
   119 
   120 	if (!(g_hCore=openlib(path)))
   121 	{
   122 #if defined __linux__
   123 		UTIL_Format(s_FailPlugin.error_buffer, 
   124 			sizeof(s_FailPlugin.error_buffer),
   125 			"%s",
   126 			dlerror());
   127 #else
   128 		DWORD err = GetLastError();
   129 
   130 		if (FormatMessageA(
   131 				FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
   132 				NULL,
   133 				err,
   134 				MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
   135 				s_FailPlugin.error_buffer,
   136 				sizeof(s_FailPlugin.error_buffer),
   137 				NULL)
   138 			== 0)
   139 		{
   140 			UTIL_Format(s_FailPlugin.error_buffer, 
   141 				sizeof(s_FailPlugin.error_buffer),
   142 				"unknown error %x",
   143 				err);
   144 		}
   145 #endif
   146 
   147 		s_FailPlugin.fail_version = fail_api;
   148 
   149 		return (METAMOD_PLUGIN *)&s_FailPlugin;
   150 	}
   151 
   152 	if (!(fn=(METAMOD_FN_ORIG_LOAD)findsym(g_hCore, "CreateInterface")))
   153 	{
   154 		goto error;
   155 	}
   156 
   157 	pl = (METAMOD_PLUGIN *)fn(METAMOD_PLAPI_NAME, &ret);
   158 	if (!pl)
   159 	{
   160 		goto error;
   161 	}
   162 
   163 	return pl;
   164 error:
   165 	closelib(g_hCore);
   166 	g_hCore = NULL;
   167 	return NULL;
   168 }
   169 
   170 bool GetFileOfAddress(void *pAddr, char *buffer, size_t maxlength)
   171 {
   172 #if defined _MSC_VER
   173 	MEMORY_BASIC_INFORMATION mem;
   174 	if (!VirtualQuery(pAddr, &mem, sizeof(mem)))
   175 		return false;
   176 	if (mem.AllocationBase == NULL)
   177 		return false;
   178 	HMODULE dll = (HMODULE)mem.AllocationBase;
   179 	GetModuleFileName(dll, (LPTSTR)buffer, maxlength);
   180 #else
   181 	Dl_info info;
   182 	if (!dladdr(pAddr, &info))
   183 		return false;
   184 	if (!info.dli_fbase || !info.dli_fname)
   185 		return false;
   186 	const char *dllpath = info.dli_fname;
   187 	snprintf(buffer, maxlength, "%s", dllpath);
   188 #endif
   189 	return true;
   190 }
   191 
   192 DLL_EXPORT METAMOD_PLUGIN *CreateInterface_MMS(const MetamodVersionInfo *mvi, const MetamodLoaderInfo *mli)
   193 {
   194 	char *filename;
   195 
   196 	load_attempted = true;
   197 	
   198 	if (mvi->api_major > METAMOD_API_MAJOR)
   199 	{
   200 		return NULL;
   201 	}
   202 
   203 	switch (mvi->source_engine)
   204 	{
   205 	case SOURCE_ENGINE_ORANGEBOX:
   206 		{
   207 			filename = FILENAME_1_6_EP2;
   208 			break;
   209 		}
   210 	case SOURCE_ENGINE_EPISODEONE:
   211 	case SOURCE_ENGINE_ORIGINAL:
   212 		{
   213 			filename = FILENAME_1_6_EP1;
   214 			break;
   215 		}
   216 	default:
   217 		{
   218 			return NULL;
   219 		}
   220 	}
   221 
   222 	char abspath[256];
   223 	UTIL_Format(abspath, sizeof(abspath), "%s" PATH_SEP_CHAR "%s", mli->pl_path, filename);
   224 
   225 	return _GetPluginPtr(abspath, METAMOD_FAIL_API_V2);
   226 }
   227 
   228 DLL_EXPORT void UnloadInterface_MMS()
   229 {
   230 	if (g_hCore)
   231 	{
   232 		closelib(g_hCore);
   233 		g_hCore = NULL;
   234 	}
   235 }
   236 
   237 DLL_EXPORT void *CreateInterface(const char *iface, int *ret)
   238 {
   239 	/**
   240 	 * If a load has already been attempted, bail out immediately.
   241 	 */
   242 	if (load_attempted)
   243 	{
   244 		return NULL;
   245 	}
   246 
   247 	if (strcmp(iface, METAMOD_PLAPI_NAME) == 0)
   248 	{
   249 		char thisfile[256];
   250 		char targetfile[256];
   251 
   252 		if (!GetFileOfAddress((void *)CreateInterface_MMS, thisfile, sizeof(thisfile)))
   253 		{
   254 			return NULL;
   255 		}
   256 
   257 		size_t len = strlen(thisfile);
   258 		for (size_t iter=len-1; iter>=0 && iter<len; iter--)
   259 		{
   260 			if (IsPathSepChar(thisfile[iter]))
   261 			{
   262 				thisfile[iter] = '\0';
   263 				break;
   264 			}
   265 		}
   266 
   267 		UTIL_Format(targetfile, sizeof(targetfile), "%s" PATH_SEP_CHAR FILENAME_1_4_EP1, thisfile);
   268 
   269 		return _GetPluginPtr(targetfile, METAMOD_FAIL_API_V1);
   270 	}
   271 
   272 	return NULL;
   273 }
   274 
   275 #if defined _MSC_VER
   276 BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
   277 {
   278 	if (fdwReason == DLL_PROCESS_DETACH)
   279 	{
   280 		UnloadInterface_MMS();
   281 	}
   282 	return TRUE;
   283 }
   284 #else
   285 __attribute__((destructor)) static void gcc_fini()
   286 {
   287 	UnloadInterface_MMS();
   288 }
   289 #endif
   290 
   291 /* Overload a few things to prevent libstdc++ linking */
   292 #if defined __linux__
   293 extern "C" void __cxa_pure_virtual(void)
   294 {
   295 }
   296 
   297 void *operator new(size_t size)
   298 {
   299 	return malloc(size);
   300 }
   301 
   302 void *operator new[](size_t size)
   303 {
   304 	return malloc(size);
   305 }
   306 
   307 void operator delete(void *ptr)
   308 {
   309 	free(ptr);
   310 }
   311 
   312 void operator delete[](void * ptr)
   313 {
   314 	free(ptr);
   315 }
   316 #endif
   317 
   318