#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 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 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; 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 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 tokens; CUtlVector 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; }