core/GameConfigs.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1307 4f646bb1f89f
child 1406 f5c07ec3c052
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

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