mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
The KeyValues class belongs here. Also reimplemented most loading methods for KeyValues, and adjusted the VPK building code to account for it. Pointers to the engine's implementation of KeyValues have been moved to a separate header ('keyvalues_iface.h'), as this allows external tools code to utilize the standalone KeyValues class implementation. Playlist utilities are completely separated from the KeyValues header; these have nothing to do with KeyValues other than manipulating a global KeyValues object for the playlists, and thus have been named as such and moved to rtech/playlists.
154 lines
3.6 KiB
C++
154 lines
3.6 KiB
C++
#ifndef KVTOKENREADER_H
|
|
#define KVTOKENREADER_H
|
|
#include "kverrorstack.h"
|
|
#include "tier1/keyvalues.h"
|
|
|
|
// This class gets the tokens out of a CUtlBuffer for KeyValues.
|
|
// Since KeyValues likes to seek backwards and seeking won't work with a text-mode CUtlStreamBuffer
|
|
// (which is what dmserializers uses), this class allows you to seek back one token.
|
|
class CKeyValuesTokenReader
|
|
{
|
|
public:
|
|
CKeyValuesTokenReader(KeyValues* pKeyValues, CUtlBuffer& buf);
|
|
|
|
const char* ReadToken(bool& wasQuoted, bool& wasConditional);
|
|
void SeekBackOneToken();
|
|
|
|
private:
|
|
KeyValues* m_pKeyValues;
|
|
CUtlBuffer& m_Buffer;
|
|
|
|
int m_nTokensRead;
|
|
bool m_bUsePriorToken;
|
|
bool m_bPriorTokenWasQuoted;
|
|
bool m_bPriorTokenWasConditional;
|
|
static char s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
|
|
};
|
|
|
|
char CKeyValuesTokenReader::s_pTokenBuf[KEYVALUES_TOKEN_SIZE];
|
|
|
|
CKeyValuesTokenReader::CKeyValuesTokenReader(KeyValues* pKeyValues, CUtlBuffer& buf) :
|
|
m_Buffer(buf)
|
|
{
|
|
m_pKeyValues = pKeyValues;
|
|
m_nTokensRead = 0;
|
|
m_bUsePriorToken = false;
|
|
}
|
|
|
|
const char* CKeyValuesTokenReader::ReadToken(bool& wasQuoted, bool& wasConditional)
|
|
{
|
|
if (m_bUsePriorToken)
|
|
{
|
|
m_bUsePriorToken = false;
|
|
wasQuoted = m_bPriorTokenWasQuoted;
|
|
wasConditional = m_bPriorTokenWasConditional;
|
|
return s_pTokenBuf;
|
|
}
|
|
|
|
m_bPriorTokenWasQuoted = wasQuoted = false;
|
|
m_bPriorTokenWasConditional = wasConditional = false;
|
|
|
|
if (!m_Buffer.IsValid())
|
|
return NULL;
|
|
|
|
// eating white spaces and remarks loop
|
|
while (true)
|
|
{
|
|
m_Buffer.EatWhiteSpace();
|
|
if (!m_Buffer.IsValid())
|
|
{
|
|
return NULL; // file ends after reading whitespaces
|
|
}
|
|
|
|
// stop if it's not a comment; a new token starts here
|
|
if (!m_Buffer.EatCPPComment())
|
|
break;
|
|
}
|
|
|
|
const char* c = (const char*)m_Buffer.PeekGet(sizeof(char), 0);
|
|
if (!c)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
// read quoted strings specially
|
|
if (*c == '\"')
|
|
{
|
|
m_bPriorTokenWasQuoted = wasQuoted = true;
|
|
m_Buffer.GetDelimitedString(m_pKeyValues->m_bHasEscapeSequences ? GetCStringCharConversion() : GetNoEscCharConversion(),
|
|
s_pTokenBuf, KEYVALUES_TOKEN_SIZE);
|
|
|
|
++m_nTokensRead;
|
|
return s_pTokenBuf;
|
|
}
|
|
|
|
if (*c == '{' || *c == '}' || *c == '=')
|
|
{
|
|
// it's a control char, just add this one char and stop reading
|
|
s_pTokenBuf[0] = *c;
|
|
s_pTokenBuf[1] = 0;
|
|
m_Buffer.GetChar();
|
|
++m_nTokensRead;
|
|
return s_pTokenBuf;
|
|
}
|
|
|
|
// read in the token until we hit a whitespace or a control character
|
|
bool bReportedError = false;
|
|
bool bConditionalStart = false;
|
|
int nCount = 0;
|
|
while (1)
|
|
{
|
|
c = (const char*)m_Buffer.PeekGet(sizeof(char), 0);
|
|
|
|
// end of file
|
|
if (!c || *c == 0)
|
|
break;
|
|
|
|
// break if any control character appears in non quoted tokens
|
|
if (*c == '"' || *c == '{' || *c == '}' || *c == '=')
|
|
break;
|
|
|
|
if (*c == '[')
|
|
bConditionalStart = true;
|
|
|
|
if (*c == ']' && bConditionalStart)
|
|
{
|
|
m_bPriorTokenWasConditional = wasConditional = true;
|
|
bConditionalStart = false;
|
|
}
|
|
|
|
// break on whitespace
|
|
if (V_isspace(*c) && !bConditionalStart)
|
|
break;
|
|
|
|
if (nCount < (KEYVALUES_TOKEN_SIZE - 1))
|
|
{
|
|
s_pTokenBuf[nCount++] = *c; // add char to buffer
|
|
}
|
|
else if (!bReportedError)
|
|
{
|
|
bReportedError = true;
|
|
g_KeyValuesErrorStack.ReportError(" ReadToken overflow");
|
|
}
|
|
|
|
m_Buffer.GetChar();
|
|
}
|
|
s_pTokenBuf[nCount] = 0;
|
|
++m_nTokensRead;
|
|
|
|
return s_pTokenBuf;
|
|
}
|
|
|
|
void CKeyValuesTokenReader::SeekBackOneToken()
|
|
{
|
|
if (m_bUsePriorToken)
|
|
Plat_FatalError(eDLL_T::COMMON, "CKeyValuesTokenReader::SeekBackOneToken: It is only possible to seek back one token at a time");
|
|
|
|
if (m_nTokensRead == 0)
|
|
Plat_FatalError(eDLL_T::COMMON, "CkeyValuesTokenReader::SeekBackOneToken: No tokens read yet");
|
|
|
|
m_bUsePriorToken = true;
|
|
}
|
|
|
|
#endif // KVTOKENREADER_H
|