diff -r c7b4237fff50 -r 03a67e41afbc core/GameConfigs.cpp --- a/core/GameConfigs.cpp Fri Mar 28 06:21:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,664 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include -#include -#include "GameConfigs.h" -#include "sm_stringutil.h" -#include "sourcemod.h" -#include "sourcemm_api.h" -#include "HalfLife2.h" -#include "Logger.h" -#include "ShareSys.h" -#include "MemoryUtils.h" -#include "LibrarySys.h" -#include "HandleSys.h" -#include "sm_crc32.h" - -#if defined PLATFORM_LINUX -#include -#endif - -GameConfigManager g_GameConfigs; -IGameConfig *g_pGameConf = NULL; -char g_Game[256]; -char g_GameDesc[256] = {'!', '\0'}; - -#define PSTATE_NONE 0 -#define PSTATE_GAMES 1 -#define PSTATE_GAMEDEFS 2 -#define PSTATE_GAMEDEFS_OFFSETS 3 -#define PSTATE_GAMEDEFS_OFFSETS_OFFSET 4 -#define PSTATE_GAMEDEFS_KEYS 5 -#define PSTATE_GAMEDEFS_SUPPORTED 6 -#define PSTATE_GAMEDEFS_SIGNATURES 7 -#define PSTATE_GAMEDEFS_SIGNATURES_SIG 8 -#define PSTATE_GAMEDEFS_CRC 9 -#define PSTATE_GAMEDEFS_CRC_BINARY 10 - -#if defined PLATFORM_WINDOWS -#define PLATFORM_NAME "windows" -#define PLATFORM_SERVER_BINARY "server.dll" -#elif defined PLATFORM_LINUX -#define PLATFORM_NAME "linux" -#define PLATFORM_SERVER_BINARY "server_i486.so" -#endif - -struct TempSigInfo -{ - void Reset() - { - library[0] = '\0'; - sig[0] = '\0'; - } - char sig[512]; - char library[64]; -} s_TempSig; -unsigned int s_ServerBinCRC; -bool s_ServerBinCRC_Ok = false; - -CGameConfig::CGameConfig(const char *file) -{ - m_pFile = sm_strdup(file); - m_pOffsets = sm_trie_create(); - m_pProps = sm_trie_create(); - m_pKeys = sm_trie_create(); - m_pSigs = sm_trie_create(); - m_pStrings = new BaseStringTable(512); - m_RefCount = 0; -} - -CGameConfig::~CGameConfig() -{ - sm_trie_destroy(m_pOffsets); - sm_trie_destroy(m_pProps); - sm_trie_destroy(m_pKeys); - sm_trie_destroy(m_pSigs); - delete [] m_pFile; - delete m_pStrings; -} - -SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name) -{ - if (m_IgnoreLevel) - { - m_IgnoreLevel++; - return SMCResult_Continue; - } - - switch (m_ParseState) - { - case PSTATE_NONE: - { - if (strcmp(name, "Games") == 0) - { - m_ParseState = PSTATE_GAMES; - } else { - m_IgnoreLevel++; - } - break; - } - case PSTATE_GAMES: - { - if ((strcmp(name, "*") == 0) - || (strcmp(name, "#default") == 0) - || (strcasecmp(name, g_Game) == 0) - || (strcasecmp(name, g_GameDesc) == 0)) - { - bShouldBeReadingDefault = true; - m_ParseState = PSTATE_GAMEDEFS; - strncopy(m_Game, name, sizeof(m_Game)); - } else { - m_IgnoreLevel++; - } - break; - } - case PSTATE_GAMEDEFS: - { - if (strcmp(name, "Offsets") == 0) - { - m_ParseState = PSTATE_GAMEDEFS_OFFSETS; - } - else if (strcmp(name, "Keys") == 0) - { - m_ParseState = PSTATE_GAMEDEFS_KEYS; - } - else if ((strcmp(name, "#supported") == 0) - && (strcmp(m_Game, "#default") == 0)) - { - m_ParseState = PSTATE_GAMEDEFS_SUPPORTED; - /* Ignore this section unless we get a game. */ - bShouldBeReadingDefault = false; - } - else if (strcmp(name, "Signatures") == 0) - { - m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; - } - else if (strcmp(name, "CRC") == 0) - { - m_ParseState = PSTATE_GAMEDEFS_CRC; - bShouldBeReadingDefault = false; - } - else - { - m_IgnoreLevel++; - } - break; - } - case PSTATE_GAMEDEFS_OFFSETS: - { - m_Prop[0] = '\0'; - m_Class[0] = '\0'; - strncopy(m_offset, name, sizeof(m_offset)); - m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET; - break; - } - case PSTATE_GAMEDEFS_SIGNATURES: - { - strncopy(m_offset, name, sizeof(m_offset)); - s_TempSig.Reset(); - m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG; - break; - } - case PSTATE_GAMEDEFS_CRC: - { - char error[255]; - error[0] = '\0'; - if (strcmp(name, "server") != 0) - { - UTIL_Format(error, sizeof(error), "Unrecognized library \"%s\"", name); - } - else if (!s_ServerBinCRC_Ok) - { - FILE *fp; - char path[PLATFORM_MAX_PATH]; - - g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY); - if ((fp = fopen(path, "rb")) == NULL) - { - UTIL_Format(error, sizeof(error), "Could not open binary: %s", path); - } else { - size_t size; - void *buffer; - - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - - buffer = malloc(size); - fread(buffer, size, 1, fp); - s_ServerBinCRC = UTIL_CRC32(buffer, size); - free(buffer); - s_ServerBinCRC_Ok = true; - } - } - if (error[0] != '\0') - { - m_IgnoreLevel = 1; - g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_pFile); - g_Logger.LogError("[SM] %s", error); - } else { - m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY; - } - break; - } - /* No sub-sections allowed: - case PSTATE_GAMEDEFS_OFFSETS_OFFSET: - case PSTATE_GAMEDEFS_KEYS: - case PSTATE_GAMEDEFS_SUPPORTED: - case PSTATE_GAMEDEFS_SIGNATURES_SIG: - case PSTATE_GAMEDEFS_CRC_BINARY: - */ - default: - { - /* If we don't know what we got, start ignoring */ - m_IgnoreLevel++; - break; - } - } - - return SMCResult_Continue; -} - -SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value) -{ - if (m_IgnoreLevel) - { - return SMCResult_Continue; - } - - if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET) - { - if (strcmp(key, "class") == 0) - { - strncopy(m_Class, value, sizeof(m_Class)); - } else if (strcmp(key, "prop") == 0) { - strncopy(m_Prop, value, sizeof(m_Prop)); - } else if (strcmp(key, PLATFORM_NAME) == 0) { - int val = atoi(value); - sm_trie_replace(m_pOffsets, m_offset, (void *)val); - } - } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) { - int id = m_pStrings->AddString(value); - sm_trie_replace(m_pKeys, key, (void *)id); - } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) { - if (strcmp(key, "game") == 0 - && (strcasecmp(value, g_Game) == 0 || strcasecmp(value, g_GameDesc) == 0)) - { - bShouldBeReadingDefault = true; - } - } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) { - if (strcmp(key, PLATFORM_NAME) == 0) - { - strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig)); - } else if (strcmp(key, "library") == 0) { - strncopy(s_TempSig.library, value, sizeof(s_TempSig.library)); - } - } else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) { - if (strcmp(key, PLATFORM_NAME) == 0 - && s_ServerBinCRC_Ok - && !bShouldBeReadingDefault) - { - unsigned int crc = 0; - sscanf(value, "%08X", &crc); - if (s_ServerBinCRC == crc) - { - bShouldBeReadingDefault = true; - } - } - } - - return SMCResult_Continue; -} - -SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states) -{ - if (m_IgnoreLevel) - { - m_IgnoreLevel--; - return SMCResult_Continue; - } - - switch (m_ParseState) - { - case PSTATE_GAMES: - { - m_ParseState = PSTATE_NONE; - break; - } - case PSTATE_GAMEDEFS: - { - m_ParseState = PSTATE_GAMES; - break; - } - case PSTATE_GAMEDEFS_KEYS: - case PSTATE_GAMEDEFS_OFFSETS: - { - m_ParseState = PSTATE_GAMEDEFS; - break; - } - case PSTATE_GAMEDEFS_OFFSETS_OFFSET: - { - /* Parse the offset... */ - if (m_Class[0] != '\0' - && m_Prop[0] != '\0') - { - SendProp *pProp = g_HL2.FindInSendTable(m_Class, m_Prop); - if (pProp) - { - int val = pProp->GetOffset(); - sm_trie_replace(m_pOffsets, m_offset, (void *)val); - sm_trie_replace(m_pProps, m_offset, pProp); - } else { - /* Check if it's a non-default game and no offsets exist */ - if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0) - && (!sm_trie_retrieve(m_pOffsets, m_offset, NULL))) - { - g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", - m_Class, - m_Prop, - m_pFile, - m_Game); - } - } - } - m_ParseState = PSTATE_GAMEDEFS_OFFSETS; - break; - } - case PSTATE_GAMEDEFS_CRC: - case PSTATE_GAMEDEFS_SUPPORTED: - { - if (!bShouldBeReadingDefault) - { - /* If we shouldn't read the rest of this section, set the ignore level. */ - m_IgnoreLevel = 1; - m_ParseState = PSTATE_GAMES; - } else { - m_ParseState = PSTATE_GAMEDEFS; - } - break; - } - case PSTATE_GAMEDEFS_CRC_BINARY: - { - m_ParseState = PSTATE_GAMEDEFS_CRC; - break; - } - case PSTATE_GAMEDEFS_SIGNATURES: - { - m_ParseState = PSTATE_GAMEDEFS; - break; - } - case PSTATE_GAMEDEFS_SIGNATURES_SIG: - { - if (s_TempSig.library[0] == '\0') - { - /* assume server */ - strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library)); - } - void *addrInBase = NULL; - if (strcmp(s_TempSig.library, "server") == 0) - { - addrInBase = (void *)g_SMAPI->GetServerFactory(false); - } else if (strcmp(s_TempSig.library, "engine") == 0) { - addrInBase = (void *)g_SMAPI->GetEngineFactory(false); - } - void *final_addr = NULL; - if (addrInBase == NULL) - { - g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")", - s_TempSig.library, - m_pFile); - } else { -#if defined PLATFORM_LINUX - if (s_TempSig.sig[0] == '@') - { - Dl_info info; - /* GNU only: returns 0 on error, inconsistent! >:[ */ - if (dladdr(addrInBase, &info) != 0) - { - void *handle = dlopen(info.dli_fname, RTLD_NOW); - if (handle) - { - final_addr = dlsym(handle, &s_TempSig.sig[1]); - dlclose(handle); - } else { - g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")", - s_TempSig.library, - m_pFile); - } - } else { - g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")", - s_TempSig.library, - m_pFile); - } - } - if (final_addr) - { - goto skip_find; - } -#endif - /* First, preprocess the signature */ - char real_sig[255]; - size_t real_bytes; - size_t length; - - real_bytes = 0; - length = strlen(s_TempSig.sig); - - for (size_t i=0; i= sizeof(real_sig)) - { - break; - } - real_sig[real_bytes++] = s_TempSig.sig[i]; - if (s_TempSig.sig[i] == '\\' - && s_TempSig.sig[i+1] == 'x') - { - if (i + 3 >= length) - { - continue; - } - /* Get the hex part */ - char s_byte[3]; - int r_byte; - s_byte[0] = s_TempSig.sig[i+2]; - s_byte[1] = s_TempSig.sig[i+3]; - s_byte[2] = '\0'; - /* Read it as an integer */ - sscanf(s_byte, "%x", &r_byte); - /* Save the value */ - real_sig[real_bytes-1] = r_byte; - /* Adjust index */ - i += 3; - } - } - - if (real_bytes >= 1) - { - final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes); - } - } - -#if defined PLATFORM_LINUX -skip_find: -#endif - sm_trie_replace(m_pSigs, m_offset, final_addr); - m_ParseState = PSTATE_GAMEDEFS_SIGNATURES; - - break; - } - } - - return SMCResult_Continue; -} - -bool CGameConfig::Reparse(char *error, size_t maxlength) -{ - SMCError err; - - char path[PLATFORM_MAX_PATH]; - g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile); - /* Backwards compatibility */ - if (!g_LibSys.PathExists(path)) - { - g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile); - } - - /* Initialize parse states */ - m_IgnoreLevel = 0; - bShouldBeReadingDefault = true; - m_ParseState = PSTATE_NONE; - /* Reset cached data */ - m_pStrings->Reset(); - sm_trie_clear(m_pOffsets); - sm_trie_clear(m_pProps); - sm_trie_clear(m_pKeys); - - if ((err=textparsers->ParseFile_SMC(path, this, NULL)) - != SMCError_Okay) - { - if (error && (err != SMCError_Custom)) - { - const char *str = textparsers->GetSMCErrorString(err); - snprintf(error, maxlength, "%s", str); - } - return false; - } - - return true; -} - -bool CGameConfig::GetOffset(const char *key, int *value) -{ - void *obj; - - if (!sm_trie_retrieve(m_pOffsets, key, &obj)) - { - return false; - } - - *value = (int)obj; - - return true; -} - -const char *CGameConfig::GetKeyValue(const char *key) -{ - void *obj; - if (!sm_trie_retrieve(m_pKeys, key, &obj)) - { - return NULL; - } - return m_pStrings->GetString((int)obj); -} - -SendProp *CGameConfig::GetSendProp(const char *key) -{ - SendProp *pProp; - - if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp)) - { - return NULL; - } - - return pProp; -} - -bool CGameConfig::GetMemSig(const char *key, void **addr) -{ - return sm_trie_retrieve(m_pSigs, key, addr); -} - -void CGameConfig::IncRefCount() -{ - m_RefCount++; -} - -unsigned int CGameConfig::DecRefCount() -{ - m_RefCount--; - return m_RefCount; -} - -GameConfigManager::GameConfigManager() -{ - m_pLookup = sm_trie_create(); -} - -GameConfigManager::~GameConfigManager() -{ - sm_trie_destroy(m_pLookup); -} - -void GameConfigManager::OnSourceModStartup(bool late) -{ - LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0); - - strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game)); - strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1); -} - -void GameConfigManager::OnSourceModAllInitialized() -{ - /* NOW initialize the game file */ - CGameConfig *pGameConf = (CGameConfig *)g_pGameConf; - - char error[255]; - if (!pGameConf->Reparse(error, sizeof(error))) - { - /* :TODO: log */ - } - - g_ShareSys.AddInterface(NULL, this); -} - -void GameConfigManager::OnSourceModAllShutdown() -{ - CloseGameConfigFile(g_pGameConf); -} - -bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength) -{ - CGameConfig *pConfig; - - if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig)) - { - pConfig->IncRefCount(); - *_pConfig = pConfig; - return true; - } - - pConfig = new CGameConfig(file); - - /* :HACKHACK: Don't parse the main config file */ - bool retval = true; - if (_pConfig != &g_pGameConf) - { - retval = pConfig->Reparse(error, maxlength); - } - - m_cfgs.push_back(pConfig); - sm_trie_insert(m_pLookup, file, pConfig); - - pConfig->IncRefCount(); - - *_pConfig = pConfig; - - return retval; -} - -void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg) -{ - CGameConfig *pConfig = (CGameConfig *)cfg; - - if (pConfig->DecRefCount() == 0) - { - sm_trie_delete(m_pLookup, pConfig->m_pFile); - delete pConfig; - } -} - -extern HandleType_t g_GameConfigsType; - -IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err) -{ - HandleSecurity sec(ident, g_pCoreIdent); - IGameConfig *conf = NULL; - HandleError _err = g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&conf); - - if (err) - { - *err = _err; - } - - return conf; -}