r5sdk/r5dev/tier1/kvtokenreader.h
Kawe Mazidjatari ee82d5d8e0 Tier1: move KeyValues class to Tier1
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.
2024-04-05 17:42:05 +02:00

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