diff -r 688718339deb -r 50b5b98b3400 tools/gdc-psyfork/GameConfigs.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tools/gdc-psyfork/GameConfigs.cpp Sun May 27 11:36:49 2012 -0400
@@ -0,0 +1,562 @@
+/**
+ * vim: set ts=4 :
+ * =============================================================================
+ * SourceMod
+ * Copyright (C) 2004-2008 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"
+
+#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
+#define PSTATE_GAMEDEFS_CUSTOM 11
+
+#define WIN 0
+#define LIN 1
+
+#define PLATFORM_NAME "linux"
+#define PLATFORM_SERVER_BINARY "server_i486.so"
+
+Offset *tempOffset;
+Sig *tempSig;
+
+unsigned int s_ServerBinCRC;
+bool s_ServerBinCRC_Ok = false;
+
+bool DoesGameMatch(const char *value)
+{
+ if (strcmp(value, game) == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+bool DoesEngineMatch(const char *value)
+{
+ if (strcmp(value, engine) == 0)
+ {
+ return true;
+ }
+ return false;
+}
+
+CGameConfig::CGameConfig()
+{
+ m_pStrings = new BaseStringTable(512);
+ m_RefCount = 0;
+
+ m_CustomLevel = 0;
+ m_CustomHandler = NULL;
+}
+
+CGameConfig::~CGameConfig()
+{
+ 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 ||
+ DoesGameMatch(name))
+ {
+ 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;
+ had_game = false;
+ matched_game = false;
+ had_engine = false;
+ matched_engine = false;
+ }
+ else if (strcmp(name, "Signatures") == 0)
+ {
+ m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
+ }
+
+ break;
+ }
+ case PSTATE_GAMEDEFS_OFFSETS:
+ {
+ m_Prop[0] = '\0';
+ m_Class[0] = '\0';
+ tempOffset = new Offset();
+ tempOffset->setName(name);
+ m_ParseState = PSTATE_GAMEDEFS_OFFSETS_OFFSET;
+ break;
+ }
+ case PSTATE_GAMEDEFS_SIGNATURES:
+ {
+ tempSig = new Sig();
+ tempSig->setName(name);
+ m_ParseState = PSTATE_GAMEDEFS_SIGNATURES_SIG;
+ 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 {
+ int val = atoi(value);
+ if (strcmp(key, "windows") == 0) tempOffset->setWin(val);
+ else if (strcmp(key, "linux") == 0) tempOffset->setLin(val);
+ }
+ } else if (m_ParseState == PSTATE_GAMEDEFS_KEYS) {
+ m_Keys.replace(key, m_pStrings->AddString(value));
+ } else if (m_ParseState == PSTATE_GAMEDEFS_SUPPORTED) {
+ if (strcmp(key, "game") == 0)
+ {
+ had_game = true;
+ if (DoesGameMatch(value))
+ {
+ matched_game = true;
+ }
+ if ((!had_engine && matched_game) || (matched_engine && matched_game))
+ {
+ bShouldBeReadingDefault = true;
+ }
+ }
+ else if (strcmp(key, "engine") == 0)
+ {
+ had_engine = true;
+ if (DoesEngineMatch(value))
+ {
+ matched_engine = true;
+ }
+ if ((!had_game && matched_engine) || (matched_game && matched_engine))
+ {
+ bShouldBeReadingDefault = true;
+ }
+ }
+ } else if (m_ParseState == PSTATE_GAMEDEFS_SIGNATURES_SIG) {
+ if (strcmp(key, "windows") == 0) tempSig->setWin(value);
+ else if (strcmp(key, "linux") == 0) tempSig->setLin(value);
+ else if (strcmp(key, "library") == 0) tempSig->setLib(value);
+ } 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;
+ }
+ }
+ } else if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM) {
+ return m_CustomHandler->ReadSMC_KeyValue(states, key, value);
+ }
+
+ return SMCResult_Continue;
+}
+
+SMCResult CGameConfig::ReadSMC_LeavingSection(const SMCStates *states)
+{
+ if (m_IgnoreLevel)
+ {
+ m_IgnoreLevel--;
+ return SMCResult_Continue;
+ }
+
+ if (m_CustomLevel)
+ {
+ m_CustomLevel--;
+ m_CustomHandler->ReadSMC_LeavingSection(states);
+ 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_CUSTOM:
+ {
+ m_ParseState = PSTATE_GAMEDEFS;
+ m_CustomHandler->ReadSMC_ParseEnd(false, false);
+ break;
+ }
+ case PSTATE_GAMEDEFS_KEYS:
+ case PSTATE_GAMEDEFS_OFFSETS:
+ {
+ m_ParseState = PSTATE_GAMEDEFS;
+ break;
+ }
+ case PSTATE_GAMEDEFS_OFFSETS_OFFSET:
+ {
+ for (list::iterator it = m_Offsets.begin(); it != m_Offsets.end(); it++)
+ {
+ if (strcmp(it->name, tempOffset->name) == 0)
+ {
+ m_Offsets.erase(it);
+ break;
+ }
+ }
+ m_Offsets.push_back(*tempOffset);
+ 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:
+ {
+ m_Sigs.push_back(*tempSig);
+ m_ParseState = PSTATE_GAMEDEFS_SIGNATURES;
+
+ break;
+ }
+ }
+
+ return SMCResult_Continue;
+}
+
+#define MSTATE_NONE 0
+#define MSTATE_MAIN 1
+#define MSTATE_FILE 2
+
+class MasterReader : public ITextListener_SMC
+{
+public:
+ virtual void ReadSMC_ParseStart()
+ {
+ state = MSTATE_NONE;
+ ignoreLevel = 0;
+ }
+
+ virtual SMCResult ReadSMC_NewSection(const SMCStates *states, const char *name)
+ {
+ if (ignoreLevel)
+ {
+ return SMCResult_Continue;
+ }
+
+ if (state == MSTATE_NONE)
+ {
+ if (strcmp(name, "Game Master") == 0)
+ {
+ state = MSTATE_MAIN;
+ }
+ else
+ {
+ ignoreLevel++;
+ }
+ }
+ else if (state == MSTATE_MAIN)
+ {
+ strncopy(cur_file, name, sizeof(cur_file));
+ had_engine = false;
+ matched_engine = false;
+ had_game = false;
+ matched_game = false;
+ state = MSTATE_FILE;
+ }
+ else if (state == MSTATE_FILE)
+ {
+ ignoreLevel++;
+ }
+
+ return SMCResult_Continue;
+ }
+
+ virtual SMCResult ReadSMC_KeyValue(const SMCStates *states, const char *key, const char *value)
+ {
+ if (ignoreLevel || state != MSTATE_FILE)
+ {
+ return SMCResult_Continue;
+ }
+
+ if (strcmp(key, "engine") == 0)
+ {
+ had_engine = true;
+ if (DoesEngineMatch(value))
+ {
+ matched_engine = true;
+ }
+ }
+ else if (strcmp(key, "game") == 0)
+ {
+ had_game = true;
+ if (DoesGameMatch(value))
+ {
+ matched_game = true;
+ }
+ }
+
+ return SMCResult_Continue;
+ }
+
+ virtual SMCResult ReadSMC_LeavingSection(const SMCStates *states)
+ {
+ if (ignoreLevel)
+ {
+ ignoreLevel--;
+ return SMCResult_Continue;
+ }
+
+ if (state == MSTATE_FILE)
+ {
+ /* The four success conditions:
+ * 1. Needed nothing.
+ * 2. Needed game only.
+ * 3. Needed engine only.
+ * 4. Needed both engine and game.
+ * Final result is minimized via k-map.
+ */
+
+ if ((!had_engine && !had_game) ||
+ (!had_engine && matched_game) ||
+ (!had_game && matched_engine) ||
+ (matched_engine && matched_game))
+ {
+ fileList->push_back(cur_file);
+ }
+ state = MSTATE_MAIN;
+ }
+ else if (state == MSTATE_MAIN)
+ {
+ state = MSTATE_NONE;
+ }
+
+ return SMCResult_Continue;
+ }
+public:
+ list *fileList;
+ unsigned int state;
+ unsigned int ignoreLevel;
+ char cur_file[PLATFORM_MAX_PATH];
+ bool had_engine;
+ bool matched_engine;
+ bool had_game;
+ bool matched_game;
+};
+
+static MasterReader master_reader;
+
+bool CGameConfig::Reparse(char *error, size_t maxlength)
+{
+ /* Reset cached data */
+ m_pStrings->Reset();
+ m_Offsets.clear();
+ m_Sigs.clear();
+ m_Keys.clear();
+
+ char path[PLATFORM_MAX_PATH];
+
+ /* See if we can use the extended gamedata format. */
+ //TODO pass in path to gamedata somehow
+
+ /* Otherwise, it's time to parse the master. */
+ SMCError err;
+ SMCStates state = {0, 0};
+ list fileList;
+ master_reader.fileList = &fileList;
+
+ err = textparsers->ParseSMCFile(path, &master_reader, &state, error, maxlength);
+ if (err != SMCError_Okay)
+ {
+ const char *msg = textparsers->GetSMCErrorString(err);
+
+ printf("[SM] Error parsing master gameconf file \"%s\":", path);
+ printf("[SM] Error %d on line %d, col %d: %s",
+ err,
+ state.line,
+ state.col,
+ msg ? msg : "Unknown error");
+ exit(PARSE_ERROR);
+ }
+
+ /* Go through each file we found and parse it. */
+ list::iterator iter;
+ for (iter = fileList.begin(); iter != fileList.end(); iter++)
+ {
+ UTIL_Format(path, sizeof(path), "%s/%s", m_File, *iter);
+ if (!EnterFile(path, error, maxlength))
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool CGameConfig::EnterFile(const char *file, char *error, size_t maxlength)
+{
+ SMCError err;
+ SMCStates state = {0, 0};
+
+ /* Initialize parse states */
+ m_IgnoreLevel = 0;
+ bShouldBeReadingDefault = true;
+ m_ParseState = PSTATE_NONE;
+
+ if ((err=textparsers->ParseSMCFile(file, this, &state, error, maxlength))
+ != SMCError_Okay)
+ {
+ const char *msg;
+
+ msg = textparsers->GetSMCErrorString(err);
+
+ printf("[SM] Error parsing gameconfig file \"%s\":\n", file);
+ printf("[SM] Error %d on line %d, col %d: %s\n",
+ err,
+ state.line,
+ state.col,
+ msg ? msg : "Unknown error");
+
+ if (m_ParseState == PSTATE_GAMEDEFS_CUSTOM)
+ {
+ //error occurred while parsing a custom section
+ m_CustomHandler->ReadSMC_ParseEnd(true, true);
+ m_CustomHandler = NULL;
+ m_CustomLevel = 0;
+ }
+
+ exit(PARSE_ERROR);
+ }
+
+ return true;
+}
+
+const char *CGameConfig::GetKeyValue(const char *key)
+{
+ int *pkey;
+ if ((pkey = m_Keys.retrieve(key)) == NULL)
+ return NULL;
+ return m_pStrings->GetString(*pkey);
+}
+
+list CGameConfig::GetOffsets() { return m_Offsets; }
+list CGameConfig::GetSigs() { return m_Sigs; }
+