#include "tier2/fileformats/json.h" #include "tier2/tokenizer.h" abstract_class CJSONArray: public IJSONArray { public: virtual uint32_t GetCount() override; virtual IJSONObject *GetParameter( uint32_t i ) override; virtual void SetArray( uint32_t uCount, IJSONValue *pValue ) override; virtual void CopyTo( IJSONArray *pObject ) override; virtual void Free() override; }; uint32_t CJSONArray::GetCount() { } IJSONObject *CJSONArray::GetParameter( uint32_t i ) { } void CJSONArray::SetArray( uint32_t uCount, IJSONValue *pValue ) { } void CJSONArray::CopyTo( IJSONArray *pObject ) { } void CJSONArray::Free() { } 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_szString = szString; } void CJSONValue::SetNumberValue( float fValue ) { MakeNULL(); m_fValue = fValue; } void CJSONValue::SetBooleanValue( bool bValue ) { MakeNULL(); } void CJSONValue::SetArrayValue( IJSONArray *pValue ) { MakeNULL(); } void CJSONValue::SetObjectValue( IJSONObject *pValue ) { MakeNULL(); 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 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 ¶m: 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; private: 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 ); virtual IJSONObject *ReadString( const char *szString ) override; }; IJSONObject *CJSONManager::CreateObject( ) { return new CJSONObject; } void CJSONManager::FreeObject( IJSONObject *pObject ) { pObject->Free(); delete (CJSONObject*)pObject; } IJSONArray *CJSONManager::CreateArray( ) { } void CJSONManager::FreeArray( IJSONArray *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 ) { return NULL; eof: V_printf("EOF\n"); return NULL; } IJSONValue *CJSONManager::ParseValue( Token_t *&pToken, const Token_t *pEnding ) { IJSONObject *pObject = ParseObject(pToken, pEnding); IJSONArray *pArray = NULL; IJSONValue *pValue = CreateValue(); if (pObject) { pValue->SetObjectValue(pObject); return pValue; } if ( GetQuotedToken(*pToken) != NULL ) { pValue->SetStringValue(pToken->m_szValue); NEXT_TOKEN(); return pValue; } return NULL; eof: V_printf("EOF\n"); return NULL; } IJSONObject *CJSONManager::ReadString( const char *psz ) { CUtlVector tokens; CUtlVector stack; IJSONObject *pGlobalObject = NULL; tokens = Tokenize(psz); Token_t *pCurrentToken = tokens.GetData(); pGlobalObject = ParseObject(pCurrentToken, tokens.end().m_pCurrent); return pGlobalObject; }; IJSONManager *JSONManager() { static CJSONManager mgr; return &mgr; }