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++;