core/GameConfigs.cpp
author Scott Ehlert <ds@alliedmods.net>
Sun Mar 30 07:00:22 2008 +0000 (2008-03-30)
changeset 1952 b7aa2b626807
child 2142 d9d876e97a66
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 <string.h>
    33 #include <stdlib.h>
    34 #include "GameConfigs.h"
    35 #include "sm_stringutil.h"
    36 #include "sourcemod.h"
    37 #include "sourcemm_api.h"
    38 #include "HalfLife2.h"
    39 #include "Logger.h"
    40 #include "ShareSys.h"
    41 #include "MemoryUtils.h"
    42 #include "LibrarySys.h"
    43 #include "HandleSys.h"
    44 #include "sm_crc32.h"
    45 
    46 #if defined PLATFORM_LINUX
    47 #include <dlfcn.h>
    48 #endif
    49 
    50 GameConfigManager g_GameConfigs;
    51 IGameConfig *g_pGameConf = NULL;
    52 char g_Game[256];
    53 char g_GameDesc[256] = {'!', '\0'};
    54 char g_GameName[256] = {'$', '\0'};
    55 
    56 #define PSTATE_NONE						0
    57 #define PSTATE_GAMES					1
    58 #define PSTATE_GAMEDEFS					2
    59 #define PSTATE_GAMEDEFS_OFFSETS			3
    60 #define PSTATE_GAMEDEFS_OFFSETS_OFFSET	4
    61 #define PSTATE_GAMEDEFS_KEYS			5
    62 #define PSTATE_GAMEDEFS_SUPPORTED		6
    63 #define PSTATE_GAMEDEFS_SIGNATURES		7
    64 #define PSTATE_GAMEDEFS_SIGNATURES_SIG	8
    65 #define PSTATE_GAMEDEFS_CRC				9
    66 #define PSTATE_GAMEDEFS_CRC_BINARY		10
    67 
    68 #if defined PLATFORM_WINDOWS
    69 #define PLATFORM_NAME				"windows"
    70 #define PLATFORM_SERVER_BINARY		"server.dll"
    71 #elif defined PLATFORM_LINUX
    72 #define PLATFORM_NAME				"linux"
    73 #define PLATFORM_SERVER_BINARY		"server_i486.so"
    74 #endif
    75 
    76 struct TempSigInfo
    77 {
    78 	void Reset()
    79 	{
    80 		library[0] = '\0';
    81 		sig[0] = '\0';
    82 	}
    83 	char sig[512];
    84 	char library[64];
    85 } s_TempSig;
    86 unsigned int s_ServerBinCRC;
    87 bool s_ServerBinCRC_Ok = false;
    88 
    89 CGameConfig::CGameConfig(const char *file)
    90 {
    91 	m_pFile = sm_strdup(file);
    92 	m_pOffsets = sm_trie_create();
    93 	m_pProps = sm_trie_create();
    94 	m_pKeys = sm_trie_create();
    95 	m_pSigs = sm_trie_create();
    96 	m_pStrings = new BaseStringTable(512);
    97 	m_RefCount = 0;
    98 }
    99 
   100 CGameConfig::~CGameConfig()
   101 {
   102 	sm_trie_destroy(m_pOffsets);
   103 	sm_trie_destroy(m_pProps);
   104 	sm_trie_destroy(m_pKeys);
   105 	sm_trie_destroy(m_pSigs);
   106 	delete [] m_pFile;
   107 	delete m_pStrings;
   108 }
   109 
   110 SMCResult CGameConfig::ReadSMC_NewSection(const SMCStates *states, const char *name)
   111 {
   112 	if (m_IgnoreLevel)
   113 	{
   114 		m_IgnoreLevel++;
   115 		return SMCResult_Continue;
   116 	}
   117 
   118 	switch (m_ParseState)
   119 	{
   120 	case PSTATE_NONE:
   121 		{
   122 			if (strcmp(name, "Games") == 0)
   123 			{
   124 				m_ParseState = PSTATE_GAMES;
   125 			} else {
   126 				m_IgnoreLevel++;
   127 			}
   128 			break;
   129 		}
   130 	case PSTATE_GAMES:
   131 		{
   132 			if ((strcmp(name, "*") == 0)
   133 				|| (strcmp(name, "#default") == 0)
   134 				|| (strcasecmp(name, g_Game) == 0)
   135 				|| (strcasecmp(name, g_GameDesc) == 0)
   136 				|| (strcasecmp(name, g_GameName) == 0))
   137 			{
   138 				bShouldBeReadingDefault = true;
   139 				m_ParseState = PSTATE_GAMEDEFS;
   140 				strncopy(m_Game, name, sizeof(m_Game));
   141 			} else {
   142 				m_IgnoreLevel++;
   143 			}
   144 			break;
   145 		}
   146 	case PSTATE_GAMEDEFS:
   147 		{
   148 			if (strcmp(name, "Offsets") == 0)
   149 			{
   150 				m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
   151 			}
   152 			else if (strcmp(name, "Keys") == 0)
   153 			{
   154 				m_ParseState = PSTATE_GAMEDEFS_KEYS;
   155 			}
   156 			else if ((strcmp(name, "#supported") == 0)
   157 					 && (strcmp(m_Game, "#default") == 0))
   158 			{
   159 				m_ParseState = PSTATE_GAMEDEFS_SUPPORTED;
   160 				/* Ignore this section unless we get a game. */
   161 				bShouldBeReadingDefault = false;
   162 			}
   163 			else if (strcmp(name, "Signatures") == 0)
   164 			{
   165 				m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
   166 			}
   167 			else if (strcmp(name, "CRC") == 0)
   168 			{
   169 				m_ParseState = PSTATE_GAMEDEFS_CRC;
   170 				bShouldBeReadingDefault = false;
   171 			}
   172 			else
   173 			{
   174 				m_IgnoreLevel++;
   175 			}
   176 			break;
   177 		}
   178 	case PSTATE_GAMEDEFS_OFFSETS:
   179 		{
   180 			m_Prop[0] = '\0';
   181 			m_Class[0] = '\0';
   182 			strncopy(m_offset, name, sizeof(m_offset));
   183 			m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
   184 			break;
   185 		}
   186 	case PSTATE_GAMEDEFS_SIGNATURES:
   187 		{
   188 			strncopy(m_offset, name, sizeof(m_offset));
   189 			s_TempSig.Reset();
   190 			m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
   191 			break;
   192 		}
   193 	case PSTATE_GAMEDEFS_CRC:
   194 		{
   195 			char error[255];
   196 			error[0] = '\0';
   197 			if (strcmp(name, "server") != 0)
   198 			{
   199 				UTIL_Format(error, sizeof(error), "Unrecognized library \"%s\"", name);
   200 			} 
   201 			else if (!s_ServerBinCRC_Ok)
   202 			{
   203 				FILE *fp;
   204 				char path[PLATFORM_MAX_PATH];
   205 
   206 				g_SourceMod.BuildPath(Path_Game, path, sizeof(path), "bin/" PLATFORM_SERVER_BINARY);
   207 				if ((fp = fopen(path, "rb")) == NULL)
   208 				{
   209 					UTIL_Format(error, sizeof(error), "Could not open binary: %s", path);
   210 				} else {
   211 					size_t size;
   212 					void *buffer;
   213 
   214 					fseek(fp, 0, SEEK_END);
   215 					size = ftell(fp);
   216 					fseek(fp, 0, SEEK_SET);
   217 
   218 					buffer = malloc(size);
   219 					fread(buffer, size, 1, fp);
   220 					s_ServerBinCRC = UTIL_CRC32(buffer, size);
   221 					free(buffer);
   222 					s_ServerBinCRC_Ok = true;
   223 				}
   224 			}
   225 			if (error[0] != '\0')
   226 			{
   227 				m_IgnoreLevel = 1;
   228 				g_Logger.LogError("[SM] Error while parsing CRC section for \"%s\" (%s):", m_Game, m_pFile);
   229 				g_Logger.LogError("[SM] %s", error);
   230 			} else {
   231 				m_ParseState = PSTATE_GAMEDEFS_CRC_BINARY;
   232 			}
   233 			break;
   234 		}
   235 	/* No sub-sections allowed:
   236 	 case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
   237 	 case PSTATE_GAMEDEFS_KEYS:
   238 	 case PSTATE_GAMEDEFS_SUPPORTED:
   239 	 case PSTATE_GAMEDEFS_SIGNATURES_SIG:
   240 	 case PSTATE_GAMEDEFS_CRC_BINARY:
   241 	 */
   242 	default:
   243 		{
   244 			/* If we don't know what we got, start ignoring */
   245 			m_IgnoreLevel++;
   246 			break;
   247 		}
   248 	}
   249 
   250 	return SMCResult_Continue;
   251 }
   252 
   253 SMCResult CGameConfig::ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
   254 {
   255 	if (m_IgnoreLevel)
   256 	{
   257 		return SMCResult_Continue;
   258 	}
   259 
   260 	if (m_ParseState == PSTATE_GAMEDEFS_OFFSETS_OFFSET)
   261 	{
   262 		if (strcmp(key, "class") == 0)
   263 		{
   264 			strncopy(m_Class, value, sizeof(m_Class));
   265 		} else if (strcmp(key, "prop") == 0) {
   266 			strncopy(m_Prop, value, sizeof(m_Prop));
   267 		} else if (strcmp(key, PLATFORM_NAME) == 0) {
   268 			int val = atoi(value);
   269 			sm_trie_replace(m_pOffsets, m_offset, (void *)val);
   270 		}
   271 	} else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
   272 		int id = m_pStrings->AddString(value);
   273 		sm_trie_replace(m_pKeys, key, (void *)id);
   274 	} else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
   275 		if (strcmp(key, "game") == 0
   276 			&& (strcasecmp(value, g_Game) == 0 
   277 				|| strcasecmp(value, g_GameDesc) == 0
   278 				|| strcasecmp(value, g_GameName) == 0)
   279 				)
   280 		{
   281 			bShouldBeReadingDefault = true;
   282 		}
   283 	} else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
   284 		if (strcmp(key, PLATFORM_NAME) == 0)
   285 		{
   286 			strncopy(s_TempSig.sig, value, sizeof(s_TempSig.sig));
   287 		} else if (strcmp(key, "library") == 0) {
   288 			strncopy(s_TempSig.library, value, sizeof(s_TempSig.library));
   289 		}
   290 	} else if (m_ParseState == PSTATE_GAMEDEFS_CRC_BINARY) {
   291 		if (strcmp(key, PLATFORM_NAME) == 0 
   292 			&& s_ServerBinCRC_Ok
   293 			&& !bShouldBeReadingDefault)
   294 		{
   295 			unsigned int crc = 0;
   296 			sscanf(value, "%08X", &crc);
   297 			if (s_ServerBinCRC == crc)
   298 			{
   299 				bShouldBeReadingDefault = true;
   300 			}
   301 		}
   302 	}
   303 
   304 	return SMCResult_Continue;
   305 }
   306 
   307 SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
   308 {
   309 	if (m_IgnoreLevel)
   310 	{
   311 		m_IgnoreLevel--;
   312 		return SMCResult_Continue;
   313 	}
   314 
   315 	switch (m_ParseState)
   316 	{
   317 	case PSTATE_GAMES:
   318 		{
   319 			m_ParseState = PSTATE_NONE;
   320 			break;
   321 		}
   322 	case PSTATE_GAMEDEFS:
   323 		{
   324 			m_ParseState = PSTATE_GAMES;
   325 			break;
   326 		}
   327 	case PSTATE_GAMEDEFS_KEYS:
   328 	case PSTATE_GAMEDEFS_OFFSETS:
   329 		{
   330 			m_ParseState = PSTATE_GAMEDEFS;
   331 			break;
   332 		}
   333 	case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
   334 		{
   335 			/* Parse the offset... */
   336 			if (m_Class[0] != '\0'
   337 				&& m_Prop[0] != '\0')
   338 			{
   339 				SendProp *pProp = g_HL2.FindInSendTable(m_Class, m_Prop);
   340 				if (pProp)
   341 				{
   342 					int val = pProp->GetOffset();
   343 					sm_trie_replace(m_pOffsets, m_offset, (void *)val);
   344 					sm_trie_replace(m_pProps, m_offset, pProp);
   345 				} else {
   346 					/* Check if it's a non-default game and no offsets exist */
   347 					if (((strcmp(m_Game, "*") != 0) && strcmp(m_Game, "#default") != 0)
   348 						&& (!sm_trie_retrieve(m_pOffsets, m_offset, NULL)))
   349 					{
   350 						g_Logger.LogError("[SM] Unable to find property %s.%s (file \"%s\") (mod \"%s\")", 
   351 							m_Class,
   352 							m_Prop,
   353 							m_pFile,
   354 							m_Game);
   355 					}
   356 				}
   357 			}
   358 			m_ParseState = PSTATE_GAMEDEFS_OFFSETS;
   359 			break;
   360 		}
   361 	case PSTATE_GAMEDEFS_CRC:
   362 	case PSTATE_GAMEDEFS_SUPPORTED:
   363 		{
   364 			if (!bShouldBeReadingDefault)
   365 			{
   366 				/* If we shouldn't read the rest of this section, set the ignore level. */
   367 				m_IgnoreLevel = 1;
   368 				m_ParseState = PSTATE_GAMES;
   369 			} else {
   370 				m_ParseState = PSTATE_GAMEDEFS;
   371 			}
   372 			break;
   373 		}
   374 	case PSTATE_GAMEDEFS_CRC_BINARY:
   375 		{
   376 			m_ParseState = PSTATE_GAMEDEFS_CRC;
   377 			break;
   378 		}
   379 	case PSTATE_GAMEDEFS_SIGNATURES:
   380 		{
   381 			m_ParseState = PSTATE_GAMEDEFS;
   382 			break;
   383 		}
   384 	case PSTATE_GAMEDEFS_SIGNATURES_SIG:
   385 		{
   386 			if (s_TempSig.library[0] == '\0')
   387 			{
   388 				/* assume server */
   389 				strncopy(s_TempSig.library, "server", sizeof(s_TempSig.library));
   390 			}
   391 			void *addrInBase = NULL;
   392 			if (strcmp(s_TempSig.library, "server") == 0)
   393 			{
   394 				addrInBase = (void *)g_SMAPI->GetServerFactory(false);
   395 			} else if (strcmp(s_TempSig.library, "engine") == 0) {
   396 				addrInBase = (void *)g_SMAPI->GetEngineFactory(false);
   397 			}
   398 			void *final_addr = NULL;
   399 			if (addrInBase == NULL)
   400 			{
   401 				g_Logger.LogError("[SM] Unrecognized library \"%s\" (gameconf \"%s\")", 
   402 					s_TempSig.library, 
   403 					m_pFile);
   404 			} else {
   405 #if defined PLATFORM_LINUX
   406 				if (s_TempSig.sig[0] == '@')
   407 				{
   408 					Dl_info info;
   409 					/* GNU only: returns 0 on error, inconsistent! >:[ */
   410 					if (dladdr(addrInBase, &info) != 0)
   411 					{
   412 						void *handle = dlopen(info.dli_fname, RTLD_NOW);
   413 						if (handle)
   414 						{
   415 							final_addr = dlsym(handle, &s_TempSig.sig[1]);
   416 							dlclose(handle);
   417 						} else {
   418 							g_Logger.LogError("[SM] Unable to load library \"%s\" (gameconf \"%s\")",
   419 								s_TempSig.library,
   420 								m_pFile);
   421 						}
   422 					} else {
   423 						g_Logger.LogError("[SM] Unable to find library \"%s\" in memory (gameconf \"%s\")",
   424 							s_TempSig.library,
   425 							m_pFile);
   426 					}
   427 				}
   428 				if (final_addr)
   429 				{
   430 					goto skip_find;
   431 				}
   432 #endif
   433 				/* First, preprocess the signature */
   434 				char real_sig[511];
   435 				size_t real_bytes;
   436 				size_t length;
   437 
   438 				real_bytes = 0;
   439 				length = strlen(s_TempSig.sig);
   440 
   441 				for (size_t i=0; i<length; i++)
   442 				{
   443 					if (real_bytes >= sizeof(real_sig))
   444 					{
   445 						break;
   446 					}
   447 					real_sig[real_bytes++] = s_TempSig.sig[i];
   448 					if (s_TempSig.sig[i] == '\\'
   449 						&& s_TempSig.sig[i+1] == 'x')
   450 					{
   451 						if (i + 3 >= length)
   452 						{
   453 							continue;
   454 						}
   455 						/* Get the hex part */
   456 						char s_byte[3];
   457 						int r_byte;
   458 						s_byte[0] = s_TempSig.sig[i+2];
   459 						s_byte[1] = s_TempSig.sig[i+3];
   460 						s_byte[2] = '\0';
   461 						/* Read it as an integer */
   462 						sscanf(s_byte, "%x", &r_byte);
   463 						/* Save the value */
   464 						real_sig[real_bytes-1] = r_byte;
   465 						/* Adjust index */
   466 						i += 3;
   467 					}
   468 				}
   469 
   470 				if (real_bytes >= 1)
   471 				{
   472 					final_addr = g_MemUtils.FindPattern(addrInBase, real_sig, real_bytes);
   473 				}
   474 			}
   475 
   476 #if defined PLATFORM_LINUX
   477 skip_find:
   478 #endif
   479 			sm_trie_replace(m_pSigs, m_offset, final_addr);
   480 			m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
   481 
   482 			break;
   483 		}
   484 	}
   485 
   486 	return SMCResult_Continue;
   487 }
   488 
   489 bool CGameConfig::Reparse(char *error, size_t maxlength)
   490 {
   491 	SMCError err;
   492 	SMCStates state = {0, 0};
   493 
   494 	char path[PLATFORM_MAX_PATH];
   495 	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "gamedata/%s.txt", m_pFile);
   496 	/* Backwards compatibility */
   497 	if (!g_LibSys.PathExists(path))
   498 	{
   499 		g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "configs/gamedata/%s.txt", m_pFile);
   500 	}
   501 
   502 	/* Initialize parse states */
   503 	m_IgnoreLevel = 0;
   504 	bShouldBeReadingDefault = true;
   505 	m_ParseState = PSTATE_NONE;
   506 	/* Reset cached data */
   507 	m_pStrings->Reset();
   508 	sm_trie_clear(m_pOffsets);
   509 	sm_trie_clear(m_pProps);
   510 	sm_trie_clear(m_pKeys);
   511 
   512 	if ((err=textparsers->ParseSMCFile(path, this, &state, error, maxlength))
   513 		!= SMCError_Okay)
   514 	{
   515 		const char *msg;
   516 
   517 		msg = textparsers->GetSMCErrorString(err);
   518 
   519 		g_Logger.LogError("[SM] Error parsing gameconfig file \"%s\":", path);
   520 		g_Logger.LogError("[SM] Error %d on line %d, col %d: %s", 
   521 			err,
   522 			state.line,
   523 			state.col,
   524 			msg ? msg : "Unknown error");
   525 		return false;
   526 	}
   527 
   528 	return true;
   529 }
   530 
   531 bool CGameConfig::GetOffset(const char *key, int *value)
   532 {
   533 	void *obj;
   534 
   535 	if (!sm_trie_retrieve(m_pOffsets, key, &obj))
   536 	{
   537 		return false;
   538 	}
   539 
   540 	*value = (int)obj;
   541 	
   542 	return true;
   543 }
   544 
   545 const char *CGameConfig::GetKeyValue(const char *key)
   546 {
   547 	void *obj;
   548 	if (!sm_trie_retrieve(m_pKeys, key, &obj))
   549 	{
   550 		return NULL;
   551 	}
   552 	return m_pStrings->GetString((int)obj);
   553 }
   554 
   555 SendProp *CGameConfig::GetSendProp(const char *key)
   556 {
   557 	SendProp *pProp;
   558 
   559 	if (!sm_trie_retrieve(m_pProps, key, (void **)&pProp))
   560 	{
   561 		return NULL;
   562 	}
   563 
   564 	return pProp;
   565 }
   566 
   567 bool CGameConfig::GetMemSig(const char *key, void **addr)
   568 {
   569 	return sm_trie_retrieve(m_pSigs, key, addr);
   570 }
   571 
   572 void CGameConfig::IncRefCount()
   573 {
   574 	m_RefCount++;
   575 }
   576 
   577 unsigned int CGameConfig::DecRefCount()
   578 {
   579 	m_RefCount--;
   580 	return m_RefCount;
   581 }
   582 
   583 GameConfigManager::GameConfigManager()
   584 {
   585 	m_pLookup = sm_trie_create();
   586 }
   587 
   588 GameConfigManager::~GameConfigManager()
   589 {
   590 	sm_trie_destroy(m_pLookup);
   591 }
   592 
   593 void GameConfigManager::OnSourceModStartup(bool late)
   594 {
   595 	LoadGameConfigFile("core.games", &g_pGameConf, NULL, 0);
   596 
   597 	strncopy(g_Game, g_SourceMod.GetGameFolderName(), sizeof(g_Game));
   598 	strncopy(g_GameDesc + 1, SERVER_CALL(GetGameDescription)(), sizeof(g_GameDesc) - 1);
   599 
   600 	KeyValues *pGameInfo = new KeyValues("GameInfo");
   601 	if (g_HL2.KVLoadFromFile(pGameInfo, basefilesystem, "gameinfo.txt"))
   602 	{
   603 		const char *str;
   604 		if ((str = pGameInfo->GetString("game", NULL)) != NULL)
   605 		{
   606 			strncopy(g_GameName + 1, str, sizeof(g_GameName) - 1);
   607 		}
   608 	}
   609 	pGameInfo->deleteThis();
   610 }
   611 
   612 void GameConfigManager::OnSourceModAllInitialized()
   613 {
   614 	/* NOW initialize the game file */
   615 	CGameConfig *pGameConf = (CGameConfig *)g_pGameConf;
   616 	
   617 	char error[255];
   618 	if (!pGameConf->Reparse(error, sizeof(error)))
   619 	{
   620 		/* :TODO: log */
   621 	}
   622 
   623 	g_ShareSys.AddInterface(NULL, this);
   624 }
   625 
   626 void GameConfigManager::OnSourceModAllShutdown()
   627 {
   628 	CloseGameConfigFile(g_pGameConf);
   629 }
   630 
   631 bool GameConfigManager::LoadGameConfigFile(const char *file, IGameConfig **_pConfig, char *error, size_t maxlength)
   632 {
   633 	CGameConfig *pConfig;
   634 
   635 	if (sm_trie_retrieve(m_pLookup, file, (void **)&pConfig))
   636 	{
   637 		pConfig->IncRefCount();
   638 		*_pConfig = pConfig;
   639 		return true;
   640 	}
   641 
   642 	pConfig = new CGameConfig(file);
   643 
   644 	/* :HACKHACK: Don't parse the main config file */
   645 	bool retval = true;
   646 	if (_pConfig != &g_pGameConf)
   647 	{
   648 		retval = pConfig->Reparse(error, maxlength);
   649 	}
   650 
   651 	m_cfgs.push_back(pConfig);
   652 	sm_trie_insert(m_pLookup, file, pConfig);
   653 
   654 	pConfig->IncRefCount();
   655 
   656 	*_pConfig = pConfig;
   657 
   658 	return retval;
   659 }
   660 
   661 void GameConfigManager::CloseGameConfigFile(IGameConfig *cfg)
   662 {
   663 	CGameConfig *pConfig = (CGameConfig *)cfg;
   664 
   665 	if (pConfig->DecRefCount() == 0)
   666 	{
   667 		sm_trie_delete(m_pLookup, pConfig->m_pFile);
   668 		delete pConfig;
   669 	}
   670 }
   671 
   672 extern HandleType_t g_GameConfigsType;
   673 
   674 IGameConfig *GameConfigManager::ReadHandle(Handle_t hndl, IdentityToken_t *ident, HandleError *err)
   675 {
   676 	HandleSecurity sec(ident, g_pCoreIdent);
   677 	IGameConfig *conf = NULL;
   678 	HandleError _err = g_HandleSys.ReadHandle(hndl, g_GameConfigsType, &sec, (void **)&conf);
   679 
   680 	if (err)
   681 	{
   682 		*err = _err;
   683 	}
   684 
   685 	return conf;
   686 }