core/GameConfigs.cpp
changeset 947 04dcaa8312e7
parent 729 110c14c99545
child 949 4cc7fd7adb8a
     1.1 --- a/core/GameConfigs.cpp	Sat Jun 16 05:40:18 2007 +0000
     1.2 +++ b/core/GameConfigs.cpp	Sat Jun 16 05:42:16 2007 +0000
     1.3 @@ -22,6 +22,12 @@
     1.4  #include "HalfLife2.h"
     1.5  #include "Logger.h"
     1.6  #include "ShareSys.h"
     1.7 +#include "MemoryUtils.h"
     1.8 +#include "LibrarySys.h"
     1.9 +
    1.10 +#if defined PLATFORM_LINUX
    1.11 +#include <dlfcn.h>
    1.12 +#endif
    1.13  
    1.14  GameConfigManager g_GameConfigs;
    1.15  IGameConfig *g_pGameConf = NULL;
    1.16 @@ -33,6 +39,9 @@
    1.17  #define PSTATE_GAMEDEFS_OFFSETS			3
    1.18  #define PSTATE_GAMEDEFS_OFFSETS_OFFSET	4
    1.19  #define PSTATE_GAMEDEFS_KEYS			5
    1.20 +#define PSTATE_GAMEDEFS_SUPPORTED		6
    1.21 +#define PSTATE_GAMEDEFS_SIGNATURES		7
    1.22 +#define PSTATE_GAMEDEFS_SIGNATURES_SIG	8
    1.23  
    1.24  #if defined PLATFORM_WINDOWS
    1.25  #define PLATFORM_NAME	"windows"
    1.26 @@ -40,12 +49,24 @@
    1.27  #define PLATFORM_NAME	"linux"
    1.28  #endif
    1.29  
    1.30 +struct TempSigInfo
    1.31 +{
    1.32 +	void Reset()
    1.33 +	{
    1.34 +		library[0] = '\0';
    1.35 +		sig[0] = '\0';
    1.36 +	}
    1.37 +	char sig[512];
    1.38 +	char library[64];
    1.39 +} s_TempSig;
    1.40 +
    1.41  CGameConfig::CGameConfig(const char *file)
    1.42  {
    1.43  	m_pFile = sm_strdup(file);
    1.44  	m_pOffsets = sm_trie_create();
    1.45  	m_pProps = sm_trie_create();
    1.46  	m_pKeys = sm_trie_create();
    1.47 +	m_pSigs = sm_trie_create();
    1.48  	m_pStrings = new BaseStringTable(512);
    1.49  	m_RefCount = 0;
    1.50  }
    1.51 @@ -55,6 +76,7 @@
    1.52  	sm_trie_destroy(m_pOffsets);
    1.53  	sm_trie_destroy(m_pProps);
    1.54  	sm_trie_destroy(m_pKeys);
    1.55 +	sm_trie_destroy(m_pSigs);
    1.56  	delete [] m_pFile;
    1.57  	delete m_pStrings;
    1.58  }
    1.59 @@ -66,6 +88,7 @@
    1.60  		m_IgnoreLevel++;
    1.61  		return SMCParse_Continue;
    1.62  	}
    1.63 +
    1.64  	switch (m_ParseState)
    1.65  	{
    1.66  	case PSTATE_NONE:
    1.67 @@ -81,6 +104,7 @@
    1.68  	case PSTATE_GAMES:
    1.69  		{
    1.70  			if ((strcmp(name, "*") == 0)
    1.71 +				|| (strcmp(name, "#default") == 0)
    1.72  				|| (strcmp(name, g_mod) == 0))
    1.73  			{
    1.74  				m_ParseState = PSTATE_GAMEDEFS;
    1.75 @@ -95,9 +119,24 @@
    1.76  			if (strcmp(name, "Offsets") == 0)
    1.77  			{
    1.78  				m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
    1.79 -			} else if (strcmp(name, "Keys") == 0) {
    1.80 +			}
    1.81 +			else if (strcmp(name, "Keys") == 0)
    1.82 +			{
    1.83  				m_ParseState = PSTATE_GAMEDEFS_KEYS;
    1.84 -			} else {
    1.85 +			}
    1.86 +			else if ((strcmp(name, "#supported") == 0)
    1.87 +					 && (strcmp(m_mod, "#default") == 0))
    1.88 +			{
    1.89 +				m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
    1.90 +				/* Ignore this section unless we get a game. */
    1.91 +				bShouldBeReadingDefault = false;
    1.92 +			}
    1.93 +			else if (strcmp(name, "Signatures") == 0)
    1.94 +			{
    1.95 +				m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
    1.96 +			}
    1.97 +			else
    1.98 +			{
    1.99  				m_IgnoreLevel++;
   1.100  			}
   1.101  			break;
   1.102 @@ -110,9 +149,18 @@
   1.103  			m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
   1.104  			break;
   1.105  		}
   1.106 +	case PSTATE_GAMEDEFS_SIGNATURES:
   1.107 +		{
   1.108 +			strncopy(m_offset, name, sizeof(m_offset));
   1.109 +			s_TempSig.Reset();
   1.110 +			m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
   1.111 +			break;
   1.112 +		}
   1.113  	/* No sub-sections allowed:
   1.114  	 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
   1.115  	 case PSTATE_GAMEDEFS_KEYS:
   1.116 +	 case PSTATE_GAMEDEFS_SUPPORTED:
   1.117 +	 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
   1.118  	 */
   1.119  	default:
   1.120  		{
   1.121 @@ -146,6 +194,19 @@
   1.122  	} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
   1.123  		int id = m_pStrings->AddString(value);
   1.124  		sm_trie_insert(m_pKeys, key, (void *)id);
   1.125 +	} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
   1.126 +		if (strcmp(key, "game") == 0
   1.127 +			&& strcmp(value, g_mod) == 0)
   1.128 +		{
   1.129 +			bShouldBeReadingDefault = true;
   1.130 +		}
   1.131 +	} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
   1.132 +		if (strcmp(key, PLATFORM_NAME) == 0)
   1.133 +		{
   1.134 +			strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
   1.135 +		} else if (strcmp(key, "library") == 0) {
   1.136 +			strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
   1.137 +		}
   1.138  	}
   1.139  
   1.140  	return SMCParse_Continue;
   1.141 @@ -191,7 +252,7 @@
   1.142  					sm_trie_insert(m_pProps, m_offset, pProp);
   1.143  				} else {
   1.144  					/* Check if it's a non-default game and no offsets exist */
   1.145 -					if ((strcmp(m_mod, "*") != 0)
   1.146 +					if (((strcmp(m_mod, "*") != 0) && strcmp(m_mod, "#default") != 0)
   1.147  						&& (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
   1.148  					{
   1.149  						g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", 
   1.150 @@ -205,6 +266,132 @@
   1.151  			m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
   1.152  			break;
   1.153  		}
   1.154 +	case PSTATE_GAMEDEFS_SUPPORTED:
   1.155 +		{
   1.156 +			if (!bShouldBeReadingDefault)
   1.157 +			{
   1.158 +				/* If we shouldn't read the rest of this section, set the ignore level. */
   1.159 +				m_IgnoreLevel = 1;
   1.160 +			}
   1.161 +			m_ParseState = PSTATE_GAMEDEFS;
   1.162 +			break;
   1.163 +		}
   1.164 +	case PSTATE_GAMEDEFS_SIGNATURES_SIG:
   1.165 +		{
   1.166 +			if (s_TempSig.library[0] == '\0')
   1.167 +			{
   1.168 +				/* assume server */
   1.169 +				strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
   1.170 +			}
   1.171 +			void *addrInBase = NULL;
   1.172 +			if (strcmp(s_TempSig.library, "server") == 0)
   1.173 +			{
   1.174 +				addrInBase = g_SMAPI->serverFactory(false);
   1.175 +			} else if (strcmp(s_TempSig.library, "engine") == 0) {
   1.176 +				addrInBase = g_SMAPI->engineFactory(false);
   1.177 +			}
   1.178 +			void *final_addr = NULL;
   1.179 +			if (addrInBase == NULL)
   1.180 +			{
   1.181 +				g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")", 
   1.182 +					s_TempSig.library, 
   1.183 +					m_pFile);
   1.184 +			} else {
   1.185 +#if defined PLATFORM_LINUX
   1.186 +				if (s_TempSig.sig_lin[0] == '@')
   1.187 +				{
   1.188 +					Dl_info info;
   1.189 +					/* GNU only: returns 0 on error, inconsistent! >:[ */
   1.190 +					if (dladdr(addrInBase, &info) == 0)
   1.191 +					{
   1.192 +						void *handle = dlopen(info.dli_fname, RTLD_NOW);
   1.193 +						if (handle)
   1.194 +						{
   1.195 +							final_addr = dlsym(handle, &s_TempSig.sig_lin[1]);
   1.196 +							dlclose(handle);
   1.197 +						} else {
   1.198 +							g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
   1.199 +								s_TempSig.library,
   1.200 +								m_pFile);
   1.201 +						}
   1.202 +					} else {
   1.203 +						g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
   1.204 +							s_TempSig.library,
   1.205 +							m_pFile);
   1.206 +					}
   1.207 +					if (!final_addr)
   1.208 +					{
   1.209 +						g_Logger.LogError("[SM] Unable to find named symbol (symbol \"%s\") (library \"%s\") (gameconf \"%s\")",
   1.210 +							&s_TempSig.sig_lin[1],
   1.211 +							s_TempSig.library,
   1.212 +							m_pFile);
   1.213 +					}
   1.214 +				}
   1.215 +				if (final_addr)
   1.216 +				{
   1.217 +					goto skip_find;
   1.218 +				}
   1.219 +#endif
   1.220 +				/* First, preprocess the signature */
   1.221 +				char real_sig[255];
   1.222 +				size_t real_bytes;
   1.223 +				size_t length;
   1.224 +
   1.225 +				real_bytes = 0;
   1.226 +				length = strlen(s_TempSig.sig);
   1.227 +
   1.228 +				for (size_t i=0; i<length; i++)
   1.229 +				{
   1.230 +					if (real_bytes >= sizeof(real_sig))
   1.231 +					{
   1.232 +						break;
   1.233 +					}
   1.234 +					real_sig[real_bytes++] = s_TempSig.sig[i];
   1.235 +					if (s_TempSig.sig[i] == '\\'
   1.236 +						&& s_TempSig.sig[i+1] == 'x')
   1.237 +					{
   1.238 +						if (i + 3 >= length)
   1.239 +						{
   1.240 +							continue;
   1.241 +						}
   1.242 +						/* Get the hex part */
   1.243 +						char s_byte[3];
   1.244 +						int r_byte;
   1.245 +						s_byte[0] = s_TempSig.sig[i+2];
   1.246 +						s_byte[1] = s_TempSig.sig[i+3];
   1.247 +						s_byte[2] = '\0';
   1.248 +						/* Read it as an integer */
   1.249 +						sscanf(s_byte, "%x", &r_byte);
   1.250 +						/* Save the value */
   1.251 +						real_sig[real_bytes-1] = r_byte;
   1.252 +						/* Adjust index */
   1.253 +						i += 3;
   1.254 +					}
   1.255 +				}
   1.256 +
   1.257 +				if (real_bytes < 1)
   1.258 +				{
   1.259 +					g_Logger.LogError("[SM] Invalid signature length of 1 (name \"%s\") (gameconf \"%s\")",
   1.260 +						m_offset,
   1.261 +						m_pFile);
   1.262 +				} else {
   1.263 +					final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
   1.264 +					if (!final_addr)
   1.265 +					{
   1.266 +						g_Logger.LogError("[SM] Unable to find signature (name \"%s\") (gameconf \"%s\")", 
   1.267 +							m_offset,
   1.268 +							m_pFile);
   1.269 +					}
   1.270 +				}
   1.271 +			}
   1.272 +
   1.273 +#if defined PLATFORM_LINUX
   1.274 +skip_find:
   1.275 +#endif
   1.276 +			sm_trie_insert(m_pSigs, m_offset, final_addr);
   1.277 +
   1.278 +			break;
   1.279 +		}
   1.280  	}
   1.281  
   1.282  	return SMCParse_Continue;
   1.283 @@ -215,10 +402,16 @@
   1.284  	SMCParseError err;
   1.285  
   1.286  	char path[PLATFORM_MAX_PATH];
   1.287 -	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
   1.288 +	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
   1.289 +	/* Backwards compatibility */
   1.290 +	if (!g_LibSys.PathExists(path))
   1.291 +	{
   1.292 +		g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
   1.293 +	}
   1.294  
   1.295  	/* Initialize parse states */
   1.296  	m_IgnoreLevel = 0;
   1.297 +	bShouldBeReadingDefault = true;
   1.298  	m_ParseState = PSTATE_NONE;
   1.299  	/* Reset cached data */
   1.300  	m_pStrings->Reset();
   1.301 @@ -276,6 +469,11 @@
   1.302  	return pProp;
   1.303  }
   1.304  
   1.305 +bool CGameConfig::GetMemSig(const char *key, void **addr)
   1.306 +{
   1.307 +	return sm_trie_retrieve(m_pSigs, key, addr);
   1.308 +}
   1.309 +
   1.310  void CGameConfig::IncRefCount()
   1.311  {
   1.312  	m_RefCount++;