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