Files
funnygame/tier2/fileformats/json.cpp
2026-01-14 20:15:49 +02:00

528 lines
11 KiB
C++

#include "tier2/fileformats/json.h"
#include "tier2/tokenizer.h"
abstract_class CJSONArray: public IJSONArray
{
public:
virtual uint32_t GetCount() override;
virtual IJSONValue *GetParameter( uint32_t i ) override;
virtual void SetArray( uint32_t uCount, IJSONValue **ppValues ) override;
virtual void CopyTo( IJSONArray *pObject ) override;
virtual void Free() override;
CUtlVector<IJSONValue*> m_values;
};
uint32_t CJSONArray::GetCount()
{
return m_values.GetSize();
}
IJSONValue *CJSONArray::GetParameter( uint32_t i )
{
return m_values[i];
}
void CJSONArray::SetArray( uint32_t uCount, IJSONValue **ppValues )
{
m_values.Resize(uCount);
for ( uint32_t u = 0; u < uCount; u++)
m_values[u] = ppValues[u];
}
void CJSONArray::CopyTo( IJSONArray *pObject )
{
}
void CJSONArray::Free()
{
for ( auto &value: m_values)
JSONManager()->FreeValue(value);
m_values = {};
}
abstract_class CJSONValue: public IJSONValue
{
public:
virtual EJSONParameterType GetType( void ) override;
virtual const char *GetStringValue() override;
virtual float GetNumberValue() override;
virtual bool GetBooleanValue() override;
virtual IJSONArray *GetArray() override;
virtual IJSONObject *GetObject() override;
virtual void MakeNULL() override;
virtual void SetStringValue( const char *szString ) override;
virtual void SetNumberValue( float fValue ) override;
virtual void SetBooleanValue( bool bValue ) override;
virtual void SetArrayValue( IJSONArray *pValue ) override;
virtual void SetObjectValue( IJSONObject *pValue ) override;
virtual void CopyTo( IJSONValue *pObject ) override;
virtual void Free() override;
EJSONParameterType m_eType;
CUtlString m_szString;
float m_fValue;
bool m_bValue;
IJSONArray *m_pArray;
IJSONObject *m_pObject;
};
EJSONParameterType CJSONValue::GetType( void )
{
return m_eType;
}
const char * CJSONValue::GetStringValue()
{
return m_szString;
}
float CJSONValue::GetNumberValue()
{
return m_fValue;
}
bool CJSONValue::GetBooleanValue()
{
return m_fValue;
}
IJSONArray *CJSONValue::GetArray()
{
return m_pArray;
}
IJSONObject *CJSONValue::GetObject()
{
return m_pObject;
}
void CJSONValue::MakeNULL()
{
if ( GetType() == JSON_PARAMETER_OBJECT )
{
JSONManager()->FreeObject(m_pObject);
m_pObject = NULL;
}
if ( GetType() == JSON_PARAMETER_ARRAY )
{
JSONManager()->FreeArray(m_pArray);
m_pArray = NULL;
}
if ( GetType() == JSON_PARAMETER_STRING )
m_szString = NULL;
}
void CJSONValue::SetStringValue( const char *szString )
{
MakeNULL();
m_eType = JSON_PARAMETER_STRING;
m_szString = szString;
}
void CJSONValue::SetNumberValue( float fValue )
{
MakeNULL();
m_eType = JSON_PARAMETER_NUMBER;
m_fValue = fValue;
}
void CJSONValue::SetBooleanValue( bool bValue )
{
MakeNULL();
m_eType = JSON_PARAMETER_BOOLEAN;
}
void CJSONValue::SetArrayValue( IJSONArray *pValue )
{
MakeNULL();
m_eType = JSON_PARAMETER_ARRAY;
m_pArray = pValue;
}
void CJSONValue::SetObjectValue( IJSONObject *pValue )
{
MakeNULL();
m_eType = JSON_PARAMETER_OBJECT;
m_pObject = pValue;
}
void CJSONValue::CopyTo( IJSONValue *pObject )
{
MakeNULL();
}
void CJSONValue::Free()
{
MakeNULL();
}
abstract_class CJSONObject: public IJSONObject
{
public:
virtual IJSONValue *GetValue( const char *szName ) override;
virtual void SetValue( const char *szName, IJSONValue *pValue ) override;
virtual void CopyTo( IJSONObject *pObject ) override;
virtual void Free() override;
struct JSONObjectParam_t
{
CUtlString m_szName;
IJSONValue *m_pValue;
};
CUtlVector<JSONObjectParam_t> m_params;
};
IJSONValue *CJSONObject::GetValue( const char *szName )
{
int i;
JSONObjectParam_t *pParam;
for ( i = 0; i < m_params.GetSize(); i++ )
{
if ( m_params[i].m_szName != szName )
continue;
return m_params[i].m_pValue;
}
return NULL;
}
void CJSONObject::SetValue( const char *szName, IJSONValue *pValue )
{
int i;
JSONObjectParam_t *pParam;
for ( i = 0; i < m_params.GetSize(); i++ )
{
if ( m_params[i].m_szName != szName )
continue;
// Scary
if ( pValue == NULL )
m_params.RemoveAt(i);
else
m_params[i].m_pValue = pValue;
return;
}
if ( pValue == NULL )
return;
m_params.AppendTail({szName, pValue});
}
void CJSONObject::CopyTo( IJSONObject *pObject )
{
}
void CJSONObject::Free()
{
for ( auto &param: m_params )
{
JSONManager()->FreeValue(param.m_pValue);
}
}
abstract_class CJSONManager: public IJSONManager
{
public:
virtual IJSONObject *CreateObject( ) override;
virtual void FreeObject( IJSONObject *pObject ) override;
virtual IJSONArray *CreateArray( ) override;
virtual void FreeArray( IJSONArray *pArray ) override;
virtual IJSONValue *CreateValue( ) override;
virtual void FreeValue( IJSONValue *pValue ) override;
virtual IJSONValue *ReadString( const char *szString ) override;
virtual CUtlString WriteString( IJSONValue *pValue ) override;
private:
CUtlString RealWriteString( IJSONValue *pValue, uint32_t uOffest );
static bool ExpectedToken( Token_t &token, const char *szValue );
static CUtlString GetQuotedToken( Token_t &token );
IJSONObject *ParseObject( Token_t *&pToken, const Token_t *pEnding );
IJSONArray *ParseArray( Token_t *&pToken, const Token_t *pEnding );
IJSONValue *ParseValue( Token_t *&pToken, const Token_t *pEnding );
};
IJSONObject *CJSONManager::CreateObject( )
{
return new CJSONObject;
}
void CJSONManager::FreeObject( IJSONObject *pObject )
{
pObject->Free();
delete (CJSONObject*)pObject;
}
IJSONArray *CJSONManager::CreateArray( )
{
return new CJSONArray;
}
void CJSONManager::FreeArray( IJSONArray *pArray )
{
pArray->Free();
delete (CJSONObject*)pArray;
}
IJSONValue *CJSONManager::CreateValue( )
{
return new CJSONValue;
}
void CJSONManager::FreeValue( IJSONValue *pValue )
{
pValue->Free();
delete (CJSONValue*)pValue;
}
#define NEXT_TOKEN() \
pToken++; \
if (pToken == pEnding) \
goto eof \
bool CJSONManager::ExpectedToken( Token_t &token, const char *szValue )
{
if ( token.m_szValue == szValue && !token.m_bIsQuoted )
return true;
return false;
}
CUtlString CJSONManager::GetQuotedToken( Token_t &token )
{
if ( token.m_bIsQuoted )
return token.m_szValue;
return NULL;
}
IJSONObject *CJSONManager::ParseObject( Token_t *&pToken, const Token_t *pEnding )
{
IJSONObject *pObject;
CUtlString szParamName;
IJSONValue *pValue;
if ( !ExpectedToken(*(pToken), "{") )
return NULL;
NEXT_TOKEN();
pObject = CreateObject();
// object might be empty
if ( ExpectedToken(*pToken, "}") )
{
NEXT_TOKEN();
return pObject;
}
while(true)
{
szParamName = NULL;
pValue = NULL;
if ( GetQuotedToken(*pToken) == NULL )
goto not_quoted;
szParamName = pToken->m_szValue;
NEXT_TOKEN();
if ( !ExpectedToken(*pToken, ":") )
goto not_colon;
NEXT_TOKEN();
pValue = ParseValue(pToken, pEnding);
pObject->SetValue(szParamName, pValue);
if ( !ExpectedToken(*pToken, ",") )
{
if ( !ExpectedToken(*pToken, "}") )
{
goto not_comma;
}
return pObject;
}
NEXT_TOKEN();
}
return pObject;
not_comma:
V_printf("%i: comma (,) or } was expected but got %s\n", pToken->m_iLine, pToken->m_szValue.GetString());
return NULL;
not_colon:
V_printf("%i: colon (:) was expected but got %s\n", pToken->m_iLine, pToken->m_szValue.GetString());
return NULL;
not_quoted:
V_printf("%s was not quoted\n", szParamName.GetString());
return NULL;
eof:
V_printf("EOF\n");
return NULL;
}
IJSONArray *CJSONManager::ParseArray( Token_t *&pToken, const Token_t *pEnding )
{
IJSONArray *pObject;
CUtlString szParamName;
IJSONValue *pValue;
CUtlVector<IJSONValue*> values;
if ( !ExpectedToken(*(pToken), "[") )
return NULL;
NEXT_TOKEN();
pObject = CreateArray();
// object might be empty
if ( ExpectedToken(*pToken, "]") )
{
NEXT_TOKEN();
return pObject;
}
while(true)
{
pValue = ParseValue(pToken, pEnding);
values.AppendTail(pValue);
if ( !ExpectedToken(*pToken, ",") )
{
if ( !ExpectedToken(*pToken, "]") )
{
goto not_comma;
}
pObject->SetArray(values.GetSize(), values.GetData());
return pObject;
}
NEXT_TOKEN();
}
return pObject;
not_comma:
V_printf("%i: comma (,) or } was expected but got %s\n", pToken->m_iLine, pToken->m_szValue.GetString());
return NULL;
eof:
V_printf("EOF\n");
pObject->SetArray(values.GetSize(), values.GetData());
return pObject;
}
IJSONValue *CJSONManager::ParseValue( Token_t *&pToken, const Token_t *pEnding )
{
IJSONObject *pObject = ParseObject(pToken, pEnding);
IJSONArray *pArray = ParseArray(pToken, pEnding);
IJSONValue *pValue = CreateValue();
if (pObject)
{
pValue->SetObjectValue(pObject);
return pValue;
}
if (pArray)
{
pValue->SetArrayValue(pArray);
return pValue;
}
if ( GetQuotedToken(*pToken) != NULL )
{
pValue->SetStringValue(pToken->m_szValue);
NEXT_TOKEN();
return pValue;
}
return NULL;
eof:
V_printf("EOF\n");
return NULL;
}
IJSONValue *CJSONManager::ReadString( const char *psz )
{
CUtlVector<Token_t> tokens;
CUtlVector<char> stack;
IJSONValue *pGlobalObject = NULL;
tokens = Tokenize(psz);
Token_t *pCurrentToken = tokens.GetData();
pGlobalObject = ParseValue(pCurrentToken, tokens.end().m_pCurrent);
return pGlobalObject;
};
CUtlString CJSONManager::WriteString( IJSONValue *pValue )
{
return RealWriteString(pValue, 0);
}
CUtlString CJSONManager::RealWriteString( IJSONValue *pValue, uint32_t uOffset )
{
IJSONArray *pArray;
CJSONObject *pObject;
CUtlString szString = "";
if (pValue)
switch (pValue->GetType())
{
case JSON_PARAMETER_NULL:
return CUtlString("null", pValue->GetNumberValue());
case JSON_PARAMETER_BOOLEAN:
if (pValue->GetBooleanValue())
return "true";
return "false";
case JSON_PARAMETER_NUMBER:
return CUtlString("\"%f\"", pValue->GetNumberValue());
case JSON_PARAMETER_STRING:
return CUtlString("\"%s\"", pValue->GetStringValue());
case JSON_PARAMETER_ARRAY:
pArray = pValue->GetArray();
szString.AppendTail("[\n");
for ( uint32_t i = 0; i < pArray->GetCount(); i++ )
{
for ( uint32_t j = 0; j <= uOffset; j++)
szString.AppendTail("\t");
szString.AppendTail(RealWriteString( pArray->GetParameter(i), uOffset+1 ));
if ( i != pArray->GetCount() - 1 )
szString.AppendTail(",");
szString.AppendTail("\n");
}
for ( uint32_t j = 0; j < uOffset; j++)
szString.AppendTail("\t");
szString.AppendTail("]");
return szString;
case JSON_PARAMETER_OBJECT:
pObject = (CJSONObject*)pValue->GetObject();
szString.AppendTail("{\n");
for ( uint32_t i = 0; i < pObject->m_params.GetSize(); i++ )
{
for ( uint32_t j = 0; j <= uOffset; j++)
szString.AppendTail("\t");
szString.AppendTail(pObject->m_params[i].m_szName);
szString.AppendTail(": ");
szString.AppendTail(RealWriteString( pObject->m_params[i].m_pValue, uOffset+1 ));
if ( i != pObject->m_params.GetSize() - 1 )
szString.AppendTail(",");
szString.AppendTail("\n");
}
for ( uint32_t j = 0; j < uOffset; j++)
szString.AppendTail("\t");
szString.AppendTail("}");
return szString;
}
}
IJSONManager *JSONManager()
{
static CJSONManager mgr;
return &mgr;
}